Service Boundaries and Data Ownership
Split by business capability
The hardest part of microservices is deciding where the lines go. Split by business capability – orders, payments, catalog, shipping – not by technical layer. A good service is cohesive (one clear responsibility) and loosely coupled (changes rarely ripple into others). Domain-Driven Design calls these boundaries “bounded contexts”.
Each service owns its data
The defining rule of microservices: a service owns its database, and no other service touches it directly. The Orders service is the only code that reads or writes the orders tables. Others must ask it through its API.
Orders service -> orders_db
Users service -> users_db
Billing service -> billing_db
Why not a shared database
A single database shared by all services seems convenient but re-couples everything: a schema change in one service can break others, and you lose independent deployment – the whole point of the architecture. Private data per service is what keeps services independent.
The consequence: distributed data
Because data is split, a query that used to be a simple SQL JOIN now spans services. You handle this by:
- Having a service call another’s API for the data it needs.
- Keeping a local read-only copy, kept up to date via events.
- Composing results in an API gateway or a dedicated aggregation service.
Right-sizing
“Micro” does not mean tiny. A service should be as small as it can be while still owning a meaningful capability. Too fine-grained and you drown in network calls; too coarse and you are back to a monolith.
Key points
- Divide by business capability, aiming for high cohesion and loose coupling.
- Each service owns its data; others access it only through its API.
- Avoid shared databases – they re-couple services and kill independent deploys.
- Distributed data replaces joins with API calls, events or aggregation.