Legacy code is sort of like your house's crawlspace.
It tends to be a repository for things that mattered to you in days past or items needed for special occasions. The code sits there, largely unnoticed. Until such time as an odd change or a production bug causes you to dig it up, dust it off, and revisit it.
By and large, forgetting legacy code is considered an acceptable state of affairs in our industry.
Part of the reason for this is that many folks who manage software development think of constructing software like constructing a house. Once you've built it, it's done. Why go back and revisit it unless some kind of problem crops up?
Unfortunately, building software isn't much like building a house.
When you build software, you stack the new atop the old and everything comes along for the ride. Sure, there may be the occasional new module that stands all by itself or plugs in with the rest, but that's the exception. The new code interacts with the old stuff, calling into it, relying on it, and running beside it in production.
If housing construction worked this way, a short circuit in the house across the street might cause your shower to stop working. If this was the case, you wouldn’t listen to someone telling you that the neighbor’s wiring was none of your business.
This is the approach required with legacy code in your code base. The fact that someone typed it out years ago doesn't mean that it doesn't have a very real, current impact on your team every time you deploy your code. Because of this, it behooves you to review it occasionally, when time permits.
Let's examine four specific benefits of auditing your legacy code.
Have you ever written a while loop that you knew wasn't very efficient? Of course, it's not that you were being lazy. Rather, you knew it wasn't worth optimizing because you'd only ever loop 10 times or so, even in the worst case scenario.
Now, imagine that you made this decision back in 2009. Or imagine that someone else did. Is it possible that you might revisit this code only to discover that your "only ever 10 times" assumption is woefully obsolete, and that bit of processing is now happening 10 thousand times?
Over the long haul, even sub-optimal situations like this simply become part of your application's performance profile, and nobody is necessarily screaming about them. But a quick review of this code allows you to realize some pretty serious performance gains, especially if there's a comment at the top that says, "We should revisit this if we ever loop through here more than 10 times."
A lot of old code bases — especially in more relaxed shops — take on the feel of archaeological digs, where the epochs of code are peeled back in discrete layers. "This part of the code base was from 2007, when someone discovered the model-view-presenter pattern." "Take a look here — this is the 2010 section of the code base when they got really into using aspect oriented programming."
If you have a code base like this, it's really hard for new team members to infer expected practice from their surroundings. Long-tenured team members know the old layers of code by familiarity. But for anyone else, it's like walking through a house where each room is a different color and trying to figure out what color the owner wants to paint the kitchen.
Reviewing the code periodically will help mute this phenomenon through pure ‘observer effect.’ But, it can also help you identify the most confusing and disparate examples and take tactical opportunities to get consistent.
3. Defect Prevention
As a code base sprawls over the years and developers come and go, there's a natural tendency for wheels to be reinvented.
This is understandable. Sooner or later there's just too much code that you can't possibly have a handle on what all of it does. But the result is well known enough that it is mentioned on a list of code smells: "oddball solution."
Having poorly duplicated code strewn throughout your code base is a recipe for unpredictable defects. A change in requirements might result in a deliberate fix in one version of the solution, with others limping along, quietly being wrong for months.
Periodic reviews of old code will tend to mitigate this, and also provide understanding of risk spots.
When talking about legacy code, there's always an implied vibe that everyone laboring away in the past was doing sloppy, incorrect things. It's just a natural offshoot of the human tendency to blame all problems in the group on people that have departed. But maybe, just maybe, it's possible that someone writing code a while ago did something right or even worth emulating.
The reasons for reviewing legacy code aren't limited to only negatives. Taking a look back through old code from time to time has the potential to reveal good techniques, effective patterns, and general practices worth emulating. You might actually learn something from the people who have been at this a while.
Every bit helps
I'd like to be clear here. I am not recommending that you bring the business surrounding your team to its knees while you spend weeks pouring through every nook and cranny of your team's source control history.
What I'm advocating for is that you take a bit of time every now and then to take stock of your team's older, less frequently visited, code. You might find opportunities to improve your application's behavior or to even standardize your code. You might catch defects before anyone notices and learn a thing or two that you can use in your own code.
But even if none of that happens on any given review, you'll understand your group's code better than you did. You'll understand what you have in storage.
Interested in learning more about how to handle legacy code? Check out the first two posts in this series: The Healthy Fear Associated With Legacy Code and How Do You Know When To Touch Legacy Code?