Skip to content

Loose Coupling

Coupling describes how much two parts of a system depend on each other. It can be low (also called loose or weak) or high (tight or strong). Another way to see it is independent variability: if you change system A, must system B change too? If not, they are loosely coupled.

Coupling is not an on/off property. It is a sliding scale with many dimensions. A design can be loose in one dimension and tight in another. For example, an event-driven design is not automatically loosely coupled.

Kinds of coupling

  • Content coupling: one module uses the code of another. This is the strongest procedural type.
  • Common coupling: several modules share access to the same global data. This is tighter than data coupling.
  • Data coupling: modules share data through parameters. This is the looser form.
  • Temporal coupling: actions are bundled into one module only because they happen at the same time. In a different sense, with synchronous calls a slow provider also slows its requestor, so the delay cascades. Asynchronous messaging cannot make an unavailable system available.
  • Location coupling: logical addressing tolerates change better than physical addressing.
  • Data format coupling: tagged formats such as JSON or XML loosen format constraints. Format coupling can still undermine other decoupling efforts.

Invisible coupling

Shared custom data types create hidden knowledge dependencies. Both components must know the same custom definition. Standard formats loosen this kind of interface coupling.

Ways to loosen coupling

  • Dependency injection and interface-based programming reduce coupling strength and help maintainability.
  • Intermediaries sit between parts. An enterprise service bus (ESB, middleware that connects systems) was invented to achieve loose coupling in multiple dimensions.

An order service needs customer data from a customer service. In a tightly coupled design, it reads the customer database directly and relies on a custom record layout. Any change to that database breaks the order service. In a looser design, the order service asks for the data through a parameterized call. It uses a standard format such as JSON and finds the provider by a logical name, not a physical address. The customer team can now change its internals without touching the order service.

Looser is not always better. The right level of coupling depends on how much control you have over the endpoints. If you own both sides, tight coupling can be acceptable.

Intermediaries have a cost. Full location decoupling through an intermediary shifts the change dependency to a central component. That component can become a bottleneck, like a “god class” that everything depends on.

  • The document states where tight coupling is accepted and why, for example because the same team owns both endpoints.
  • Shared custom data types between components are identified, since they create hidden dependencies.
  • Synchronous calls are reviewed for cascading slowdowns when a provider is slow.
  • Any intermediary that decouples locations is checked for becoming a central bottleneck.
  • Shared global data between modules is avoided or justified, since it is tighter than passing data by parameters.