In 2019 we split our flagship platform into seventeen services because that was the consensus answer. We deployed independently, owned our own data, and wore the badge proudly. Three years later we were spending more engineering hours on cross-service plumbing than on customer features. The math was decisive.
What we got wrong wasn't the technology — service meshes work, eventual consistency is real, and async messaging is fine. What we got wrong was the cost of distributed reasoning. Every feature now needed a sequence diagram. Every incident needed three engineers in three repos. Every onboarding cost a week of context.
The modular monolith, ten years late
Today we default to a modular monolith. One repo, one deploy, strict internal module boundaries enforced at build time. We extract a service when a clear physical reason demands it — different scale, different language, different uptime profile — and not before.
The trade-off is that you have to be disciplined about modules. We use static analysis to prevent cross-module imports outside published APIs, treat database access the same way, and review architecture every quarter. Once that discipline is real, the productivity delta over micro-services is enormous.
What we'd tell our 2019 selves
If you're tempted to split, ask whether you're solving an organizational problem, a scaling problem, or a fashion problem. Only the first two justify the cost. For the third, fix your modules first — almost every team can buy two more years on a clean monolith if they take encapsulation seriously.
Want this kind of work on your project?
One conversation, honest pricing, recommended engagement model — within a business day.
Keep reading
All articlesHow we estimate software projects (and why most estimates are wrong)
Every estimate is wrong. The useful ones are wrong in known ways. A practical method we've refined across 50+ engagements — and the failure modes we learned to spot first.
The unreasonable effectiveness of plain SQL
ORMs are fine. Until they aren't. After a decade of building data layers on every framework we could find, we keep coming back to plain SQL — and the patterns that make it pleasant.
Why your first ML model should be embarrassingly simple
The first model in production teaches you more in a week than a perfect model in a notebook teaches you in a quarter. A practical case for shipping something terrible — on purpose — first.