Coupling and Cohesion
Overview
Section titled “Overview”The previous topic listed what each style costs. It did not say how to tell which one a particular system needs.
That judgement comes down to two properties. They are old ideas, usually taught at the level of classes and functions; what follows is the same pair applied to boundaries between deployables, where the stakes are much higher because the boundaries are expensive to move.
The two properties, briefly
Section titled “The two properties, briefly”Coupling is how much a change in one part forces a change in another. Cohesion is how much the things inside one boundary belong together.
The design goal is not “low coupling” as an absolute — it is boundaries that contain change. A perfectly decoupled system where every feature touches six services has achieved nothing except distributing the problem.
Put the boundary where change stops, not where the diagram looks tidiest.
Boundaries that contain change — one requirement, one place to edit:
graph LR R1["New requirement"] --> A["Part A"] A --> OK["Ships from<br/>one deploy"] B["Part B"] C["Part C"] classDef touched fill:#D9695B,stroke:#B4483A,stroke-width:2px,color:#ffffff classDef quiet fill:#D8D3CB,stroke:#B8B2A8,stroke-width:2px,color:#3F3F3F classDef good fill:#7D9A4E,stroke:#5F7A38,stroke-width:2px,color:#ffffff class R1,A touched class B,C quiet class OK good
Boundaries that do not — the same requirement, four coordinated releases:
graph LR R2["New requirement"] --> D["Part A"] R2 --> E["Part B"] R2 --> F["Part C"] D --> SLOW["Four teams,<br/>four releases,<br/>one order"] E --> SLOW F --> SLOW classDef touched fill:#D9695B,stroke:#B4483A,stroke-width:2px,color:#ffffff classDef bad fill:#E8A33D,stroke:#C4832A,stroke-width:2px,color:#ffffff class R2,D,E,F touched class SLOW bad
The same change against two boundary layouts. Terracotta marks what has to be edited — and the second layout is what “we have microservices but releases take three weeks” looks like from above.
The kinds of coupling worth naming at this altitude
Section titled “The kinds of coupling worth naming at this altitude”You do not need a taxonomy. You need to recognise the three that make boundaries expensive to move later.
Shared data. Two parts reading and writing the same tables is the strongest coupling available and the least visible on any diagram. Nothing in a service boundary means anything if the database is shared, because the schema becomes a public interface that nobody is versioning.
Temporal coupling. One part must be available at the moment another runs. It is the coupling an event-driven style exists to break, and breaking it is also how you acquire eventual consistency as a product problem.
Semantic coupling. Two parts agree on what a field means. This is the one that survives every refactor, because it is not written down anywhere. A field renamed is caught by a compiler; a field reinterpreted is caught by a customer.
You cannot remove coupling, only move it
Section titled “You cannot remove coupling, only move it”This is the load-bearing idea of the topic.
Every seam you introduce converts in-process coupling into an interface — which is a thing to version, a failure to handle, a latency budget to spend, and a conversation between two teams whenever it changes. Decoupling is a transfer, not a deletion.
So the architect’s question is never “how do I decouple this?” but “where do I want the coupling to live, given which changes I expect?” Put the seams across the axes where change is rare and keep the frequently-changing parts on the same side of a boundary.
The cost of getting this wrong in either direction is asymmetric and worth knowing. Too few boundaries gives you a system that is hard to change safely. Too many gives you a system that is hard to change at all, because every change is a negotiation. The second is harder to recover from, which argues for fewer boundaries than instinct suggests — and for choosing them from evidence.
Change-case analysis: the cheap version of this judgement
Section titled “Change-case analysis: the cheap version of this judgement”You do not have to guess. Take three to five changes you genuinely expect in the next year, and for each one count the boundaries it crosses.
It costs an hour, it needs no tooling, and it routinely overturns a boundary layout that looked obvious on a whiteboard. The output is not a number — it is the observation that two components always appear together, or that one component is touched by every single change, which means the boundary is in the wrong place.
The limitation, stated honestly: it only tests the changes you thought of. It is evidence, not proof, and it is still far better than drawing boxes by domain noun and hoping.
Cohesion, in one paragraph
Section titled “Cohesion, in one paragraph”The mirror property, and the common failure is organising by technical layer rather than by reason-to-change: all the controllers together, all the handlers together. That maximises the number of boundaries every feature crosses, which is the exact opposite of the goal above. Group by what changes together. The cost of doing so is some duplicated plumbing inside each boundary, and that is a price worth paying.
Feeds the workbook
Section titled “Feeds the workbook”Run change-case analysis before you fill in the trade-off table. If a candidate structure makes two of your expected changes cross three boundaries each, that belongs in the table as a scored weakness rather than as a feeling.
→ Boundaries decided, the gross shape is set. Inside it there is a catalog of smaller, deliberate moves. — The quality tactics catalog