Legacy code: Why it happens and how to handle it
Published: 2023-03-01 14:33:22

#Legacy or just old?
Ask five developers for a definition of legacy code, and you’ll get six different answers. We all have different opinions on what constitutes legacy code, but most can agree on this: it's old code still in use, and it's hard to work with.

>We could spend a lot more time trying to define it, but smarter people than me have done that more eloquently than I could, so I'll link some good articles at the end for further reading. They also go into more depth than me, so I recommend checking them out after this.

However you want to define it, we all know it when we see it, and nobody likes working on legacy code.

#Why does code become legacy?
So.. If everyone can recognize it, and nobody likes working on it, why does it happen? Well, a few things: feature bloat, tech debt, time and lack of testing are the main culprits. So, taking them one at a time...

###Time
This is kind of the big one of the group that often leads directly or indirectly to the other points. Legacy code is also old code which could mean a few things in my experience:
* Current fundamentals like Entity Framework or web frameworks were maybe not available or widely adopted at the time, which resulted in custom-made or outdated/deprecated solutions we have to adapt to and basically learn from scratch.
* The original developers were likely used to working in a totally different paradigm which means it can look either odd or illogical to our modern sensibilities.
* Inertia - The longer a product is in use the harder it becomes to make meaningfully large changes, making it easier to focus on things in the short-term like:
 
###Just one more feature
When a product is successful for many years, it will inevitably gain more and more features along the road because features drive sales/profits/etc. 
This means that the older the product, the more stacked (bloated) with features it might become. This is great in the short term because each feature makes the product more marketable, but if not planned correctly this will make the codebase more and more unmanageable.  

###Tech debt
Another thing that will often happen over time is tech debt. The reality of creating any kind of product is the need to drive sales which means features like I mentioned above, but this and tight deadlines will often mean neglecting what doesn't directly drive sales: maintenance. 
On a vehicle, this means changing the oil, checking the tires or the like, but for a codebase this means refactoring, updating to newer versions, actually going back over the quick fixes and to-dos that will accumulate over time and so on. All of these things don't affect profitability in a noticeable way in the short term, but in the long run it is what makes a codebase become unmaintainable and eventually legacy.

###Lack of tests
We know we should all write more and better tests (check out [this article](https://dev.to/itminds/writing-good-tests-part-1-what-makes-a-test-bad-4gfd) on writing good tests by one of my colleagues), but often it's something we'll postpone for some other day. When lack of testing becomes a year's long worth of lack, it can be hard to know what breaks when we have to make changes to the code.



#So.. How do we handle it?
I am by no means an expert in this subject, but I will give my two cents on what I have experienced to be effective and necessary when working with legacy code and especially when you're coming in from outside as a consultant or new hire.

###Long or short term
My perspective is going to be influenced by my position as a consultant and is therefore on a limited scope and timeframe, but if a codebase has reached the legacy stage, it will usually be necessary in the long term to eventually rewrite it using best practices from scratch. 

###Communication and estimation
Working on legacy code is difficult, but one of the things I have found most difficult when working on legacy code is estimation which is sometimes more of an art than a science - and with legacy code it is always more challenging. 
The answer to this is cliché for a reason: communication. Be open and up front about your estimates, and don't be afraid to readjust when you run into problems.

###Leave it better than you found it
When adding functionality to a class that is already 8000 lines long and when the if-statement is already nested several levels beyond what is comfortable, it's tempting to think *oh well, what's another few lines*. 
But, that's just making the problem slightly worse for next time / the next developer. You should always try to leave it slightly better than you found it - if there isn't enough time to do a proper refactor of the class/whatever you're working in, you should at least not make it worse.

###Code style
This may mostly be relevant for developers in a consultant role like myself, but I'm including it still because I think it's important.
When working on - and especially adding to - legacy code, it's tempting to rewrite older code completely in a much more efficient style. And I'm not saying you shouldn't do this, but I think it's very important to keep in mind who else will be working on the code. What I mean is that you should be looking for a good middle ground between something you can be proud of doing and something that isn't too foreign to developers used to working in older code. 
You can either try to document and comment your code in such a sufficient manner that the next developer knows how to handle your code, or you can try to adapt to the existing code style. This again comes down to the above point of communication: Talk to your lead/fellow developers etc., and figure out the best solution.

In the end, it doesn't matter how clever your improvements are, as they are useless if the next developer to look at it won't know what they're looking at. Like making a speech, you have to know your audience and adjust your choice of words accordingly.


###To sum up
* Legacy status is almost inevitable for any product over time unless it is actively avoided and planned for.
* Communication is key - legacy is difficult to work with and estimating tasks for legacy doubly so. Make sure to communicate any problems, questions or ideas you have along the way.
* Don't take the easy way out - try to leave it better than you found it, otherwise you're just making the problem worse for the next person.
* The code you add or change will have to be understood and expanded upon by other developers - adjust accordingly.

Below are a few good articles both defining legacy code and going more in depth with handling legacy code - among other things the best ways to implement testing.

* [Key Points of working effectively with legacy code](https://understandlegacycode.com/blog/key-points-of-working-effectively-with-legacy-code/)

* [Everything You Need to Know About Legacy Code](https://enkonix.com/blog/legacy-code/)

* [Podcast (transcript) with Michael Feathers on legacy code](https://www.infoq.com/podcasts/working-effectively-legacy-code/)