In Global Software Architecture Summit in Barcelona, we talked about “Legacy Code” and there were many opinions about it. I decided to do a small research to continue investigating, I read books about this topic and talked with our software development team to see what it is exactly and what are the most common and right approaches of working with Legacy Code.
I must say that while doing this research, I saw that very often programmers call “legacy code” when they join a project and they don’t like the existing codebase. But is it right to call it “legacy code”? In our opinion – not really. If you join a project and there is a 15-year-old codebase that still does what it was designed to, bug-free, nurture it, don’t rewrite it. Users don’t care about the age of the code, they care about working software.
The common problem of software developers that they always want to rewrite everything, living in a constant state of feeling their code could be dramatically improved. But do you remember the famous quote about it? “It’s harder to read code than to write it.”
So, what are the common definitions of Legacy Code:
- All code is Legacy Code
- Code that developers don’t like
- Code that developers don’t understand because there is a lack of documentation
- Code developers inherit
- Code built using obsolete practices and platforms
- Code without unit tests
- Code that is high-risk to change
Michael Feathers in his book “Working Effectively with Legacy Code” defines legacy code as code without tests. And we totally agree with him!
It’s true that legacy codebases are often tightly coupled, overly complex, and weren’t written with modern understanding of good design principles in mind. Whether developers are working with a legacy codebase they’ve inherited, or one they wrote themselves over some period of time, they probably have experienced the pain that can be involved with trying to change a large, complex system that suffers from a fair bit of technical debt and lacks the safety net of tests.
You can’t improve the legacy codebase overnight, but you can take gradual steps to improve it:
1. Test it
One way to understand the code is to create characterization tests and unit tests.
This will help you understand what the code actually does. And it will reveal any potentially problematic areas. Once you understand the code, you can make changes with greater confidence.
2. Review Documentation
Reviewing documentation of the original requirements will help you understand it. Without this information, you could accidentally make changes that introduce undesirable behavior.
3. Rewrite code when necessary
It takes too much time, while it is not always necessary. Do it only when there is no other option.
4. Refactor it
It’s better to refactor the legacy codebase than rewrite it. And, it’s best to do it gradually.
But remember, that refactor code that has unit tests, so you know what you have. And
test after refactoring to make sure you didn’t break anything. Have a safety net – continuous integration, so you can revert to a previous build.
5. Make changes in different review cycles
Don’t make too many changes at once. It’s a bad idea to refactor in the same review cycle as functional changes.
6. Keep new code clean
Make sure that the code you add is clean using best practices and DRY principle.
Legacy Code Books we recommend you to read
If you believe your code is “Legacy Code”, then I recommend you to read these books, which will definitely help you in your daily life:
1. “Working Effectively With Legacy Code” by Michael C. Feathers, which contains some good examples of how to make changes to the codebase.
2. “Refactoring: Improving the Design of Existing Code” by Martin Fowler. This book offers many tips for effectively refactoring code.
Actually, our Principal Engineer – Alvaro Garcia gives his Legacy Code Course in Apium Academy, if you are interested, let us know!