THIS EXPLANATION
THE ROOM
CDA·58 Computing, Data & AI 6 MIN · 8 STATIONS

Coupling

A Socratic walk-through of coupling — reasoned out one step at a time, not lectured.

abcdefgh
a

The question we started with

THE QUESTION #

Why can code with no repetition anywhere still be impossible to modify safely?

Imagine a codebase that would pass every tidiness check you could name. No copy-pasted blocks, no function longer than a screen, every constant defined once, names consistent throughout. By the usual measures it is exemplary. And yet a one-line change takes a week, breaks something in a distant module, and nobody can say in advance what it will touch.

That combination should be puzzling. If duplication is what makes change expensive, the absence of duplication should make change cheap. Clearly something else is doing the work. What is it?

b

Reasoning it through

REASONING #

Start by asking what actually happens when a change is dangerous. Danger means a change propagates: you edit here and something over there stops being true. So the question becomes — what makes an edit in one place able to falsify an assumption in another? The answer must be that the other place knew something about here. That knowledge is coupling.

Now the useful step: notice that duplication is only one way for two places to know something about each other. If the same constant is written twice, both copies know its value. Removing the duplication removes that particular shared knowledge. But it removes only that kind, and there are many others.

Work through a few. A caller knows a function's name and argument order — rename or reorder and the caller breaks. It knows the type of what comes back. It may know the meaning of a returned value, that minus one means "not found". It may know the order in which two calls must be made — open before write. It may know a timing property, that the call returns before the record is visible elsewhere. It may know that both it and another module write to the same table, so their assumptions about that table must agree even though neither mentions the other.

None of these is duplication in the textual sense. Each is a fact that lives in two heads. And this is the point: coupling is the number of assumptions two pieces of code make about each other, not the number of characters they share.

Which raises the sharper question — can coupling be eliminated? No, and it is worth being precise about why. Modules that never assume anything about each other also cannot cooperate; a system of perfectly independent parts is not a system. So the goal is never zero coupling. The goal is to make the assumptions few, explicit, and stable, so that most changes stay inside one module.

That reframes the design problem the way Parnas did in 1972: a module boundary is a decision about what you promise not to change. Whatever is inside can vary freely; whatever is visible has been promised. He argued that modules should be drawn around the decisions most likely to change — hide the volatile thing, expose the stable one. Read that way, "encapsulation" is not about privacy for its own sake; it is about shrinking the set of facts other code is allowed to depend on.

And now the paradox dissolves. De-duplication and de-coupling can pull in opposite directions. Extracting a shared helper deletes the repeated text and simultaneously creates a new dependency for every caller, plus a requirement that all of them agree about what that helper does. If the callers were unrelated, you have traded duplication — which does not propagate — for coupling, which does. The exemplary codebase in the opening may well have got that way by extracting everything shareable, which is precisely how a system ends up with no repetition and no ability to move.

There is a further wrinkle worth naming honestly: some coupling is not visible in the code at all. Two services can be coupled through a database table, a message format, a deployment order, or a shared clock. Static analysis will report them as independent. Only an incident reveals otherwise.

c

The analogy

THE ANALOGY #
THE FIGURE

Think of a building's plumbing. Two flats can share no fixtures at all — separate taps, separate basins, no repeated parts — and still be joined by a single water main. Change the pressure for one and the other's shower runs cold. Nothing was copied; something was assumed, and the assumption ran through a pipe nobody drew on the flat's own plan.

WHERE IT BREAKS DOWN

pipes are physical, so an engineer can eventually trace one; many software couplings exist only as an expectation in someone's head — that a field is never null, that a job runs after midnight — and there is nothing to trace at all until it is violated.

d

Clarifying the model

THE MODEL #

Three refinements.

First, coupling has strength, and the useful skill is ranking it. Depending on a name is weaker than depending on an argument order, which is weaker than depending on a return code's meaning, which is weaker than depending on timing or on internal state. The vocabulary of connascence exists to make this comparison sayable; the practical use is that a change which converts a strong form into a weak one is progress even if the code gets slightly longer.

Second, direction matters as much as quantity. A module depended on by twenty others is not badly designed by that fact — if its promises are small and stable, that is exactly what a good utility looks like. Trouble comes from a module that both depends on many things and is depended on by many things, since changes then arrive from both sides.

Third, the practical test is not "does this look clean" but "if I change X, what must I read?" A codebase where the answer is usually "this file" is loosely coupled, whatever its cosmetics. A codebase where the answer is "it depends, and nobody is sure" has coupling that nobody has written down — and the first repair is to make the assumptions explicit, in types, contracts, or tests, before trying to remove them.

e

A picture of it

THE PICTURE #
Coupling
Coupling Each box is a component that contains none of another's code, and each line is an assumption one makes about another -- the label says what is actually known, not what is called. Follow the two lines into the order table: the checkout service and the nightly report never reference each other, yet a column rename by either falsifies the other's assumption, which is coupling through shared data with no shared text. The chain from the mobile client through checkout to the pricing rules shows why change propagates: each link is a promise someone else is standing on. {"generator":"mermaid-svg-renderer@3.2.1","source":"../Socrates/.diagram-cache/_src/coupling.md","sourceIndex":1,"sourceLine":4,"sourceHash":"3bfc13aa4e036804516a0f98e522d4f3106f7ca04a967e63d7bd7bba1e93005e","diagramType":"er","layoutVariant":"source","repairedDuplicateIds":[],"motion":"entrance-with-reduced-motion-fallback","presentation":"editorial","attempt":1,"viewBox":{"x":0,"y":0,"width":1088,"height":748},"qa":{"passed":true,"findings":[]}} writes columns ithardcodes reads the same columns assumes its roundingbehaviour depends on field names inthe response promises a fixed columnorder CHECKOUT_SERVICE ORDER_TABLE NIGHTLY_REPORT PRICING_RULES MOBILE_CLIENT EXPORT_FILE

How to readEach box is a component that contains none of another's code, and each line is an assumption one makes about another — the label says what is actually known, not what is called. Follow the two lines into the order table: the checkout service and the nightly report never reference each other, yet a column rename by either falsifies the other's assumption, which is coupling through shared data with no shared text. The chain from the mobile client through checkout to the pricing rules shows why change propagates: each link is a promise someone else is standing on.

f

What became clearer

WHAT CLEARED #
WHAT CLEARED

Duplication and coupling are different diseases with similar symptoms. Duplication means one fact is written twice; coupling means one module's assumption lives in another module's behaviour, and only coupling makes a change spread. Since text-level tidiness can be achieved by adding dependencies, a codebase can be immaculate and immovable at the same time. The design question is therefore not how little code repeats, but how few things other people are allowed to assume — and how many of those assumptions are written down rather than merely believed.

g

Where to go next

ONWARD #
  • Connascence as a graded vocabulary for the strength of a dependency, and what "weakening" one actually looks like in code.
  • Why coupling through a shared database is the form most often invisible to tooling, and how contract tests expose it.
h

Key terms

TERMS #
TermWhat it means
Couplingthe degree to which one unit of code depends on assumptions about another; measured by what must change together, not by shared text.
Change propagationthe spread of a single edit into other modules that relied on what it changed.
Information hidingParnas's principle of drawing module boundaries around the decisions most likely to change, so volatility stays private.
Connascencea taxonomy ranking forms of dependency (on name, position, meaning, timing, order) by how strongly they bind two components.

Every term the collection defines is gathered in the glossary.

Nearby on the shelf

4