Stories about Software


So, You’ve Inherited a Legacy Codebase

Editorial Note: I originally wrote this post for the SubMain blog.  You can check out the original here, at their site.  While you’re there, have a look around at some of the other posts and sign up for the feed.

During my younger days, I worked for a company that made a habit of strategic acquisition.  They didn’t participate in Time Warner style mergers, but periodically they would purchase a smaller competitor or a related product.  And on more than one occasion, I inherited the lead role for the assimilating software from one of these organizations.  Lucky me, right?

If I think in terms of how to describe this to someone, a plumbing analogy comes to mind.  Over the years, I have learned enough about plumbing to handle most tasks myself.  And this has exposed me to the irony of discovering a small leak in a fitting plugged by grit or debris.  I find this ironic because two wrongs make a right.  A dirty, leaky fitting reaches sub-optimal equilibrium and you spring a leak when you clean it.

Legacy codebases have this issue as well.  You inherit some acquired codebase, fix a tiny bug, and suddenly the defect flood gates open.  And then you realize the perilousness of your situation.

While you might not have come by it in the same way that I did, I imagine you can relate.  At some point or another, just about every developer has been thrust into supporting some creaky codebase.  How should you handle this?

Put Your Outrage in Check

First, take some deep breaths.  Seriously, I mean it.  As software developers, we seem to hate code written by others.  In fact, we seem to hate our own code if we wrote it more than a few months ago.  So when you see the legacy codebase for the first time, you will feel a natural bias toward disgust.

But don’t indulge it.  Don’t sit there cursing the people that wrote the code, and don’t take screenshots to send to the Daily WTF.  Not only will it do you no good, but I’d go so far as to say that this is actively counterproductive.  Deciding that the code offers nothing worth salvaging makes you less inclined to try to understand it.

The people that wrote this code dealt with older languages, older tooling, older frameworks, and generally less knowledge than we have today.  And besides, you don’t know what constraints they faced.  Perhaps bosses heaped delivery pressure on them like crazy.  Perhaps someone forced them to convert to writing in a new, unfamiliar language.  Whatever the case may be, you simply didn’t walk in their shoes.  So take a breath, assume they did their best, and try to understand what you have under the hood.

Get a Visualization of the Architecture

Once you’ve settled in mentally for this responsibility, seek understanding quickly.  You won’t achieve this by cracking open the code and looking through random source files.  But, beyond that, you also won’t achieve it by looking at their architecture documents or folder structures.  Reality gets out of sync with intention, and those things start to lie.  You need to see the big picture, but in a way that lines up with reality.

Look for tools that map dependencies and can generate a visual of the codebase.  Plenty of these tools exist for you and can automate visual depictions.  Find one and employ it.  This will tell you whether the architecture resembles the neat diagram given to you or not.  And, more importantly, it will get you to a broad understanding much more quickly.


Once you have the picture you need of the codebase and the right frame of mind, you can start doing things to it.  And the first thing you should do is to start writing characterization tests.

If you have not heard of them before, characterization tests have the purpose of, well, characterizing the codebase.  You don’t worry about correct or incorrect behaviors.  Instead, you accept at face value what the code does, and document those behaviors with tests.  You do this because you want to get a safety net in place that tells you when your changes affect inputs and outputs.

As this XKCD cartoon ably demonstrates, someone will come to depend on the application’s production behavior, however problematic.  So with legacy code, you cannot simply decide to improve a behavior and assume your users will thank you.  You need to exercise caution.

But characterization tests do more than just provide a safety net.  As an exercise, they help you develop a deeper understanding of the codebase.  If the architectural visualization gives you a skeleton understanding, this starts to put meat on the bones.

Isolate Problems

With a reliable safety net in place, you can begin making strategic changes to the production code beyond simple break/fix.  I recommend that you start by finding and isolating problematic chunks of code.  In essence, this means identifying sources of technical debt and looking to improve, gradually.

This can mean pockets of global state or extreme complexity that make for risky change.  But it might also mean dependencies on outdated libraries, frameworks, or APIs.  In order to extricate yourself from such messes, you must start to isolate them from business logic and important plumbing code.  Once you have it isolated, fixes will come more easily.

Evolve Toward Modernity

Once you’ve isolated problematic areas and archaic dependencies, it certainly seems logical to subsequently eliminate them.  And, I suggest you do just that as a general rule.  Of course, sometimes isolating them gives you enough of a win since it helps you mitigate risk.  But I would consider this the exception and not the rule.  You want to remove problem areas.

I do not say this idly nor do I say it because I have some kind of early adopter drive for the latest and greatest.  Rather, being stuck with old tooling and infrastructure prevents you from taking advantage of modern efficiencies and gains.  When some old library prevents you from upgrading to a more modern language verison, you wind up writing more, less efficient code.  Being stuck in the past will cost you money.

The Fate of the Codebase

As you get comfortable and take ownership of the legacy codebase, never stop contemplating its fate.  Clearly, in the beginning, someone decided that the application’s value outweighed its liability factor, but that may not always continue to be true.  Keep your finger on the pulse of the codebase, while considering options like migration, retirement, evolution, and major rework.

And, finally, remember that taking over a legacy codebase need not be onerous.  As initially shocked as I found myself with the state of some of those acquisitions, some of them turned into rewarding projects for me.  You can derive a certain satisfaction from taking over a chaotic situation and gradually steering it toward sanity.  So if you find yourself thrown into this situation, smile, roll up your sleeves, own it, and make the best of it.

  • Nathan Armstrong

    The nasty bit is that – as a consultant – oftentimes I’ve seen us choose poor scope in our SOWs, and end up with a client that gives us legacy code and then expects us to operate on it without changing it. That’s when I’ll start getting vitriolic at the codebase – when I’m stuck working in it without being able to improve it, much less characterize it well.

    • Definitely understand the sentiment. Do the clients hand you an NDA and give you a peek at the codebase ahead of signing the SOW?

      • Nathan Armstrong

        Can’t say our leadership is mature enough to ask for things like that, though maybe it’s something to discuss. I’d love to be able to examine those types of things before coming on board to a new client – it reveals so much about them.

        • Ah, I feel your pain. Is it staff augmentation kind of work?

          • Nathan Armstrong

            It becomes that more often than not.

    • Jim L

      I assume that the client doesn’t expect you to change the functioning of the application. But, if he hired you as his software consultant, you must do your best to fix the “technical debt” or code and design smells that exist in the product. It will not be an easy or quick task to do, but will make for better and quicker maintenance when the customer wants to make additions.

      Also, as part of you working on the codebase, you must inform the client that improvements to the code and design are necessary to make it possible to make the requested changes more effectively and quickly. Also, to allow the software to accommodate future changes.

      If we remember the Y2K debacle, there was probably the same mentality. “If it ain’t broke, don’t fix it.” Sometimes, it seems that the business of corporate software production is like the business of used cars. It doesn’t matter what it’s like under the hood, it only needs to run.

      • Nathan Armstrong

        I am in total agreement; and by our own internal perspective, we ought to be taking steps like that. Too often that ‘consulting’ relationship dissolves into a ‘feet on the ground’ relationship by the time we actually get to work.

  • FortyEightK

    A few years ago I inherited an ASP.NET code base. Fine, you might think, apart from one thing: Every page was built from a single Literal and the code-behind built the HTML to chuck into it. No .NET controls at all and the HTML string was built by calling dozens of functions, not to mention that JavaScript was created on the fly too in the same way. Took about two weeks to decide that the project was uninheritable…

    • nightmare!

    • Wow, that’s… quite a scheme. It’d be really interesting to know how they came to decide that was the way to go. I often think that looking at legacy projects provides some interesting anthropology kinds of opportunities.

  • I inherited a classic asp application with a mix of .net 2.0 in the late 2000’s. This huge application was vital for the client who were making thousands of CRUD operations daily, 24 hours a day. I was tasked to stop the bleeding for this application, patch it up with classic asp and .net.

    Management did not want to rebuild so I was tasked to do this for years while also working on other new projects using new technologies. That dinosaur application sucked the life out of me.

    After I left that position, I periodically check in with my friends and colleagues who I worked with at that time. The last time I asked about the soul snatcher application, I was told the client decided to quit using it and go back to excel sheets because it was causing too much headache and problems for them. The application collapsed and has hundreds of thousands of database records. All that data and no system to support it.

    Currently, I have joined a team with a large ASP.NET 3.5 webforms application that management has told me they want to convert to MVC.
    – Is it required that the application to use the MVC pattern/framework? Management said yes.
    – There will not be a conversion. It will be rebuilt as a new project.
    – Timeline/Phases
    – I’ll train the webforms developers on the team how to code using MVC5.
    – I’ll develop a plan and present it to management.

    Anyone who has experience in a similar situation, please share your thoughts and advice.

    • Jonathan Horvath

      I would suggest first moving all data access and business logic into separate projects. You might be surprised that in completing this task, there might be no need to convert to MVC. Even if you do decide to convert to MVC, it will be much easier task.

      Remove any dependency on WebForm server side session state. Store local persistent data on the client. I’ve seen many issues with server session state that are difficult to resolve.

      Finally, the latest version of Visual Studio allows to mix both WebForms and MVC in a single project. I would recommend working to migrate individual pages instead of rebuilding the solution from scratch. This will give the team an opportunity to learn MVC in a familiar code base.

    • Jonathan Horvath
    • At a quick glance, what I’d do is try quickly to convince management that Weforms and MVC are HUGELY different beasts, and that you’ll need to supplement your efforts to bring the team up to speed with some kind of training. Maybe that’s something like a week-long course, or maybe it’s a bunch of Pluralsight sessions or something.

      But Webforms is basically an illusion to trick converted desktop devs into thinking they’re still desktop devs. MVC is going to be a pretty different beast than they’re use to, and that’s going to lead to early growing pains.

  • David Brown

    Right, who would want to work with yucky legacy code when you could write a new system making similar hacks/mistakes directly resulting from your own hubris and ‘modernity’ in a rush to get something to market next month? First, read all the publications and blogs (making sure the author has the right beard growth), and use the most-hyped recent development environment/language (isn’t everything supposed to be in Haskell now?). Be sure and stick in lots of sloppy open source code you don’t even slightly comprehend that never gets updated… then as soon as you and your employers (who will have all moved on to new dynamic robot positions with other sinking ships) realize what a cluster has been created, get that resume out there and start all over again. Cuz that’s what savvy, hip developers do, it pays the rent on their second cubicle masquerading as an apartment in SOMA or Lake Union.
    The future is gonna be great.

    • Wow, I’m not really sure why/how this is a response to my post. But it definitely seems that you’re pretty angry at… someone. I hope you guys get it sorted.

  • Jonathan Horvath

    I handle legacy codebase a little differently.

    At first glance I notice that variables names are not meaningful. I see a variable named ‘sText’ that is reused throughout the method. It is called throughout the method. At the beginning it creates a log message, later it represents that status of an object. At this point I will start randomly shouting profanities like a person with Tourettes.

    I run into a class that is over 5000 lines long. It does everything, UI, business and data access. There are methods that are 100’s of lines and it is impossible to keep track of all the variables. I take my chair and throw it out the window.

    Standing at the desk, I realize that all the SQL queries are concatenation of strings. Since there is no central repository of data access routines, a tedious search for the SQL injection attacks is needed. I give up on the situation. There is only one thing left to do, pour gasoline on the computer and light it up with a match.

    My next comment will be from prison. Hahahaha

  • Michael K

    I don’t mind inheriting legacy code. I enjoy troubleshooting and tracing through the codebase to figure out how it all works and how it might be improved. If it’s particularly old code it brings a feeling of nostalgia as I am reminded of the way we used to do things.

    Plus, if I’m being honest, I’ve left some pretty ordinary code for others to inherit (is anybody ever happy with what they produce?), so I feel like it would be hypocritical to get annoyed at inheriting another person’s work.

    • Definitely a good point along the lines of “what goes around comes around.” And, that’s kind of where I was coming from in writing about the futility of getting worked up or assuming the people that wrote it were stupid. Most people writing code are smart and they make the best decisions they can in the context they make them in.

      I also don’t mind working with legacy code… provided I have discretion to set and manage expectations. In other words, it’s fine with me as long as people aren’t expecting surgery on long-abandoned modules to be turned around easily, quickly, and without mistakes. There’s definitely satisfaction to be had in evolving a codebase to a better state of affairs.

  • Diogo Oliveira

    Any concrete suggestions on tools to “visualize the architecture”? ( I am on a Java/Spring/Jquery/Bootstrap environment.) Thanks for the excellent article.

    • Running to go catch a plane, but real fast, you should give JArchitect a look: http://www.jarchitect.com/ That’s typically what I use for client assessments with Java codebases.

      • Diogo Oliveira

        Tks a lot! 🙂