Make Sushi, Not Spaghetti
Have you heard the term "spaghetti code" in reference to a software system? It's a pejorative term that developers use, mostly to describe other people's work. It means that the design of an application is complex, hard to understand, and linked together in ways that make it difficult to troubleshoot, maintain, or enhance.
Spaghetti code is the enemy of rapid innovation. It increases the time and money required to implement new business ideas. It also increases the cost of running existing systems, which saps money away from more valuable projects. Why? Because every extra hour it takes for a developer to dig through spaghetti code, trying to figure out how to change it without breaking the system, is an hour that they could have spent developing that cool new business function that you've been waiting for.
The thing about spaghetti code is that it's nobody's fault. Every developer who touches a system over time is trying to do their best. They are often working with minimal documentation, limited understanding of the history of a system, and knowing that their manager really only cares that they deliver new functionality on time. It is no wonder that most developers end up increasing the amount of spaghetti in the code that they touch, rather than reducing it.
When software architects talk about the challenges of agile development for large systems, they often reflect on what could be done differently to prevent the spread of spaghetti code. Sometimes it is suggested that tighter control of development standards might help. Other times there is a movement to implement architecture review boards, or peer code reviews, or some other type of project oversight. But in truth, none of these approaches really works for very long. Not because people aren't trying, but simply because the architecture of most existing systems offers no alternative to spaghetti coding.
So what can be done to improve the longevity, and lower the maintenance costs of enterprise software systems? One idea that has come to the forefront in recent years is the notion of designing systems that are composed of small, self-contained modules. Each module performs one discreet business function, such as "Manage Purchase Orders". It is accessible by the other modules in the system and ultimately by the user only via a clearly defined contract, or Application Programming Interface (API). The current catch phrase for this type of design is "Micro-services". I personally like to think of it as software sushi; lots of small rolls of yumminess, each contained in a tight little wrapper.
In the micro-services model, if a new business function is desired and it does not fit cleanly into the definition of a current business process, then a whole new micro-services module is created, and wired to the other modules via its API. In this way, the complexity of a system grows more often by adding new modules, rather than adding new code to existing modules. So metaphorically speaking, a complex application that uses micro-services ends up looking a lot more like a plate of sushi than a plate of spaghetti, with each little sushi roll representing a discreet business function. For the developer, that means that understanding how to solve a problem means only understanding the micro-services that impact the problem at hand, rather than every line of code in the system.
There are a couple of advantages to micro-services based systems design. For one thing, it is much easier to keep smaller modules of software code "clean" over time. So following the simple practice of isolating business functions into micro-services helps to ensure that the business rules inside of any given service will remain intelligible through many enhancement cycles. Also, small software modules are easier to test. And because micro-services are isolated by API, the scope of testing a business change can be limited to the services that interact with a given API.
It goes without saying that micro-services are not a panacea. There are many design patterns and best practices that are needed to make a micro-service architecture efficient and scalable at the enterprise level. However, even if not implemented perfectly, micro-services architecture provide benefits in terms of maintainability, testability, and extensibility of large systems, and that alone that make this type of architecture worth looking at. So next time you are replacing a legacy system, think about micro-services architecture and make sushi, not spaghetti.
Code, in general, has become so complex that no single HUMAN BEING is able to completely understand the issues, let alone the repercussion's of their actions until another human being decides to mess with it. It is like artwork. Some like the piece, others don't, and other see a way to improve it, or mess with it; with so much nonsense all involved in general.
Really good post. I'm going to reuse your metaphor.
Love this :)!