
Agile Tips
Unlocking Agile Wisdom: Insights from Decades of Experience. Scott Bain is a 44+ year veteran of systems development.
Agile Tips
#32-Legacy Code and Magic Buttons Part 2
Last week I teased the notion that it's possible to bring your legacy code under better control by using a magic button. While such buttons obviously do not exist, this week I'll outline how to get the value of such a resource anyway, at a manageable cost.
I'll start by reiterating our thought experiment from last week.
Imagine there are two magic buttons, A and B. Button A instantly generates tests that cover 90% of your legacy code, but the 10% not covered is completely unknown. Button B gets you 75% code coverage, but the 25% that remains is clearly defined.
I suggested that there is a way to get the value of Button B, not at zero cost but at a cost that you can control, measure, and budget for.
The prerequisite to this approach is that your technical team must know to conduct test-driven development properly, must have strong skills in refactoring, and must have brought both of these to maturity. This will take time, effort, and training and is certainly not without costs, but I hope I've made it clear that I think this should be done anyway. So, there will be no additional costs, so far.
The next step is to set a firm policy in place, and again it is a policy that I think should already be adopted regardless of the legacy situation in an organization. It is this:
No change may be made to any part of the system until the associated test has been changed first, observed to fail, and then made to pass by updating the system. When seeking to make the test pass, the test itself may not be altered in any way.
Why this is a good idea in general I will address in another tip. But in terms of legacy code, the realization it forces is that most legacy code is untested, at least in the sense that TDD means "tested." That means that in order for the policy to be adhered to, the team will have to start by bringing the portion of the legacy code that is to be changed under the protection of a TDD-style test, so that they can change it first.
That may be difficult, but it is manageable because it only involves a single change. Some refactoring may be required to make the involved part of the codebase testable, but that will also create an incremental improvement to the legacy system overall.
This also means that the system will become, gradually, more thoroughly tested, and the unit tests that are added to it will identify where such improvements have been made and where they have not. Code coverage measurement tools, which TDD typically ignores, can actually help in this process because they help us to track where we are in the gradual, realistic, manageable process of improving our legacy code.
Some parts of the legacy system in question will never gain such a test, but that will only be because a) they work properly and b) they apparently never required a change. Tests of code like that are probably not necessary anyway and may even be wasteful.