Top tips on working with legacy code
I have worked with a couple of legacy codebases in past years. Based on my learning, I have attempted to gather a few high level tips to help work with such code to ensure productivity and help in continuous improvement of the code base to make it more manageable.
Understand the context: Know the history of code
The reason we categorise a source code as legacy codebase is its age. Which means it has years of context, perspectives, history of technical decisions and coding styles of different developers hidden in it.
So depending on your intent of change, it is very important to:
- Study the system architecture to understand workflow and dependencies
- Arrange a session with SMEs and connect as and when required
- Make note of various tools and frameworks used, and find out how and why they were introduced
- Go through all documentation related to functionality and history of change.
- If you find some information through conversations with folks, add to documentation.
- Always check the git history to see the trail of changes and the reasons for it through JIRA tickets and/or comments. Have a conversation with experienced developers to get context if needed.
Once you understand the code, you can make changes with greater confidence.
Add tests: Create a safety net
A good suite of well written tests make any code base robust and easy to change. Characterisation tests and unit tests also help to build context for all developers by making functionality and work flows easy to understand. But a very common finding in legacy code is lack of good tests.
So, add tests as guided by the test pyramid to ensure the right number of tests, fast feedback and defect-free code.
Whenever legacy code is edited, ensure that unit tests are immediately added to the relevant section to confirm that the particular piece of code that was touched, functions in the same way it did, earlier. This will create a safety net for the whole code slowly.
Follow clean code practices: Maintainable code
Writing code by following clean code guidelines ensures that the code is readable, maintainable and well-designed. It should also be extensible and easy to change.
Clean code practices include practices like using meaningful variable names/function/class names, reuse code, follow OOPs concepts for good design, writing unit tests, adding comments where necessary and so on.
Few tips to introduce clean code in a legacy codebase:
- Fix/clean code while working on a task/story.
- Follow clean code practices for all kinds of code: production code, test code, infra code.
- Leave code cleaner than before
- Create tech debt cards for bigger refactoring, and pick them in future sprints
- Train the whole team to follow standard coding practices.
- Along with refactoring the code, also indent and format code where required, to make it more readable.
Refactoring is the process of changing the structure of the code without changing its functionality.
It is the best way to slowly change problematic areas of legacy code to improve code quality as well as maintainability.
Few high level tips for refactoring code:
- Refactor code that has unit tests — so you can validate the functionality. Write unit tests first if they don’t already exist.
- Start with the deepest point of your code — it will be easiest to refactor.
- Run unit tests after refactoring — to make sure you didn’t break anything.
Static code analysis tools: Tech metrics
Static code analysis tools help teams to analyze code to find code smells and security vulnerabilities. Example of one such tool I have used is Sonarqube. It shows the code smells, bugs, code coverage and other similar metrics for the source code.
Along with these, additional tools like dependency check tools can be used to identify security vulnerabilities in the code.
One of the major issues in legacy code is: outdated technology. This includes older versions of tools/libraries, outdated tech stack, custom frameworks etc.
These can be tackled one by one as individual initiatives and changed across the application. If the code is already modularised then it can be done one module/microservice at a time. If not, then one of the first task must be to look into modularising the code so that upgrades can be done on smaller pieces of code with minimal impact.
Collaboration: Key to success
There are many ways for a team to work in a collaborative way to tackle and improve a legacy code while still managing to achieve common team goals.
- Pair programming with other developers in the team is a great way to discuss and apply good design ideas, share knowledge and also learn from fellow developers.
- Regular tech huddles with the team help in discussing ideas and approaches.
- Collaborating with BAs and QAs in story/task kick-offs, desk checks etc also helps in bring the team on the same page and making sure that the product is developed with the right requirements and good quality.
I hope this article was helpful in identifying the key areas where legacy code needs attention.
All the best !!