Legacy Code

Code that is risky to change because its behaviour is poorly understood or weakly protected — and the characterization-test, seam, small-step loop that makes it safe.

What "Legacy" Actually Means
▶ lab

Legacy code is code that is risky to change because its behaviour and assumptions are poorly understood or weakly protected. Age is a correlate, not the definition.

Q · Which code in this repository is legacy, and what property am I actually measuring when I decide?
Characterization Tests
▶ lab

Tests that record what the code does today — including what it does wrongly — so that a later change has a baseline to be measured against. They assert behaviour, not correctness.

Q · How do I get a safety net around code whose correct behaviour nobody can state?
Seams
▶ lab

A seam is a place where you can change behaviour, or substitute a dependency, without editing the code at that place. Finding one is what makes untestable code testable.

Q · This code reaches out to the network, the clock and the database from inside a nested loop. Where can I get a grip on it without rewriting it?
The Legacy Change Loop
▶ lab

Understand, characterize, seam, small refactor, change behaviour, verify — in that order, because each step is what makes the next one safe rather than brave.

Q · A ticket needs one behaviour changed in code with no tests. What is the actual sequence of moves, and why is that the order?
The Strangler Pattern
▶ lab

Put a routing layer in front of the old system, move one behaviour at a time behind it, expand until nothing is routed to the old system, then retire it. The old and new run together for a long time.

Q · The module is too large and too unprotected to change in place, and a rewrite is too risky. What is the third option?
The Risk in a Rewrite
▶ lab

Rewrites fail for four specific reasons — hidden requirements, the delivery gap, migration complexity and feature-freeze pressure. They are sometimes still the right call, and the conditions are nameable.

Q · What exactly goes wrong in a rewrite, and under what conditions is one actually the better bet?
Incremental Migration
▶ lab

Old and new coexist; you migrate one slice, verify it against reality, and repeat. The design work is choosing the slice and defining what "verified" means.

Q · If old and new have to run side by side for months, what does one increment consist of and how do I know it worked?