Cyclic Dependency
Two or more components depend on each other directly or indirectly.
“Allow no cycles in the component dependency graph.” – Acyclic Dependencies Principle (ADP)
A depends on B, and B depends on A.
Signs of Use (Symptoms)
- Changes in one component cause ripples in seemingly unrelated components.
- You cannot test one component without dragging in the other.
- Build tools warn about circular dependencies.
- “God Objects” or “Hubs” that everyone knows about, and that know about everyone.
Why it is bad (Consequences)
- High Coupling: Components are locked together.
- Testability: Impossible to unit test in isolation.
- Infinite Recursion: Potential stack overflows during serialization or construction.
- Build Ordering: Compilers can’t determine which to build first.
Why it happens (Root Cause)
- Lack of architectural layering.
- “Convenience” (e.g., User needs to know about Order, Order needs to know about User).
- Poor responsibility assignment.
When it might be okay (Exceptions)
- Closely related classes (e.g., Parent/Child in a DOM tree) within the ANY SAME package/module. But NEVER across architectural boundaries.
Explanation
Problem
You split code into modules to lower cognitive load. Any module should likely be able to function or be understood without knowing the entire system.
The Flaw
If A -> B -> A, then A and B are effectively one large component. You haven’t really separated them.
Real world analogy
Two friends who can’t decide where to eat. Alice: “I’ll go where Bob goes.” Bob: “I’ll go where Alice goes.” Result: Deadlock.
Refactoring Solution
- Dependency Inversion Principle (DIP): Introduce an interface. A -> Interface <- B.
- Mediator: Introduce a third component. A -> M <- B.
- Events: A emits event, B listens. No direct dependency.
Pros and Cons (of the Antipattern)
| Pros (Why people do it) | Cons (The price you pay) |
|---|---|
Comparison
- Related Antipatterns: Spaghetti Code, God Class.
- Related Principals: Acyclic Dependencies Principle (ADP), Dependency Inversion Principle (DIP).
Code example
Typescript
Bad (The Antipattern)
Good (The Fix)
PHP
Bad (The Antipattern)
Good (The Fix)