How I Approach Inherited Code
When I started at BHW, one of my first tasks was to take over an existing codebase that was originally written by one of our client’s in-house developers. Over the past 4 years, I have become an expert on reading this nearly incomprehensible code. This code is so bad that about once a month I will find a code snippet that I jokingly send around the office. I am truly amazed that this code has been used for over a decade and that its bits have helped process tens of millions of dollars over that period. The point of this story is not to complain about or make fun of this previous developer, but is to show that bad code exists and can run successful applications.
Many developers see such code and hastly declare that it has to be rewritten. However, that is often unrealistic or impossible. The question then becomes, how do you approach bad code? This article will discuss my approach when working with existing code and will explore several key things I consider before writing a single
Understand your Tech Stack
Prior to looking for the exact lines of code you need to change, take a high-level look at the project. What languages are used? Is there a package manager? How is the code organized? What are the code's layers and interfaces? When working on a new project, one of the first things I do is find a simple page from the project to follow from webpage to database and back to webpage. Find the HTML, see where the styles are set, find where the request is received by the server, see how that server-side code accesses the database, and see how it is returned to the client. Then, see if the loaded page makes any additional server requests and follow those as well.
As you get more familiar with the solution, try to see if the way code has been written has changed over time. This is important when working with code that has changed stewardship over a long period of time. The next point helps understand this further.
Review Recent Commits
Hopefully you have access to source control with historical commit messages. If this is not the case, I am very sorry, but please continue reading. Assuming you do have this access, take a look at some recent commits. Start with the messages to see what the intent of the change was. Then look to see what files they modified. Often, you will find a change that is similar to your task. Knowing what sort of files you will have to update to complete your task can be extremely helpful.
Another thing to look for is code style. Code that is styled consistently is easier to read and understand. Take some time and see how the codebase looks and do your best to make your commits consistent. However, this does not mean you should write sloppy code if the existing code styling is poor or that you should restyle everything to match your preferences. This code could very well outlive you, so just leave it better than you found it.
If you are luckier still and are able to speak with or have worked with the other developers, find commits from the developer you most respect and see how they work with this codebase. And of course, ASK QUESTIONS as needed.
Understand your technical limitations.
Time for a quick self-deprecating anecdote. When I first started working on the project I mentioned in the introduction, I was presented with a somewhat involved change. I did a bit of Googling and found a nice NuGet package that would be a big help. I added the package to the project, included the package in my file, and then got to coding. About a week later, it came time to deploy my changes to production. I transferred over my updated files, loaded up the website, and the site wouldn't load. 500s. I quickly revert the deployment and locate the error logs. It turns out my awesome NuGet package requires a newer version of .Net. More fun yet, that version of .Net can’t be installed on this particular “retro” server.
The lesson learned is that you have to understand your compatibility limitations, including those in production. It is important to remember that your development machine (and even staging machine!) can be newer than the server the production app runs on. It is never safe to assume your environments will be the same. They almost never are!
Read all the relevant code.
Unless you are making a simple copy or color change, I strongly recommend reading more than the lines you plan on editing. Understand the context of the file. I usually start by examining the included files and packages and then read the function headers of the file I plan on working in. At least a handful of times, I have skipped this step and written a function, only to realize another function already performed the same task.
Another reason you want to review the code is to remove newly killed code. If you remove the usage of a class, function, or file, check to see if it is used elsewhere. If it is not, consider deleting it. Having dead code lessens the solutions maintainability. Furthermore, deleting code is significantly more satisfying than writing it. As long as you have source control in place, don’t be afraid to remove unused code.
Deciding when to introduce new technologies.
When working with older systems, it is very likely that a newer technology could be helpful when adding new features. But, there are many things you should consider before doing so. Here are some things to think about:
How does this change affect the project’s learning curve?
Is your new technology’s usage isolated?
If the component you are updating is used widely in a project and is not properly isolated or interfaced, be wary of making a fundamental change. It might be the right thing to do but will likely require some regression testing and careful planning. The last thing you want to do is remove something only to find that you pulled a strand that is holding everything together.
Will your new technology help make other changes easier?
This is where understanding a project’s roadmap is invaluable. If you know you will have to build several new pages of a certain type and they would all be made better or easier with this new technology, then putting in a bit of extra effort to lay a new solid framework could be a great idea.
Every time you commit code, you are either improving or degrading a codebase. Bad code can be copied and extended. Or it can identified, contained, and with time, replaced. There are many things that can anchor a solution in terms of available technologies and frameworks, but even within that limiting context, code of wildly different qualities can be written. Take the time to understand the existing code and plan your approach. By following this guide, hopefully you are able to be a developer who leaves every codebase better than they found it.