Two teams share one service. Neither can deploy without coordinating with the other. A shared library upgrade blocks both for three weeks. The postmortem will say "poor architecture." The actual cause: two forces are misaligned — coupling is high where it should be low, and cohesion is low where it should be high.
The Concept
Coupling measures how much one module's change forces change in another. Cohesion measures how strongly a module's internals belong together.
High cohesion means everything inside a module serves one purpose. The payment module handles payments. It does not also manage user profiles. When you change the payment flow, you change one module.
Low coupling means modules interact through narrow interfaces. The payment module exposes an API. The order module calls that API. Neither knows the other's internal structure. When the payment module rewrites its database schema, the order module does not change.
The goal: high cohesion inside modules, low coupling between them. This produces modules that teams can deploy independently.
Production Mechanics
Shared database schemas are hidden coupling. Two services read the same table. One service adds a column. The other service's ORM breaks. Neither team intended to create a dependency. The schema created it for them.
Hidden coupling patterns:
Shared schema:
Service A ──reads──→ table: users
Service B ──reads──→ table: users
Service A adds column → Service B's ORM breaks silently
Shared library:
Service A ──depends──→ auth-lib v2.3
Service B ──depends──→ auth-lib v2.3
v3.0 ships with breaking change → both must upgrade simultaneously
Event bus (looks decoupled, is not):
Payment ──publishes──→ [Queue] ──subscribes──→ Order service
Order requires event within 500ms → queue is now latency-critical
Coupling moved from code to infrastructure
Shared libraries with breaking changes are explicit coupling. Service A and Service B both depend on auth-lib v2.3. The library ships v3.0. Both services must upgrade simultaneously or one breaks. The library that was supposed to reduce duplication became a coordination bottleneck.
Event-driven architectures reduce coupling by replacing direct calls with published events. Adding a third subscriber — an analytics service — requires zero changes to the publisher. But if the order service requires the payment event within 500 milliseconds, the event bus becomes a latency-critical path. The coupling moved from code to infrastructure. It did not disappear.
Conway's Law predicts that team boundaries become system boundaries. Two teams that communicate frequently build tightly coupled systems. Two teams that communicate through contracts build loosely coupled systems. The org chart is the first architecture diagram.
The Failure Mode
When coupled services share a dependency, one failure propagates to all. The authentication service goes down. Every service that calls it directly also fails. The blast radius equals the coupling surface.
A circuit breaker reduces the blast radius. But the circuit breaker is a patch on a coupling problem. The structural fix is to reduce the coupling surface itself. Fewer shared dependencies mean fewer failure propagation paths.
The Tradeoff
Perfect decoupling requires duplication. Two services that share nothing must each implement their own authentication, logging, and configuration. The duplication cost is real.
The decision is not "eliminate all coupling." The decision is "choose where coupling is acceptable." Coupling within a bounded context is fine. Coupling across bounded contexts creates deployment dependencies. The line between them is the most consequential architectural decision in any system.
The Signal
Two teams cannot deploy independently. A change in one service requires a change in another. A shared library upgrade blocks three teams simultaneously. These are coupling signals. Check the dependency graph. The number of edges crossing team boundaries is your coupling score.
Concept: Coupling and cohesion
Tradeoff: AT8 — perfect decoupling requires duplication; the decision is where coupling is acceptable, not whether it exists
Failure Mode: FM2 — coupled services share failure propagation paths; one dependency failure brings down every service that depends on it
Signal: Two teams cannot deploy without coordinating; a shared library upgrade blocks multiple services simultaneously
Series: Book 5, Ch 3