Skip to main content

Coupling: Minimize What a Module Needs to Know

What This Concept Is

Coupling is how much one module must know about another in order to work. Two modules are tightly coupled when a change in one forces a change in the other. They are loosely coupled when each can change independently as long as a narrow, agreed-upon contract is honored.

Coupling is not a single scalar. It comes in kinds, roughly from cheap to expensive:

  • Message coupling: one module calls a method on another through a stable interface.
  • Data coupling: modules share simple data through parameters and return values.
  • Stamp coupling: modules exchange whole records when they only use a few fields.
  • Control coupling: one module passes a flag that makes another branch.
  • Content coupling: one module reaches into another's private state or implementation.

Lower-numbered kinds are usually cheaper; the last one is a red flag.

Why It Matters Here

You cannot build software that survives change without managing coupling. Every concept in this module exists to reduce unnecessary coupling without losing useful structure.

Specifically: the SOLID principles are largely about which coupling is safe. Depend on stable abstractions (DIP), depend on narrow interfaces (ISP), and extend rather than modify (OCP) -- all three are coupling-management moves.

Concrete Example

Tight coupling (content coupling, reaching into another class):

class ReportPrinter {
void print(Order order) {
// reaches across the boundary: relies on private representation
for (Item item : order.items) {
System.out.println(item.name + " " + item.price);
}
}
}

ReportPrinter now depends on Order.items being a public, iterable list of Item with name and price fields. Any change to the representation breaks the printer.

Loose coupling (message coupling through a narrow method):

class ReportPrinter {
void print(Order order) {
for (String line : order.lineItems()) {
System.out.println(line);
}
}
}

Order now owns the representation and exposes only a narrow operation. ReportPrinter knows less, so less can break.

Common Confusion / Misconception

"Less coupling is always better." It is not. Zero coupling is zero collaboration, and you are not building a system of lonely classes. The goal is to pay coupling only when you get something for it, and to prefer cheap coupling (messages over private state, data over flags, interfaces over concretions).

A second misconception: "two classes in the same file are coupled." File layout and coupling are unrelated. Two classes in one file can be entirely independent; two classes in separate packages can be tightly coupled through shared mutable globals.

How To Use It

When writing or reviewing code, ask the coupling questions before reaching for a pattern:

  1. What does this module need to know about its collaborators?
  2. Is it reaching past an interface to touch state that should be private?
  3. If I changed a private field on the collaborator, would this code need to change too?
  4. Can the collaboration move to a stabler abstraction (interface, narrow method)?

Check Yourself

  1. Why is "content coupling" the most expensive form?
  2. Why can two classes share data through parameters (data coupling) without being problematic?
  3. What is the difference between coupling and cohesion?

Mini Drill or Application

Pick any two modules you have written that depend on each other. Do all four:

  1. Name the coupling kind on that edge (data, stamp, control, content, message).
  2. Write the narrowest interface one could ask of the other.
  3. Identify one private detail currently leaking through the dependency.
  4. Sketch a rename or extraction that would pull the leak back behind the boundary.

Read This Only If Stuck