It has become some sort of a trend to bash monolithic systems without understanding what they truly are. Also, it has become common for organizations and teams to jump on the microservices bandwagon without fully embracing the idea.
The idea that monoliths are like big balls of mud and microservices are always good has taken hold within the industry.
In my view, this thought process is flawed. And the main reason is that we don’t bother to understand the strengths or weaknesses of our existing monolithic systems.
In today’s post, we will look at different types of monolithic systems along with ideas on how to deal with them.
1 - What is a Monolithic System?
Though this is a pretty basic question, I have seen many developers tend to struggle while answering this question.
Some developers might answer this in terms of the number of modules within the system. If the system has more than X number of modules, it is a monolithic system. Some determine whether a system is monolithic depending on the size of the development team maintaining that particular system.
The above factors may help determine the type of the system. But they are more like the result of a monolithic system rather than the reason.
The best barometer for classifying a system as monolithic is to determine if the system is a single unit of deployment. When all the functionality of the system has to be deployed together, it is essentially a monolithic system.
In a monolithic architecture, the entire application is bundled into a single package that includes the source code, libraries, configurations, and all other dependencies required for the application to run.
Typically, monoliths are known to have some limitations:
Large deployment artifacts that are often slow to start.
Change to some part of the application (even minor in nature) requires re-building and re-deploying the entire system.
No efficient way of scaling the system horizontally.
Subscribe to the Publication
2 - Types of Monolithic Systems
Despite the common limitations of monolithic systems, not all such systems are equal from the perspective of a developer.
There are various types of monolithic systems. It is important to know what type of monolithic system we are dealing with before thinking of any improvements.
2.1 - The Single Process Monolith
The Single Process Monolith is probably the most commonly occurring monolithic system out there.
In this type of monolithic system, the entire code is deployed as a single process. Though there might be multiple instances for backup or scalability purposes, the entire code is still part of a single process.
Such systems can also be modular in nature. In other words, the system might comprise of multiple modules. Such a system is also known as Modular Monolith.
Though developers can work on these modules separately, but they still need to be combined for deployment purpose. This allows parallel development of the system while avoiding the complexity of a totally distributed system.
One of the companies that uses the Modular Monolith approach is Shopify. When the time came to redesign their architecture, Shopify chose a Modular Monolith approach over a full-blown microservices architecture. Their goal was to increase the modularity of the system while keeping a single deployment unit. More on this approach in a later post.
The main challenge that might arise from the Single Process Monolith approach is that the database often lacks the modular de-composition of the code base. This can cause significant maintenance challenges.
Needless to say, if we have to build a monolithic system for whatever reason, it is better to go with a Modular Monolith approach.
2.2 - The Distributed Monolith
Distributed Monolith sounds like the best of both worlds but it actually ends up being the worst of both worlds.
A Distributed Monolith application is an application that’s deployed like a microservice but is built like a monolith. In this approach, changes tend to create rippling effects across service boundaries. Seemingly innocent changes tend to break other parts of the system.
With a Distributed Monolith, we have the heaviness and inflexibility of monoliths, the complexity of microservices, and few of the benefits of either architecture. We still have slow deployments and poor scalability, but now we’ve added operational complexity and removed the isolation between services.
The developers working on a distributed monolith need to learn the new architecture, adopt new tooling, and rebuild their applications to adapt to the dynamic and transient world of containers. This adds significant overhead in time and labor.
But why do Distributed Monoliths come into existence?
Usually, such monoliths arise due to un-needed push towards microservices or distributed architecture. While making the transition, not enough focus is placed on concepts like information hiding and cohesion of business functionality.
In essence, the developers don’t really want to fully embrace microservices but have to do it for whatever reason. This leads to a highly coupled architecture without the benefits of a truly distributed system. It goes without saying that Distributed Monoliths should be avoided as much as possible.
2.3 - Third-party Black Box Monoliths
As the name suggests, this is usually software developed by other people and we may not have the ability to change the code.
Typically, these are off-the-shelf products or other SaaS applications used in our system for some business purpose.
While such applications may be pretty well designed, but for the team adopting them, they are simply black boxes or monoliths.
3 - How to handle a Monolithic System?
If you start off with a monolith, your goal should be to keep it from growing into a monstrosity.
The key to doing this is to simply listen to your application!
Of course, it sounds easier, but as a monolithic application grows, we need to keep asking some questions about the system.
Is there anything within the system that is scaling at a different rate than the rest of the system?
Is there anything that feels forced into the system while looking from outside of the system?
Is there a part of the system that requires more frequent deployments than the rest of the system?
Is there a part of the system that a single person, or a small team, operates independently from the rest of the group?
Is there a subset of tables in your database that isn’t connected to the rest of the system?
If the answer to more questions is close to Yes, then it might be time to look at some sort of refactoring. Of course, it does not mean that you should straight away jump towards a microservices architecture. But it is certainly time to make your system more modular.
What kind of system are you currently working on?
If it is a monolith, does it fall within the types mentioned in the post or is it something totally different?
What are the challenges you face on a day-to-day basis in running or changing the system?
I would love to hear your thoughts on the topic covered in this post.
Do share your views in the comments section below as it might help build further understanding for everyone who might be grappling with similar challenges.