When you have to modify some legacy code and you don’t have any tests1 to begin with, what do you do?
“Legacy code is simply code without tests.”
– Michael Feathers, from “Working Effectively With Legacy Code”
Regardless of why there aren’t any automated tests, in my opinion the right way to proceed is:
Write some characterization tests to pin down the current behaviour. This is fundamental because tests guides you to really understand the code you are going to modify. And more importantly, if you listen to them, they’ll reveal code smells that lie more or less unnoticed in the code base.
“If it stinks, change it.”
– Grandma Beck2, discussing child-rearing philosophy
This is quite simple, but not always easy:
In some cases, this could be a long and difficult process. The temptation to skip it and “Just Make It Work” may be very strong. My suggestion is: don’t4. Remember that technical debt erodes a system not by chance and suddenly, but little by little, workaround after workaround. The only way to maintain a sustainable pace is to stop adding technical debt, and repay it refactoring after refactoring.
As a system evolves, its complexity increases until work is done to maintain or reduce it.
Ignoring a problem won’t make it go away. Maybe you spare some time now, but you are preparing for a much greater damage down the line.
“The act of leaving a mess in the code should be as socially unacceptable as littering.”
––Robert C. “Uncle Bob” Martin
Tests are a good thing, and static types are also a good thing when it comes to maintainance. ↩
Kent Beck’s Grandma ↩
BTW, this actually happened to me… ↩
Well, as all guidelines there are exceptions. Maybe there is a legitimate and pressing need to deliver, in those cases cutting corners may be OK. But only if done in moderation, with awareness and by committing to fix it immediatly after the deadline. ↩