How does the Common Closure Principle apply when the components are independently deployable services rather than packages, and what does a violation look like at that scale?
answer
- service = component; CCP still applies
- lockstep deploy = CCP violation at scale
- distributed monolith: entity/layer splits, shared schema
- re-cut around bounded contexts, own your data
- Conway: two teams owning one service = two reasons to change
basics
~20 sThe rule is the same but the cost is much higher: if one business change forces you to edit and release several services in lockstep, CCP is violated. That is a distributed monolith - the split followed technical or data lines, not business change.
solid answer
~50 sWhen the component is a deployable service, CCP says a service should encapsulate everything that changes for one business reason, so a feature can be shipped by changing and deploying one service. The violation signature is lockstep release: a story that requires coordinated edits to several services, a shared release train, or 'deploy B before A or it breaks'. Root causes are boundaries drawn by technical layer (a UI service, a logic service, a database service), by entity/CRUD rather than capability, or by shared mutable database schema. The remedy is to re-cut boundaries around business capabilities/bounded contexts so each owns its data and its full vertical slice, and to make contracts backward-compatible so producer and consumer can deploy independently. This trades against the Common Reuse Principle and independent scaling, and it interacts with Conway's law: a service that must change for two teams' reasons will never be independently deployable, so boundaries and team ownership should be aligned - and re-aligned when the change axes move.
go deeper
Say that a service is just a bigger component, so the rule still holds: a change should ideally touch one service, and needing to deploy several together is a warning sign.
Name the distributed-monolith symptoms - lockstep releases, ordered deploys, shared database - and connect them to boundaries drawn by layer or entity instead of capability.
Discuss re-cutting around bounded contexts with data ownership, plus contract evolution (additive changes, tolerant readers, consumer-driven contract tests) as the cheaper first fix, and be willing to merge services back.
Frame it economically and organisationally: services touched per story and coordinated releases per month as standing metrics, Conway alignment of teams to capabilities, an explicit trigger for boundary review, and acceptance that some contract co-change is inherent and should be made safe rather than eliminated.
## Same principle, higher stakes In a monolith, a CCP violation costs extra edits, a bigger rebuild, and a wider test surface. When components are **independently deployable services**, the same violation costs **cross-team coordination, ordered deployments, version-compatibility windows, and coupled rollbacks**. The principle scales; the penalty scales faster. ## The violation signature You have a CCP problem at service scale if any of these are routine: - One user story requires code changes in several services **in the same release**. - Deployments must happen in a **specific order**, or 'nothing works unless we ship them together'. - A **release train**: services are versioned and shipped as a set rather than on their own cadence. - A rollback of one service forces rollbacks of others. - Services share a **database schema**, so a column change is a multi-service migration. - End-to-end tests are the only meaningful gate, because no service is independently verifiable. The collective name is the **distributed monolith**: the operational cost of distribution with none of the independence benefit. ## Common root causes 1. **Split by technical layer.** A 'frontend service', a 'business-logic service', a 'data-access service'. This is package-by-layer at deployment scale - guaranteed fan-out per feature. 2. **Split by entity/CRUD.** An OrderService, a CustomerService, a ProductService, each a thin CRUD wrapper. Real capabilities (checkout, fulfilment, pricing) cut across all of them, so every feature touches several. 3. **Shared mutable data.** Several services reading and writing the same tables. Schema is the coupling; the code boundary is cosmetic. 4. **Breaking contracts by default.** Even a well-placed boundary produces lockstep deploys if every change is a breaking one. Expand/contract (tolerant reader, additive-only fields, dual-write/dual-read migration windows) restores independence. 5. **Premature decomposition.** Splitting before the domain's change axes are understood; boundaries end up guessing wrong. Starting as a modular monolith and extracting once the co-change data is in is the lower-risk sequence. ## The fix, in order of leverage - **Re-cut around business capabilities / bounded contexts.** Each service owns a capability end-to-end: its API, its logic, its data. A capability change is then one service, one deploy. - **Give each service its own data.** No shared schema; integrate through APIs or events. This removes the deepest source of lockstep. - **Make contracts evolvable.** Additive changes, tolerant readers, versioned events, consumer-driven contract tests. This decouples deployment even when both sides eventually change. - **Merge services that always co-change.** Two services that ship together on most changes are one component with extra network hops; recombining is a legitimate, senior move, not a retreat. - **Introduce an anti-corruption layer** where a volatile external dependency would otherwise propagate change inward - closing your services against someone else's release cadence. ## Interaction with other forces - **CRP / independent scaling pull the other way.** Very large capability services can be hard to scale independently or reuse. CCP at service scale still has to be balanced, and the balance point moves. - **Conway's law.** Organisations ship copies of their communication structures. If two teams own one service, that service changes for two sets of reasons - a CCP violation baked into the org chart. The 'inverse Conway manoeuvre' - shaping teams around the capability boundaries you want - is CCP applied to people. - **Business change axes are the real input.** Boundaries should follow where the business varies independently (regulatory reporting vs. pricing vs. fulfilment), not where the data model happens to normalise. ## Measuring it Track **services touched per story/change** and **coordinated release count per month**. Both are direct CCP proxies at architecture scale. A rising trend means the boundaries no longer match how the business changes - which is expected over time, and is the trigger to re-cut rather than evidence of an original mistake. ## The honest caveat Some coupling is inherent: a shared contract between a producer and consumer will always be co-changed occasionally. The goal is not zero cross-service change; it is that the **common** change is a one-service change, and that the rarer cross-service change is made safe by versioned, backward-compatible contracts.
- You inherit twelve services that always deploy together. What is your first move?Measure before restructuring: count services touched per story and identify which combinations recur. Then check whether the coupling is data (shared schema) or contract (breaking changes). Fix contracts first - it is cheap and restores independent deploys; re-cut or merge boundaries only where co-change is structural.
- Isn't merging two services back together an admission of failure?No. If two services co-change on most stories, they are one closure region paying network, deployment, and observability costs for nothing. Recombining them restores CCP; the boundary can be re-extracted later when the domain's change axes actually diverge.
- How does Conway's law relate to CCP at service scale?Organisations produce designs that mirror their communication structures. A service owned by two teams changes for two sets of reasons, violating CCP structurally - no amount of code hygiene fixes it. Aligning one team to one capability boundary (the inverse Conway manoeuvre) is CCP applied to the org chart.
Restaurant kitchens. Splitting by station - one team chops, one team fries, one team plates - means every new dish requires all three to retrain and coordinate on the same night. Splitting by dish, each kitchen owning its own prep, means a new dish is one kitchen's change.
saying these in an interview costs you the question
- Assuming microservices automatically satisfy CCP - splitting by entity or layer usually violates it
- Blaming lockstep deploys purely on boundary placement when the real cause is non-backward-compatible contracts
- Leaving services sharing one database schema and still calling them independently deployable
- Refusing to merge services that always co-change because 'we already split them'
- Ignoring team ownership, so a service serves two roadmaps and can never have one reason to change
- Treating a boundary set as permanent, when change axes shift with the business and boundaries must be re-cut