The monolith you should keep
Architecture · Jun 2026 · 6 min read
Splitting a service is a bet on your ability to run more infrastructure. Often the right architecture decision is a well-bounded module and a boring deploy.
Almost every team that asks me for microservices wants two specific things: independent deploys and clear ownership. Both are organisational problems, and you can solve both inside one codebase without taking on a distributed system.
The three seams worth splitting on
I look for a genuine seam before agreeing to a split, and there are only three I trust: a different scaling curve, a different failure tolerance, or a different team with its own release cadence. Absent one of those, a split distributes your existing bugs across a network.
- Different scaling curve: video transcoding next to a CRUD admin panel.
- Different failure tolerance: payment capture that must not go down when search does.
- Different team: a genuinely separate group with its own on-call rotation.
A distributed transaction is a bug you chose to build. Make sure you chose it for a reason you can name.
Enforce the boundary before you enforce it with HTTP
The good news is you can get most of the discipline for free. Declare your modules, then fail the build when one reaches into another's internals. If a boundary survives six months of that pressure without anyone needing to cheat, it is real and you can extract it in an afternoon. If people cheat constantly, the boundary was wrong and you just saved yourself a rewrite.
modules:
billing: depends_on: [shared]
catalogue: depends_on: [shared]
# billing must never import catalogue internals
$ composer analyse:boundaries
FAIL Billing\Invoice imports Catalogue\Models\Product
Keeping the monolith buys you one migration story, real transactions, one trace per request, and a local environment that a new hire can run before lunch. Those are not consolation prizes. They are the things teams miss most about six months after the split.
Takeaways
- Split on scaling curves, failure tolerance, or team lines — not on architecture diagrams.
- Enforce module boundaries in CI first; extract to a service only once the boundary has held.
- One migration story and one trace per request are worth more than they look on a slide.
All notes · Shehzad Aslam