Somewhere in the last decade, "we should move to microservices" became a thing technology teams say to signal that they are serious. The word carries a whiff of modernity: it is what the big, admired engineering organisations do, so surely it is what a growing business should aspire to. This is one of the most expensive misunderstandings in modern software, and the people who popularised microservices are among the first to say so.
You don’t win by doing microservices.
What the words actually mean
Strip away the fashion and there are three options worth understanding, in plain terms.
- A monolith is one application, deployed as a single unit. Everything ships together. This is not an insult — it is simply how most software is, and should be, built.
- Microservices split that one application into many small, separately deployable services that talk to each other over a network. Each can be changed and released on its own.
- A modular monolith is the middle path: still one application deployed as a single unit, but cleanly divided inside into independent modules that separate teams can work on in parallel without tripping over each other.
The crucial thing the marketing skips is that microservices buy independent deployment by paying for it with distributed-systems complexity. The moment two services talk over a network, you inherit a long list of new problems: things fail halfway, calls time out, data gets temporarily out of step, and you now need real infrastructure to deploy, monitor and trace it all. That cost is real, it is permanent, and it shows up whether or not you needed the benefit.
You will not appreciate the true horror, pain and suffering of microservices until you’re running them in production.
Why "modular monolith" is usually the answer
Most growing businesses want the benefit people imagine microservices give — a tidy system where teams can work in parallel and one area can change without breaking another — without the operational tax. That benefit comes from good internal structure, not from splitting across a network. You can have clean, independent modules inside a single application. You get the separation; you skip the distributed-systems pain.
Many of the teams I work with would actually be better off with a modular monolith than a microservice architecture.
There is a worst-of-both-worlds outcome to avoid, too: the distributed monolith. This is what you get when you split a system into separate services but the pieces are still so entangled that a change in one forces changes and redeployments across all of them. You have paid the full operational cost of distribution and kept the coupling of a monolith. It is a surprisingly common destination for teams that adopt microservices for the badge rather than the constraint.
Architecture follows the constraint, not the trend
So when are microservices the right call? When you have a specific constraint that only separate deployment solves: one part of the system needs to scale very differently from the rest; several teams are genuinely blocked by having to release together; a critical area needs to keep running while everything around it is being changed. These are real, and when they apply, the operational cost is worth paying. The discipline is to make the change because of the constraint — and to change the architecture only as much as the constraint requires.
It is extremely rare that your goal is to kill the monolith… you change the architecture enough to do what you need.
For a smaller team the maths is starker still. The overhead of running many services — the deployment, the monitoring, the coordination — can dwarf the code that delivers value. A one- or two-person team almost always ships faster, and sleeps better, with a single well-structured application.
If you’re one or two people, write all the code in one repo and deploy it all as one thing… that effort is going to outweigh the actual code you write.
The practical advice, then, is unglamorous and correct: start with — or modernise toward — a well-structured modular application. Get the internal boundaries clean. Split a piece out into its own service only when a real, named business constraint forces you to, and then only that piece. Architecture is a series of trade-offs answering the question "what is actually holding this business back?" — not a ladder you climb because larger companies are further up it.
If you are not sure whether your current structure is holding you back — or whether a proposed re-architecture is solving a real constraint or a fashionable one — our free Software Health Check helps you name the actual constraint before you commit to a shape, at /application-modernisation/free-assessment.