Here’s a campfire horror story of legacy code that probably sounds at least somewhat familiar.
One day, your manager strolls by casually, sipping a cup of coffee, and drops a grenade in your lap. “Do you think we can add an extra field to the customer information form?” Sure, it may sound innocuous to an outsider, but you know better.
The customer information form is supported by something written almost a decade ago, by a developer long departed. Getting that data out of the database and onto the form prominently features a 60,000 line class called DataRepositoryManagerHelper and it also makes use of a gigantic XML file with odd spacing and no schema. Trying to add a field to that form casts you as Odysseus, navigating between Scylla and Charybdis. In fact, you’re pretty sure that author of the legacy code made it necessary for the assigned developer to cut off and sacrifice a finger to get it working.
Aware of all of this, you look at your manager with a mix of incredulity and horror, telling her that you’ll need at least 6 weeks to do this. Already swirling around your mind is the dilemma between refactoring strategically where you can and running exhaustive manual testing for every character of the source code and XML that you change. It’s now her turn to look incredulous and she says, “I’m just asking for a new field on one form.” You’ve told her before about this, and she’s clearly forgotten. You’re frustrated, but can you really blame her? After all, it does sound a little crazy.
Dealing with Legacy Code
I’ve talked in the past about legacy code as code that developers are afraid to touch (which I correlate closely with Michael Feathers’ definition as “code without tests”). If you accept this definition as axiomatic, there’s a critical implication here: legacy code creates a disconnect between the developers and everyone else.
As “everyone else” you see a form that needs a conceptually simple tweak. As a developer, you see a mythological monster that threatens to rip your digits from your body; you see something that inspires fear. And, while the bodily fear I’m referring to is an exaggeration, the visceral fear of the unknown and a lack of understanding is not. Management is asking you to do something it thinks of as simple, and your head is flooded with an overwhelming number of possibilities as to how this could all go quite wrong. And, worst of all, it’s really hard to explain this without it sounding as though you’re making excuses, being lazy, or being melodramatic.
If you want to understand how to manage expectations around the legacy code in your codebase, understanding this expectation mismatch is critical. From that starting point, let’s look at some things you can do to make your life easier.
As horrified as you might be at the prospect of having to sacrifice a finger to DataRepositoryManagerHelper, try to put yourself in your manager’s shoes. To do that, forget about code or the moment. Instead, imagine this analogous situation.
The pilot light on your furnace goes out, and you try to relight it without success. Needing the house heated, you call a service guy over to take a look. He spends a few minutes looking at the furnace and tells you that you’ll need to buy a new one.
“A new one!? All I called you over here to do was re-light the pilot!”
He shrugs uncomfortably and starts to explain that the thingamajig that controls the doowackey is covered with glork. As he talks, you feel the indignation building. He made a proclamation that defies common sense, and he’s justifying it with a bunch of indecipherable jargon, forcing your only choice to be taking his word for it and buying a new furnace from him. And, it’s not exactly that you think he’s trying to scam you, but… you just wish you had more information and weren’t being blindsided.
That is the position your manager is in as you tell her about the horrors of the DataRepositoryManagerHelper and why something that seems like it should be done tomorrow will take 6 weeks. She has her own goals and problems to solve, and you’ve just told her that she’s in trouble without helping her understand why.
Once you understand this, calm down a little, and see if you can explain it to her. Use analogies. See if you can offer her options or alternative solutions. Try to demonstrate something for her that will make the issue visible and understandable in her mind. Most importantly, imagine yourself dealing with the furnace guy, and do for her what you would want him to do for you.
Get Out in Front of It
Dealing with a manager on whom you’ve just laid some seriously bad news is ideal for no one. So, being empathetic and calm in the moment will help, but it can only do so much good. You need to have an ongoing strategy for creating visibility around legacy code.
I say this because, for management, legacy code is basically a landmine. It’s something they can’t see, and every now and then, it explodes in their face, creating huge problems in the form of production bugs or suddenly slipped deadlines. You need a strategy for planting flags in the ground that say, “here be dragons.”
NDepend offers some great capabilities for this, but you could even go low tech. What you should do is generate some kind of visual representation of the code and color code it from, say, green for awesome to red for landmine. Put this up on a build radiator or on the wall or something, and explain it to management. “As long as feature requests and bug fixes touch the yellow and green areas, we’re good. If it touches something red, it’s going to get ugly.” That will spur a discussion about what kinds of requests would touch only green and yellow and what kinds would touch red.
Now, management can see problems down the line. This serves two purposes: (1) they won’t be surprised and (2) they can start to think about remediation strategies.
Speaking of remediation strategies, I would advise not waiting for management to hand them down. You should be looking at ways to boy scout and chip away at the danger of legacy code bases. This is a war of attrition that you’ll have to fight on a daily or even hourly basis.
You can’t stop what you’re doing and “clean up” for weeks at a time. But you can make a difference. Start adding unit tests around the legacy code. Each time something sends you in there to touch it, refactor a little as long as you’re in there to reduce bad coupling and mitigate future risk. It’s unlikely that you’re going to make it awesome, but you can at least stop it from festering and getting worse.