Yo-Yo Problem
The Yo-Yo Problem is a deep inheritance hierarchy that forces readers to bounce between many classes to trace one operation. Flatten the hierarchy and favor composition so each behavior is cohesive and readable in one place.
The Yo-Yo Problem describes the experience of reading code in a deep inheritance hierarchy: to understand what one method does, you must repeatedly jump up to the parent, then down to a subclass override, then up again to another ancestor — bouncing like a yo-yo through many files to assemble the full picture of a single operation.
Why It Happens
It arises when inheritance is used heavily to model variation, producing tall chains of base, abstract intermediate, and concrete classes. Template-method designs that scatter small overridable hooks across several levels make it worse. Each layer seemed reasonable when added, but together they fragment behavior so that no single class tells the whole story.
Why It Hurts
Comprehension is expensive: a developer must mentally merge contributions from every level to know what actually runs, holding multiple files in mind at once. Bugs hide in the gaps between layers, where an override partially changes inherited behavior. The hierarchy is fragile — a change in a base class ripples unpredictably through descendants (the fragile base class problem). Onboarding is slow, and refactoring is risky because the effective behavior of any concrete class is an emergent sum of distant code.
Warning Signs
- Inheritance chains several levels deep.
- Understanding one concrete class requires opening many ancestor files.
- Behavior of a single operation spread across base, abstract, and concrete levels.
- Frequent surprises when a base-class change breaks distant subclasses.
Better Alternatives
Prefer composition over inheritance: assemble behavior from small collaborators that can be read in one place, rather than spreading it across a tall chain. Flatten the hierarchy by collapsing thin intermediate classes and favoring shallow inheritance (one or two levels). The strategy and decorator patterns let behavior vary by composing objects instead of subclassing. Where shared code is the only motivation, extract it into helpers rather than a base class.
How to Refactor Out of It
Map the hierarchy and identify levels that exist only to share a little code or add one hook. Collapse thin intermediate classes into their parent or child. Convert variation that is really 'pluggable behavior' into injected strategy objects, so each behavior lives in one cohesive class. Replace template-method hooks scattered across levels with composed collaborators. Aim for hierarchies no more than a level or two deep, and confirm with tests that each concrete type's behavior is now understandable from few, nearby sources.