advanced 3 min answer

A team is splitting a monolith into services. How do you decide where the boundaries go?

boundariescouplingcohesionconwayddd
Show the full answer Hide the answer

The criterion is what changes independently

Parnas's information hiding is the sharpest formulation: decompose around the decisions most likely to change, not around the steps of a process. Each volatile decision — the storage engine, the pricing rule, a partner's protocol — sits inside one module with a stable interface outside.

The failure mode this rules out is decomposition by technical layer — a data service, a validation service, an orchestration service — which spreads every business change across every service and produces maximum coupling with the appearance of modularity.

Use cohesion and coupling as the test

High cohesion inside: a service that changes for one reason. A service with low cohesion changes for many unrelated reasons, so every team touches it — which is how a distributed monolith forms.

Low coupling across, and specifically low temporal coupling. A synchronous call multiplies the callee's availability into the caller's: ten dependencies at 99.9% give 99.0%. If a proposed boundary introduces a synchronous call on every request, it is the wrong boundary or it needs to be asynchronous.

Check the numbers where you can: a component with high afferent and high efferent coupling — everything depends on it and it depends on everything — is the part nobody wants to touch, and splitting it is usually the first priority.

Use the domain, not the database

Bounded contexts from domain-driven design are the practical technique: find where the same word means different things. "Customer" in billing, in support and in marketing are different models, and that divergence is the boundary.

Business capabilities arrive at the same answer from the other direction — what the business does, independent of how it is organised — and they are stable for decades where org charts are not.

Respect Conway's Law rather than fighting it

Boundaries should follow team boundaries. A service split across two teams will develop a fluid, chatty interface; an interface between teams that rarely talk will become strict and stable.

The corollary is the important one: microservices with a functionally-siloed organisation produce a distributed monolith. The services exist, every change still crosses the same coordination boundaries, and distribution is added as pure cost. If the organisation cannot be aligned to the target architecture, the target architecture should change.

Sequence the work to be reversible

Modular monolith first. Establish boundaries as modules with enforced dependency rules — checked in CI, so a violation fails a build. Boundaries are cheap to move inside one deployable and expensive to move once distributed.

Extract only where there is a reason: independent scaling, independent deployment cadence, team ownership, technology divergence, or isolation of a risk. "It should be a service" is not a reason.

Strangler fig for the extraction — route traffic through a facade, move one capability at a time, keep the old path until the new one is proven.

Know what a wrong boundary costs

Architectural debt charges interest on everything. A wrong boundary means every feature crossing it costs coordination between two teams, forever, and the cost grows with the number of features. Repay it incrementally attached to feature work; a proposed rewrite competes with delivery and loses.