Start with a well organised monolith. Microservices solve a team problem, too many teams stepping on the same code, long before they solve any problem of scale. With a team of five, distributed architecture will cost you more than it delivers.
The microservices conversation usually starts from the wrong end. Someone reads that Netflix runs hundreds of independent services and concludes that the company’s system should too. Except Netflix got there pushed by a problem most companies do not have: thousands of engineers who cannot wait on each other to ship a change.
The cost nobody puts on the diagram
On the slide, microservices are clean boxes joined by arrows. In production, every arrow is a network call that can fail, hang or come back half finished.
When you break a system into services you gain deployment independence and you pay with:
- Distributed transactions. What was a
BEGIN ... COMMITbecomes a choreography of compensations. Order created, payment failed, stock already reserved. Now what? - Debugging in several places at once. One slow request crosses four services. Without distributed tracing you are hunting in the dark.
- Local environments. The new developer needs seven services running to test one screen.
- Contract versioning. Changing a response field stops being a commit and becomes a negotiation between teams.
That cost pays off when you have enough teams that the real bottleneck is human coordination. Before that, it is pure tax.
The modular monolith almost nobody tries
There is a step between “everything tangled” and “everything separate”, and it is where most systems should live for a long time. One process, one database, but with internal boundaries taken seriously.
In practice that means three things. Each domain (billing, catalogue, users) lives in its own module with its own data access layer. Modules talk through explicit interfaces instead of rummaging through each other’s tables. And no JOIN across tables from different domains: if you needed one, the boundary is in the wrong place.
Built that way, the day a module needs to become its own service, it can. The dependencies are already mapped and the extraction is a few days of work rather than a quarter.
Concrete signs that the time has come
Not a feeling. Evidence:
- Deploys blocking each other. Two teams routinely waiting on the other’s release queue.
- Very different scaling profiles. The reporting module eats eight times the CPU of everything else, and you scale the whole application just to feed it.
- Different availability requirements. Checkout cannot go down. The internal admin panel can be offline for ten minutes with no drama at all.
- Incompatible technology. One part of the system needs heavy computation the main language does not do well.
One item on that list justifies extracting that specific piece. Zero items on the list does not justify rewriting everything.
Extract one, not thirty
When the time does come, the safe path is always the same. Pick the module with the cleanest boundary and the least coupling. Ship it as a service. Let the monolith call it. Then watch what breaks, because something will, and it is far better to find out with one service than with fifteen.
If the first extraction is smooth, the second will be too. If it is a nightmare, you just learned something valuable at the lowest possible price.
What usually delivers more first
Most systems that “need microservices” actually need far less glamorous things.
Database indexes, to begin with. I mean it: most bottlenecks that become architecture arguments are a query without an index. Then caching in the right place, with invalidation thought through. A queue for the heavy work, taking email sending, report generation and image processing off the user’s request path. And, as a last resort, a bigger server. Vertical scaling is unfashionable, it is bounded, and it solves far more cases than the literature admits.
Need this solved at your company?
A twenty minute call is usually enough to tell whether it makes sense, and you talk straight to the engineer who builds it.