step 14 / 32 · 6 min
Monolith, services, and the honest comparison
How a system is divided into deployable pieces is one of the harder decisions to reverse, and it is frequently made for the wrong reasons.
Monolith
One deployable unit. All the code, one process, usually one database.
[ web | orders | payments | inventory ] -> [ database ]What it gives: a function call instead of a network hop, one transaction across everything, one thing to deploy, one place to debug, and a stack trace that crosses the whole request.
What it costs: everything deploys together, so one team's change blocks another's. Scaling means running more copies of everything, even the parts that are idle. Over time the boundaries blur unless someone defends them.
Services
Separate deployables, each owning its data.
[ web ] -> [ orders ] -> [ orders db ]
-> [ payments ] -> [ payments db ]What it gives: independent deployment, independent scaling, a fault contained to one service, and teams that can move without coordinating.
What it costs, and this is usually underestimated:
- a function call becomes a network call that can fail, time out or arrive twice
- a transaction across two services does not exist; you need sagas and compensation
- a request spans several services, so debugging needs distributed tracing
- local development means running several things, or mocking them
- every service needs deployment, monitoring, alerting and on call
| Monolith | Services | |
|---|---|---|
| Deploy | all together | independently |
| Transactions | free | distributed, or given up |
| Debugging | one stack trace | tracing across services |
| Operational load | one system | one per service |
| Team independence | low | high |
The honest guidance
Start with a monolith, with clear internal boundaries.
The reason is not that services are bad. It is that at the start you do not yet know where the boundaries are, and a boundary drawn in the wrong place is far more expensive to move once it is a network interface. Inside one codebase it is a refactor.
The signal to split is organisational more often than technical: several teams blocking each other on one deployment pipeline. A single team running twelve services has taken on the costs and none of the benefit.
The middle ground
A modular monolith enforces boundaries inside one deployable: modules that communicate through defined interfaces and do not read each other's tables. It gets most of the design benefit with none of the distributed systems cost, and it makes extracting a service later mechanical rather than archaeological.