Coupling
Context
In any system with more than one part, those parts relate to each other. Coupling is the degree of that interdependence: how much one part needs to know about, depend on, or coordinate with another. It operates at the architectural scale and is, alongside cohesion, one of the two fundamental measures of structural quality.
Some coupling is inevitable. A consumer that calls a function is coupled to that function’s interface. The question is never “is there coupling?” but rather “is this coupling necessary, and is it managed?”
Problem
How do you let the parts of a system communicate without making them so dependent on each other that changing one part breaks everything else?
Forces
- Zero coupling between parts means they can’t interact. They’re separate systems.
- High coupling means changes ripple unpredictably, testing requires the whole system, and parallel work becomes impossible.
- Some forms of coupling are visible, like explicit function calls. Others are hidden: shared global state, implicit ordering assumptions.
- Reducing coupling often adds indirection, which has its own costs in complexity and performance.
Solution
Manage coupling deliberately. Prefer coupling to stable interfaces over coupling to volatile implementation details. The hierarchy of coupling from loosest to tightest is roughly:
- Data coupling — parts share only simple data (parameters, return values). Loosest and safest.
- Message coupling — parts communicate through messages or events without direct calls.
- Interface coupling — parts depend on a defined interface, not a specific implementation.
- Implementation coupling — parts depend on the internal details of another part. Tightest and most fragile.
Push your design toward the top of this list wherever possible. Use abstractions and interfaces to create seams, places where you can change one side without disturbing the other.
In agentic workflows, coupling determines the blast radius of an agent’s changes. If module A is tightly coupled to modules B, C, and D, a change to A may require changes to all of them, and the agent must understand all four to work safely. If A is loosely coupled through a clean interface, the agent can work on A in isolation.
How It Plays Out
A web application stores user preferences in a global dictionary that multiple modules read and write directly. When the team tries to change the preference format, every module that touches the dictionary breaks. This is implementation coupling at its worst. They refactor: preferences are now accessed through a PreferenceService with a stable interface. The coupling shifts from implementation to interface, and the next format change requires editing only the service.
An AI agent is asked to swap out a payment provider. In a loosely coupled system, the agent changes the implementation behind the PaymentGateway interface and runs the existing tests. In a tightly coupled system, the agent discovers that payment provider details have leaked into the order processing module, the email templates, and the admin dashboard. What should have been a single-module change becomes a system-wide surgery.
“The payment provider details have leaked into the order processing module and the email templates. Refactor so that all payment logic lives behind the PaymentGateway interface and nothing else references Stripe directly.”
Consequences
Low coupling gives you the freedom to change parts independently, test them in isolation, and assign them to different people or agents. It makes a system resilient to change.
But coupling reduction isn’t free. Every seam you introduce (an interface, a message queue, an event bus) adds indirection, which adds complexity and can hurt performance. Over-decoupled systems are hard to follow because the path from “something happened” to “here is the effect” passes through too many layers. The goal is appropriate coupling, not zero coupling.
Related Patterns
- Paired with: Cohesion — aim for high cohesion within modules and low coupling between them.
- Managed via: Interface, Contract — these tools let you make coupling explicit and stable.
- Measured across: Boundary — boundaries are where coupling becomes visible.
- Reduced by: Abstraction — abstracting away details reduces implementation coupling.
- Arises from: Dependency — every dependency is a form of coupling.
- Related: Big Ball of Mud – mud is characterized by maximal, unmanaged coupling.