27. Monolith vs Microservices
27.6 How do you draw service boundaries?
Living with services
In the restaurant: Put the tandoor and the naan in the same stall; they're used together every minute. Don't put the rice in one stall and the rice cooker in another. Split where the conversation between cooks is quiet.
In the system: Good boundaries follow business capabilities (what the business does), not technical layers:
- By capability / domain: catalogue, ordering, payments, shipping, recommendations. Each has its own language and rules (domain-driven design calls these bounded contexts).
- High cohesion inside, low coupling between: code that changes together and talks a lot stays together.
- Not by layer ("a database service", "a UI service") or by noun (one service per table): that guarantees chatty calls.
Figure: keep chatty parts together; cut where the traffic is light.
In the chapter's code, one order involves 21 calls between components. A split that separates chatty pairs (cart from catalogue, inventory from catalogue) makes 20 of them cross the network; a split by business capability, keeping catalogue, cart and inventory together as "shop", makes only 11 cross.
Signs a boundary is wrong:
- Two services always deploy together.
- One service constantly calls another for the same data.
- A feature always needs changes in several services.
- Teams negotiate every change across the boundary.
Boundaries are easier to find after living with the domain for a while, which is a strong argument for starting with a modular monolith and extracting later.
Memory code: "Cut where the cooks rarely talk."