How much a change in one place forces changes elsewhere. Do things that should be independent actually stay independent?
It maps onto near-decomposability: In a well-architected system, interactions within subsystems are much stronger than interactions between subsystems.
Complex systems that survive are modular and hierarchical → Robust to change and evolutionarily adaptable.
What makes coupling expensive is how far changes propagate.
A module behind a narrow, stable interface can be heavily depended on cheaply (std library functions, for instance).
A module with a wide, volatile interface is expensive even with few dependents.
DRY, encapsulation, separation of concerns are all heuristics for “reduce coupling.”
DRY increases coupling: Extracting shared code to avoid repetition creates a dependency.
If the duplication was coincidental (same code, different reasons to change), you’ve coupled things that should be independent. A change for one caller’s needs now ripples to all callers. Three similar functions can be cheaper than one “flexible” function with flags and conditionals (→ the wrong abstraction).
Find good cut points: narrow interfaces that trap complexity behind them.
cohesion is the other side of the same question: coupling asks whether independent things stay independent, cohesion asks whether related things stay together.
Reducing one without the other doesn’t work: splitting a monolith into microservices lowers coupling but can destroy cohesion if you cut along the wrong boundaries.