When you should not break up the monolith
Microservices sound modern, but decomposing a monolith without sufficient reasons creates more problems than it solves. How to think about this decision.
The word "monolith" in architecture discussions is increasingly said with an apologetic tone. As if it is a problem in itself that needs to be fixed. Yet none of the people who developed microservice architecture ever said a monolith is always bad. They said the opposite: microservices only make sense under specific conditions, and trying to apply them before those conditions are met is expensive.
I have been seeing several projects recently where teams have embarked on monolith decomposition for reasons that do not hold up under scrutiny. I want to describe how I think about this question.
What decomposition actually solves
Microservice architecture solves specific scaling problems: independent deployment of parts of the system, scaling only the loaded components, independent technology stacks for different teams.
All of this makes sense when there are multiple independent teams who are hindered by co-owning a single repository. Or when different parts of the system have fundamentally different load requirements. Or when the speed of independent deployment is critically important.
If none of these conditions apply, decomposition does not solve a problem - because there is no problem. It creates new ones: network calls instead of function calls, distributed transactions, debugging complexity, service orchestration. This is real operational overhead that is paid regardless of how "modern" the architecture sounds.
Signs that splitting is not needed
The first sign: the team is three to seven people working on one product. Microservices solve the coordination problem of large teams. With a small team this is a solution without a problem.
The second sign: the product is not yet settled. If requirements are changing every few weeks, hard boundaries between services will become an obstacle rather than a help. Refactoring interfaces between services is significantly more expensive than refactoring inside a monolith.
The third sign: load on the system is uniform and predictable. If no part of the system is loaded fundamentally differently from the rest, independent scaling is not needed.
The fourth sign: the problem is in the code, not the architecture. A poorly organised monolith can be made cleaner without splitting into services. Decomposing a chaotic monolith into services produces distributed chaos - each of the problems is now harder to find and fix.
What to do instead
If the complaint is that the monolith is "hard to maintain", it is worth understanding specifically what is difficult. The answer is often inside the monolith: no clear module boundaries, mixed-up logic, no tests, no documentation.
A modular monolith with clear internal boundaries between components solves most maintainability problems without the overhead of a distributed system. If a module needs to be extracted into a service later, that can be done. But doing it upfront, before a real need arises, means paying the cost now for a hypothetical future benefit.
Questions before the decision
If your team is discussing a move to microservices, a few questions worth asking before any work begins:
- What specific problem are we solving - and is there a simpler solution to it?
- How many independent teams will be deploying different parts of the system?
- Are there components with fundamentally different load requirements?
- Who will be responsible for orchestration, monitoring, and debugging of the distributed system?
- What happens if we discover we drew the service boundaries in the wrong place?
That last question is especially important. Wrong boundaries in a microservice architecture are one of the most expensive mistakes, and one that is hard to roll back.