We’ve been assigned work on legacy code. The maintainer is no longer around and we have no clue how the system should behave. What’s the safest way to go about it?
First we need to learn what the code we’re about to change does. After we make our changes, we compare the resulting state against the initial one to verify that we introduced only our intended changes.
We can get a snapshot of the initial system behaviour using characterization tests. Characterization tests help reverse engineer specifications and are a trustworthy source on system behaviour.
Here are the steps to adding a characterization test to a legacy codebase.
- 🤷Formulate a hypothesis – We choose a unit or behaviour we want to investigate and add a test to exercise it.
- 🙅Assert it – We purposely write a failing assertion and let the test output tell us what the correct output / behaviour is.
- 🙋Get a clear picture of the system – The test retraces our steps and it’s replayable. Any future change we’ll make will be compared to this snapshot so we can be sure we did not introduce defects.
Characterization tests serve as documentation for other folks that need to interact with the code and minimise the time it take to share expertise.
They’re also entertaining to implement – the process is somewhat like detective work, where we investigate different hypotheses to understand what the code actually does.
Characterization tests are great to implement in legacy codebases from the first moments when we’re still learning about the code and they’ll provide value even later on because they sustain refactoring efforts without introducing defects.