20 — Legacy Systems & Safe Change¶
Driving question: How do we improve design when the system is difficult to test and cannot stop changing?
Learning objectives¶
- Create seams that enable characterization tests.
- Separate behavior capture from design improvement.
- Plan dependency-breaking changes incrementally.
- Use branch-by-abstraction or strangler-style migration where appropriate.
Legacy code as code without sufficient safety net¶
The first challenge is often not “apply pattern X” but “create a place where change can be verified.” Techniques include:
- characterization tests;
- extract-and-override seams;
- wrapper/adaptor seams around external systems;
- dependency injection at selected boundaries;
- golden-master testing for complex outputs;
- branch by abstraction for staged replacement.
Refactoring economics¶
A technically cleaner target can still be a poor plan if migration cost, operational risk, or team capacity makes it infeasible. Graduate-level design includes transition architecture, not only end-state diagrams.
Design / research exercise¶
Choose one tightly coupled legacy dependency. Design the smallest seam that enables testing. Compare the seam with a full architectural rewrite and identify the migration risk avoided.
Suggested reading¶
- Michael Feathers, Working Effectively with Legacy Code.