Legacy code - This phrase gives most of us the shivers. We imagine legacy code as a messy, unreadable, complicated, written-with-old-technology-and-conventions code. We embrace the dreadful phrase "if it works - don't touch it". We try to avoid as much as possible touching this horrible thing called Legacy code.
|Smelly code: Picture taken from here|
What exactly is legacy code?
I tried to get an answer to this question. Is it a code written using old technology? A code written by somebody who doesn't work for the company anymore? A code that is very fragile or complicated?
Well, I guess all of the above are correct. But I believe code becomes legacy code the moment it is too intimidating to be changed. No matter what the reason is. If you wrote a new feature today, which took you a lot of mental energy and time, and tomorrow you'll be afraid to change it, then I've got news for you - you have a new-born-healthy-two-days-old legacy code. Congratulations!!!
As time passes, our code becomes harder and harder to understand and maintain. The developers who touch the code come-and go, functionality evolves which causes much more flows that serve an ever-growing demand of use-cases to appear, technologies change but each of them leaves its signature on the code-base.
Refactoring is our way, as engineers, to clean up the mess. Some people think that refactoring is a matter of aesthetics. While this may be true, aesthetics is merely a mean to an end - making the code more easily-maintainable and more readable to others. And when I say others, I also mean - the future you. You are the one who most likely will read this code in the foreseeable future, and I bet you prefer not to struggle with it.
Invest in your future
A lot of engineers fail to realize that refactoring is an investment. You invest in order to save much more later. Every minute that is spent trying to understand the code, is a minute wasted. If the code is read by different people, in different times, and each of them struggles to understand it because it's complicated - that's a lot of time wasted. If only one of them would break the habbit and invest in a one time effort for a better future - a lot of development time would be spared and could be invested in new features.
The fear factor
And still, people, mostly, but certainly not exclusively, juniors, afraid of refactoring. And I have to admit, there are good reasons to be afraid. How do you start to read this code? It's so complicated and full of variables and branches and try-catches and too many lines of-code and code-duplications.
It's also very intimidating to refactor when the person who wrote most parts of the code does not work with you anymore. Or maybe it was you who wrote it but you just can't remember why the hell you did it this way, but you're sure there was a reason.
Eliminating the fear factor
Luckily we have so many tools in our disposal that, when you think about it, completely reduce the amount of fear one should have when refactoring.
You can always revert back to the way things were before the change using the source control.
Tests are key for an efficient refactor process. You need to have tests that test the code. If you don't have tests (or don't have enough) - write tests before starting to refactor. Not only will it improve your confidence that you don't break anything while refactoring, but it will also help you to better understand the code.
Try to find ways to control and monitor your changes. For example, in Outbrain, we use feature flags in order to control new features. When we want to implement a new change, we create a flag that instructs the service on whether to use the new feature or not. This can be easily used for refactoring. And of course, it helps reverting in no-time. Just turn-off the feature and you're back to the way you were before the change. We also monitor a lot of metrics in every part of the flow. Usually, I can easily monitor the behaviour of a flow and see if anything changes. Even if you don't have advanced monitoring tools, you could utilize the log for monitoring the changes. Find your way to control and monitor the changes, this will greatly ease your fear.
Suspect comments. Comments are deceiving. They lead you to think that the code does something which it may or may not do. Computers don't understand comments, they just read the code. You should trust the code. If there are comments, use them as a guidance, but be very suspicious about them. Comments rot much faster than code. Also try to write code that is readable without comments when you refactor.
Take baby steps. Don't ever ever ever try to make too many changes at once. Always do one simple change and try to test it. You should allow yourself to be certain what was the exact change that caused problems. Don't make a project out of it. Refactoring is not a "all or nothing" deal. Every change you make, even the tiniest one, is blessed.
Boy scouts rule. Aside from taking baby steps, try to embrace the boy scouts rule - always leave the place cleaner than it was when you got there. While you work, do minor refactorings all the time. It's pretty easy and doesn't take a lot of time or effort. If everybody does that, the accumulating affect will create a much more robust code-base.
Invest only where necessary. If you see an ugly code which is very rarely touched, don't refactor it (aside from, maybe, very minor refactorings). It's not worth the effort. Invest in places to which you come back again and again.
Use refactoring to learn. You already need to change and extend a piece of code. While refactoring you make the code readable for yourself. You start with minor refactoring, and bit-by-bit you unravel the code and learn how to extend it as you go.
What's the worst that could happen?
When I started working at Outbrain, I had an on-boarding with Ori Lahav, Co-Founder of Outbrain. Ori told us to embrace the phrase "What's the worst that could happen?" and told us to not let fears limit our progress.
When you refactor you should think exactly that - what's the worst that could happen? If you're not touching an extremely sensitive component, then it's no biggy. If you do refactor a sensitive component, there are probably, and hopefully, enough tests around it, and monitoring, and backups, and failover mechanisms and so on. And, of course, you'll take baby-steps and test and monitor the change carefully. So go ahead and refactor. What's the worst that could happen??
My next post will include a video tutorial that shows how to refactor a piece of legacy-code using TDD. Hope you already can't wait!
Find me on Twitter: @AviEtzioni
More interesting posts from this blog: