How to make debugging other people’s legacy code suck less
It’s 2 AM on a Saturday and you get a call. You bolt out of bed and pick up the phone knowing that something terrible has happened. No, your dog didn’t get kidnapped and you don’t need to use your particular set of skills and parental rage to bring its captors to justice. Instead, your weekend slumber has been interrupted because there’s a bug in a system and you have to fix it.
Whether you’re debugging legacy code early on a Saturday or in the middle of the workweek it sucks. Nearly every system that you work on will have code that was written by someone else. In some cases, that code may have been written more than 10 years ago.
When some old code creates a bug what should your first line of defense be? Surprisingly it’s not a methodology or a tool. It’s a personality trait. Let me explain.
Empathy: the first line of defense against legacy code debugging
“Programming today is a race between software engineers striving to build bigger and better idiot-proof programs, and the Universe trying to produce bigger and better idiots. So far, the Universe is winning”. – Rick Cook
After dealing with many bugs, I know how easy it is to get frustrated. But, the real key to making headway is showing empathy toward whoever wrote the code in the first place. This breaks you out of fight or flight thinking and helps you approach the problem logically. Use these questions to develop empathy for your fellow developers:
- What was the last developer trying to achieve?
- What was their mindset for achieving this goal?
- What pitfalls may they have inadvertently run into and how could they have dealt with them?
- How did the challenges at that point in time affect their thinking?
These questions will keep you open-minded and help you understand the landscape faster. Most importantly, they help you identify the mindsets of those who wrote the legacy code. The closer you get to their thinking, the better you walk in their shoes, the more likely you’ll be to understand their intentions and the strengths and weaknesses of their code/design. Understandings that will speed up your debugging process.
Applying empathy to your debugging process
Think of empathy as your prep work. It gets you in the mindset to understand other people’s mindsets. Now you need to apply it to a process.
Here’s what I’ve seen to be the most critical steps in the process of debugging legacy code.
- No man is an island. Get the right information handoff. Before you can debug anything, you need to understand what it does and how it does it. More often than not, there will still be someone at the company who understands the code, even if they didn’t write it. Your goal is to gather information, understand their mindset, and learn the history of that piece of software. This will help you see things from their perspective as you work through the documentation and code. While it’s easy to think “I can figure it out on my own,” sharing mindsets with other people often creates faster and better results.
- No (micro)service is an island. Understand the architecture around the system. The component you’re working on will rarely be standalone, and you’ll rarely be able to fully understand it and how it affects the system without looking at the bigger picture. To understand the architecture, ask yourself: What are the requirements for the system? What top-level concepts are part of this system?
- Read before you run. Start with a static review. Read through the code and recreate the process in your mind. Use empathy and the information you’ve gathered to understand why things were done a certain way and where errors could exist. It can be tempting to jump right in guns blazing and just run the code to see where it fails. While you usually won’t miss key information for debugging, you would be missing the right context and mindset to interpret this information.
- Take it for a run. Continue with a dynamic review. By running the software, especially with the help of a debugger, you can observe how it behaves and review its log lines. You’ll also be able to test out data flows, which is very important for systems that rely on other components. Enabling you to see the bigger picture from the details.
Into the onion, skills to keep you at the top of your game
“Debugging is like an onion. There are multiple layers to it, and the more you peel them back, the more likely you’re going to start crying at inappropriate times.” – @iamdevloper
Software as a whole is going through changes. Systems are more scaled up, distributed, and asynchronous. This creates opportunities for friction, especially in older software that contains legacy code which is more likely to break in this modern framework. And it makes it more difficult for you to determine where the bugs are. These changes also mean that debugging processes are getting more complicated.
To keep up, you need to keep developing your skills as a developer. There are three specific skills that I advise developers to cultivate so that they can be at the top of their game.
First, the most critical skill is being able to work with and shift between mindsets quickly. As a developer, you need to quickly shift between the mindsets behind every one of the many components that make up a system. This is extremely hard to do (we’re humans and have limited brainpower), but when you achieve it, you’ll be able to debug more quickly in high-pressure situations.
Second, you need to use your time more wisely than ever. The more encapsulated, complex, or data-driven a solution is, the more difficult it will be to see the truth of how it functions. One client told us that just getting set up for preliminary debugging is laborious and takes at least an hour. When you understand how to prioritize your testing, you’ll be able to get in the zone and get the answers you need before it’s too late.
Third, you need to master the art of data collection and debugging without breaking stuff. Use non-breaking breakpoints and observability tools to understand as much as you can, so you can minimize logging and redeployment efforts.
Killing bugs with kindness (and empathy)
Debugging other people’s legacy code will always suck. But, you don’t have to feel helpless while the bug holds your systems captive. Build up your empathy, learn to use mindsets to your advantage, and make good use of your debugging time. With this particular set of skills, you will find the bug, you will kill it, and you might even get a sequel.