Chapter 14: Component Coupling
"The dependency structure between components must be a directed acyclic graph (DAG). There can be no cycles."
๐ For New Learnersโ
The Three Coupling Principlesโ
While cohesion answers "what goes inside a component," coupling principles answer "how should components depend on each other":
| Principle | Rule |
|---|---|
| ADP โ Acyclic Dependencies | No cycles in the component dependency graph |
| SDP โ Stable Dependencies | Depend in the direction of stability |
| SAP โ Stable Abstractions | Stable components should be abstract |
ADP: The Acyclic Dependencies Principleโ
Cycles in the dependency graph are catastrophic:
ComponentA โ ComponentB โ ComponentC โ ComponentA (cycle!)
To change any component in the cycle, you must consider changes to all components in the cycle. You cannot test A without B and C. You cannot release A without releasing B and C. The cycle makes the group of components a single monolithic block disguised as separate pieces.
Breaking cycles โ two solutions:
-
DIP: introduce an interface that inverts the dependency. If
ComponentCdepends onComponentA, create an interface inComponentCthatComponentAimplements. Now the runtime call goes from C โ A, but the source code dependency goes from A โ C. Cycle broken. -
New component: extract the shared thing that creates the cycle into a brand new component. Both A and C depend on the new component. No cycle.
SDP: The Stable Dependencies Principleโ
Stability doesn't mean "doesn't change." It means: hard to change because many things depend on it.
- A component with many fan-in (things depending on it) is stable โ changing it breaks many things
- A component with many fan-out (it depending on many things) is unstable โ it changes frequently because its dependencies change
SDP says: depend in the direction of stability. Volatile components (high fan-out, few dependents) should depend on stable components (high fan-in, few dependencies). Never the reverse.
Stability metric: I = fan-out / (fan-in + fan-out)
I = 0: maximally stable (nothing depends on anything external; many things depend on it)I = 1: maximally unstable (depends on many things; nothing depends on it)
SDP: dependencies should point from high-I components to low-I components.
SAP: The Stable Abstractions Principleโ
A maximally stable component that is also maximally concrete is maximally rigid โ it cannot be extended without modification (OCP violation).
The solution: stable components should be abstract. Stability + abstraction = flexible stability.
- Concrete + Unstable: fine โ volatile details that change freely
- Abstract + Stable: ideal โ stable policies expressed as interfaces that can be extended
- Concrete + Stable: problematic โ rigid, hard to extend (the "zone of pain")
- Abstract + Unstable: useless โ interfaces nobody depends on (the "zone of uselessness")
๐ฌ Senior Deep Diveโ
Cycle Detection in Maven Projectsโ
Maven's dependency-check plugin and ArchUnit can detect cycles:
// ArchUnit: fail the build if cycles exist between packages
@Test
void noCyclesBetweenPackages() {
JavaClasses classes = new ClassFileImporter()
.importPackages("com.example");
slices().matching("com.example.(*)..").should().beFreeOfCycles()
.check(classes);
}
In a multi-module Maven project, cycles between modules cause Maven build failures โ Maven enforces DAG structure at the module level, which is one reason multi-module projects improve architecture.
SDP and the Clean Architecture Layersโ
The Clean Architecture's concentric rings are ordered by stability:
| Layer | Stability | Instability Metric (I) |
|---|---|---|
| Entities (domain) | Most stable | ~0 |
| Use Cases | Stable | Low |
| Interface Adapters | Unstable | Medium |
| Frameworks & Drivers | Most unstable | ~1 |
Dependencies point inward (toward stability). The domain layer has the highest fan-in (everything depends on it) and nearly zero fan-out (it depends on nothing external). This is SDP + SAP realized as concentric rings.
SAP Metrics and the Main Sequenceโ
Martin introduces the "Main Sequence" โ the ideal line on a graph of Abstractness (A) vs. Instability (I):
A
1 โ โ Zone of Uselessness
โ (abstract but nobody depends on it)
โ
โ โฒ Main Sequence
โ โฒ (ideal)
โ โฒ
โ โฒ
0 โโโโโโโโโโโโ Zone of Pain
0 1 I
(concrete and maximally stable = rigid)
Components should plot near the main sequence. Distance from the main sequence is the metric of architectural health:
D = |A + I - 1|
D near 0 is ideal. High D means either "zone of pain" (stable + concrete) or "zone of uselessness" (abstract + unstable).
Applying These Metrics in Spring Projectsโ
A typical Spring application's component metrics:
Domain model (pure Java)
fan-in: high (used by everything)
fan-out: near zero
Abstractness: high (interfaces, value objects)
โ I โ 0, A โ 0.7 โ near main sequence โ
Spring Boot starter classes (@SpringBootApplication)
fan-in: near zero (nothing depends on the main class)
fan-out: very high (depends on all other components)
Abstractness: near zero (concrete configuration)
โ I โ 1, A โ 0 โ near main sequence โ
Spring @Service "God service" class
fan-in: high (many controllers depend on it)
fan-out: high (depends on many repos, clients, utils)
Abstractness: zero (concrete class)
โ I โ 0.5, A = 0 โ Zone of Pain โ
The God Service is architecturally dangerous: it's concrete (hard to extend) and moderately stable (hard to change without breaking callers), but not abstract enough to be extended cleanly. Breaking it up โ making it depend on interfaces, extracting smaller use cases โ moves it toward the main sequence.
Summaryโ
| Principle | Core Rule | Violation Consequence |
|---|---|---|
| ADP | No cycles | Cycle = monolith in disguise; cannot release independently |
| SDP | Depend toward stability | Stable component depending on volatile one = unexpected breaks |
| SAP | Stable components should be abstract | Stable + concrete = Zone of Pain (rigid, can't extend) |
| Main Sequence | Balance stability and abstraction | Use D metric to identify architectural problem areas |