If you ever needed to make a legacy code work with the newer one you might have noticed that it is a bit of a challenge; especially if you are not the author of neither version and original creator is no longer available to be constantly harassed and followed with questions about why things the way they are.
For the past 6 month I’ve been doing exactly what most people don’t like to do and consider it to be a boring task – porting legacy features to newer releases. Although, there is no magic bullet that could make porting tasks a breeze, but there are way to ease the pain along the way. In this post I’ll briefly outline practices that helped me and hopefully will help others to ease the experience. If you find yourself thinking that following information is obvious and fairly straightforward, you may pat yourself on a shoulder. I wish you shared your knowledge with me before I had to figure things out on my own. Nevertheless, let’s get to it.
1) Ask for a Documentation.
First thing to do when your team lead/program manager/senior developer/the boss has given you a porting task is to ask for a documentation and contacts of someone who is at least vaguely familiar with a code base in question. Having any information on what a code does before starting to dig through it is a huge advantage. You still have to read a code, there is no way around that, just because it is often a case that a documentation is left unattended and a code upgrades go forward without any trace in docs. The most valuable thing that you should be looking for in docs are:
- What does it do? What is the purpose of a code you are trying to port?
- How does it do it? What are the main components? Data flow and component interactions.
I wouldn’t bother with reading class diagrams and low level details at this point,
it is always a good idea to take in information in smaller chunks. Plus as I mentioned
earlier diagrams could simply be wrong.
2) Copy over whatever is needed according to a documentation.
Don’t worry about design patters or refactoring at this point. Refactoring to cleaner architecture requires deep understanding of system components and the way they interact with each other. Don’t spend your mental capacity on that yet. Plug whatever you brought in into your building process. If you have a luxury to build parts of your system in isolation figure out where you need to instantiate your old feature. Implement that part and start compiling/interpreting or running unit tests. It is a perfect starting point. Modern compilers are smart and should be considered as your friend. First time you try to compile your code it will blow up and spit a ton of errors. Those errors are valuable information. You could use it as a some sort of a diff, a guideline for you to follow and make things work.
3) Comment out everything that you don’t understand.
Leave a minimal class skeletons with stubs for functions/methods. If function arguments cause compilation errors comment out entire function signature and body, and any function calls. Spare yourself some frustration and headache, just do it. It is always a good idea to decrease the amount of things that you need to think about at the moment. Commenting out broken code does not solve your main task but it is a way to make a compiler happy. Keeping a compiler happy means that you can run unit tests and verify that things do what they are expected to be doing. If you think about it, every time you see a green bar after running unit tests you have a functional code. You not only have something concrete to show your manager and commit to git, but also a comfortable stepping stone that allows you not to worry about having a correct values in your last conditional statement.
4) start to Uncomment lines one by one.
Starting from your old feature constructor, begin to uncomment some lines of code.
As you start to do that you’ll have a single point of focus and a happy compiler. Start with a method signature and arguments, then proceed to method body. After each finished method/function write a unit test. It is a perfect time to do that. You understand ins and outs of a function since you just went through it line by line. The rest is just work. Uncomment method signature -> method body -> write unit test; and all this while keeping compiler happy.
If you find the post helpful, subscribe and like. Really want to hear your thoughts and ways other people are approaching similar tasks.