Dealing with the monster called “Legacy Code”
What is legacy code?
The modern interpretations of legacy code is source code inherited from someone else and source code inherited from an older version of the software. Michael Feathers in his book named ‘Working effectively with legacy code’ introduced a definition of legacy code as code without tests, which reflects the perspective of legacy code being difficult to work with in part due to a lack of automated regression tests.
Why tackling legacy code is necessary?
- Adding a feature
- Fixing a bug
- Improving the design
- Optimizing the code due to current changes
What should not change when changing legacy code?
While changes (as mentioned above) are important in the legacy code, it is vital that the functionality of the code doesn’t change. However due to the lack of automated regression test, it is extremely difficult to ensure the functionality is not affected.
How to ensure nothing unintended is changed in legacy code?
Start with writing test for the legacy code. Considering legacy code will contain lot of logic in an unstructured manner, it is also difficult to start writing a test cases. It is pretty much impossible to complete all test cases in one go. To identify which part of the legacy code more test case are worthy is also a cumbersome task. In such a scenario an effect sketch comes handy.
What is Effect Sketch?
In effect sketch it is determined how a change in a variable will affect which part of the functionality.
For example let’s take the following example. The attribute which is in focus is variable ‘declarations’. From the piece of code it is clear that the variable is used in three different methods. However it is not possible to write the test cases for all three methods. To select which is the right method to write test cases, let’s do further analysis. The variable and methods are depicted in a bubble and the dependency is shown using arrows.
Drawing the effect sketch stepwise:
Step 1: The method getDeclarationCount is depend on the variable declarations and hence the first diagram is created.
Step 2: In the next steps, we add further methods which is depend on the variable.
Step 3: The final diagram looks like below considering all the methods related to the variable.
From the above sketch it is clear that on changing variable ‘declarations’, it will affect three methods. And there is a fan out. It would be difficult to write the test for all the function modules and with the current effect sketch it is not clear on which function to focus on. However if you look into the code closer and make small change in the code, it would lead in a clearer sketch and it would also help us in deciding which function should be the focus for the test.
So the final effect sketch is:
From the effect sketch it is clear that when we focus on the getInterface method, we can cover a larger part of the code as it will also test the getDeclaration method.
To draw an effect sketch is not an easy task. In many ways the effect propagates in the code and we need identify the ways. The basic three ways are:
- Return Values that are used by caller
- Modification of objects passed by reference
- Modification of Global data that is used later
Steps to identify side effects:
- Identify the method to change
- Check whether it has return parameters , if it has look at its callers
- Check whether method modifies any attributes
If yes look at the methods that use those values and methods that use those methods
- Check whether the parameters passed by reference is changed inside the method
- Look for global variables and static data that is modified in any of the methods
With the above information, hopefully it will help everyone in dealing with legacy code and identifying how a change in a variable will affect the functionality.
Enjoy working with legacy code.
Special thanks to Mohan George for supporting me in editing the blog.
Please refer to my other blogs at Rupali Ray’s Blog