My definition of legacy code comes from an interesting interview Michael Feathers gave at dZone. He defines legacy code as “code without tests”. And I bet, there is a lot of that stuff out there. But what if you decided to develop test-driven in the meantime? Should you leave the legacy code as it is? If you still want to use it, the answer is of course NO. But how could you make this good old big ball of mud better maintainable?
Tests give you a certain amount of stability as they fail when you break functionality. This amount heavily depends on the coverage rate, which measures the amount of code paths of your program are tested by your tests. Normally, test driven development also leads to testable code – smaller classes, encapsulated functionality. If you have a program, that was written some time ago without any tests and maybe evolved over time, it’s very likely, that you best can compare your code to spaghetti. Every class somehow relates to 50 others, functionality is spread all over the classes like tomato sauce and you really don’t like to change anything, because the whole thing surely will break.
The best idea then is to wrap the whole thing into an accompanying skeleton of acceptance tests, to ensure that you don’t break main functionality when refactoring and changing code. Then you can start to split the whole chunk into smaller units, that then can be tested in a more modular way. (xUnit anyone?)
The big advantage of this approach is, that you don’t have to do it all at once. Start writing the acceptance tests and start writing unit tests for bugfixes. Maybe you also have some more minutes when fixing a bug and increase the code coverage by adding another small unit test for some other small class. When you’re feeling comfortable about the code coverage and about the interdependencies of your code, you can also do some refactorings without too much risk. Step by step, the big ball of mud will become a maintainable piece of code with good test coverage and not too much time wasted.