Working with legacy code can be difficult, especially if the code was written by some unknown programmer in an unfamiliar language. But according to Mob Programming's R Jason Kerney and Llewellyn Falco, bugs in legacy applications can be found and fixed relatively quickly with a couple of fairly straightforward tricks.
"I do not usually get the luxury of understanding [legacy] code, so I have to come up with techniques to let me work without understanding it," Falco said.
Falco and Kerney demonstrated their ability to find and fix bugs without the overhead of working out what legacy code does in a session at Agile2014 in Orlando. In their session, Tackling Legacy Code, the two programmers drew an analogy between working efficiently with legacy code and cutting into a mango. The meat of the fruit is the important code. The rest is either the peel or the pit. They referred to their technique colloquially as "peeling and slicing."
The basis of the peel-and-slice technique is to narrow the focus until the only code to examine is directly involved with a specific bug. Falco explained how to start at the outside and peel away layers to get down to the important code. Kerney showed how to slice out the pit that sits in between the bits of code in question. From there, it is relatively simple to see what's going wrong and how to fix it.
The use case
They demonstrated with a hypothetical financial application that produced multiple new records when it should have added information to existing records. Basically, if "Joe" has three separate loans, the legacy code produced three separate records for him that have one loan each. It should have added loans to the existing record for Joe.
The legacy application in question was hypothetically written in the Czech Republic by an outsourced software team that no longer exists and thus is unavailable to explain their code. In the hypothetical situation, there also was no easy access to the database itself, so there's nothing to learn from that.
The only known variables were what the code is expected to do when it runs, and what the code actually does when it runs. From just this information and the right tools, Falco and Kerney said it is possible to determine what's wrong in the legacy code and how to fix the problem.
Peeling away the tough code
The peeling technique requires separating the tough code and the important code. The basic plan is to split a complex method into two parts. The first will contain the tough code and the second part will contain the code that we want to get at. Then the important code can be extracted as a second method and treated as separate from the other code.
Generally, this will require some simple refactoring to "massage the code" into a more workable order. Kerney and Falco stressed that this refactoring is still simple enough to be done without actually understanding the code base of the legacy application under test.
Slicing out the pits
Llewellyn FalcoAgile coach and Legacy code expert
There are often portions of the code that are not easy to work with that cannot be separated as above. These parts are the pits in the Falco-Kerney mango analogy. This is where they employ the slicing technique, which is really about mocking out troubling components.
Kerney used a tool called EasyMock to mock out the database and abstract it out of the picture. He noted that this is very similar to the mocking process used in test-driven development. The difference is that instead of checking new code to see if it passes the test, this method is all about testing existing code to see what parts do or don't pass the tests.
Making the fix
By first peeling away the bulk of the code outside of the scope of the problem and then slicing away irrelevant code within that scope, Falco and Kerney were left with a handful of lines of code where the problem could be. With just a few lines of code to focus on, the duo was better able to see what was actually going awry.
It turned out, in this example, that two lines of code were written in the wrong order. Ordinarily, the order of these two lines would not matter. The order mattered here because of intricacies in the Java language and how it works.
When Falco and Kerney ran their tests on the simplified bit of code, it was apparent that the first line of code was being called too soon. It did not take much experimenting to find the right order, fix the bug and save the day -- all without really understanding the code.
A few words of caution
It's important to note that these techniques do not guarantee new dependency errors will not be produced if and when outside code refers to the altered code. However, as Kerney pointed out, "understanding the code doesn't ensure there aren't any lingering dependencies on it either."
When it comes to finding and fixing the bugs in old legacy applications, one could argue it's a waste of time to figure out how the legacy code works. There are some (possibly considerable) learning opportunities lost by not taking the time to learn the code. However, if that learning is really worth the developer's time, he or she can learn from the code after the bug is ironed out.
A look at the tools
Falco and Kerney ran their demonstration with software tools geared towards Java. The basic tools they used were the Eclipse IDE, JUnit test tools, EclEmma for test coverage and EasyMock to generate mock objects. The precise tools used would change based on the specifics of any given project.
A series of videos in which Llewellyn Falco explains these processes for .Net developers is available on YouTube.
While you're slaying all the bugs in your legacy code, don't forget to track the defects in your new projects.