A product team of fifteen engineers must choose between a modular monolith and services. What should decide it?
Show the full answer Hide the answer
What should decide it
Whether any component has a genuinely different operational requirement, not team size or domain complexity.
For a product with a video-processing pipeline the answer is usually yes — transcoding is CPU-intensive, bursty, long-running and failure-tolerant, which shares nothing with serving an API. That component is a legitimate service.
Everything else — the API, the workspace model, sharing, permissions, comments, search — likely has the same operational profile and belongs in one deployable with strong module boundaries.
What the modular monolith preserves
- The design discipline: enforced dependency rules between modules, checked in the pipeline, so boundaries are real rather than aspirational.
- The ability to test a module in isolation, which is most of the practical benefit of a service boundary.
- One transaction boundary, which removes an entire class of distributed-consistency problems from the parts of the domain that share invariants.
- One deployment, one debugging session, one on-call surface for a team of fifteen that cannot support many.
What it gives up
Independent deployability and independent scaling for the modules inside it. For a team of fifteen, those are usually not needed — fifteen engineers do not have enough independent workstreams to be blocked by a shared pipeline, and the components rarely have divergent scaling profiles.
The evolution property that makes it the better starting point
A well-bounded module is the cheapest possible thing to extract into a service later. The boundary already exists, the dependencies are already enforced, and the extraction is a deployment change rather than a design project.
The reverse is not true: a distributed system built before the boundaries were understood has boundaries in the wrong places, and moving a boundary across a network is far harder than moving one inside a process.
Start with the monolith and extract on evidence — a component with a genuinely different scaling need, a different failure domain, or a team that is genuinely blocked. Each extraction then has a reason that can be stated.