Debugging is a fundamental skill in the arsenal of any engineer. Mistakes happen, and bugs are inevitable, but a skilled debugger can catch a bug early and find an elegant solution.
It’s tempting to think of debugging as solving a problem. You’re fixing it, so it doesn’t come up again. This is not true. You’re not at the point of a solution. Right now, you’re investigating. You’re trying to work out the problem before committing to a solution.
“Debugging is like being the detective in a crime movie where you are also the murderer.” – Filipe Fortes
So let’s get into it. Here are five debugging techniques that will supercharge your debugging skills and give you insight into even the most complex problems.
A typical pattern that many engineers do is rely heavily on their minds. This pattern is good, but it’s not optimal. Your IDE comes packed with tools that will help you analyze a problem, like the software debugger tool that will help you to step through a coding problem, line by line. The important thing about the software debugger tool is that it can also tell you the value of every single variable, how many times a loop is iterated, whether an if-statement is entered, and more. When you’re debugging in programming, this tool is indispensable.
All the IDE can do is surface as much information as possible. It’s up to you to do two things. The first is to set up your IDE best for your working style. Some people like to have every window and dial open to see all the metrics as they work. Others prefer a clean, minimalistic working space. The second is to use the information put in front of you effectively. Your IDE gives you everything – it’s up to you to filter that down into insights. When you get the tooling right, it’s time to think more methodically about the problem in front of you.
Debugging is fundamentally a testing activity. You’re poking your creation to truly understand how it behaves and, most importantly, why it behaves that way. When you’re testing, you have to make a series of assumptions. It’s a natural part of the testing process, but sometimes, those assumptions can be incorrect.
Our assumptions can be so fundamental that we overlook them, but it’s valuable to be thoroughly conversant with the assumptions you’re making for complex issues.
Behavior-driven development (BDD) is a powerful technique for surfacing assumptions, describing expected behavior, and flushing out any inconsistent thinking you have. It is most commonly utilized in the software design phase, but it’s equally valuable when trying to understand existing software.
Try this workflow.
Mastering your use of language to surface your assumptions is one of the vital debugging techniques, but sometimes it’s not just about your language – it’s about your thinking. Sometimes you need someone, or namely something, to talk to.
Sometimes, it’s a good idea to completely abandon your sanity and talk to inanimate objects when you’re stuck. This may sound a little wild, but it has a long and convincing pedigree in software engineering. The beauty of speaking to a rubber duck is that the conversation is agonizingly one-sided, forcing you to articulate every detail.
Speaking about a problem often helps you find inconsistencies or assumptions in your thinking. These assumptions can lead to new test cases that will help you focus on the issue. There are dozens of senior engineers who swear by rubber duck debugging.
You could also have a conversation with a colleague. Asking for help is not a sign of weakness; it’s the sign of an efficient, collaborative engineer. If there is an available colleague nearby, have a chat! But sometimes, there’s nothing better than the vacant, plastic stare of a rubber duck.
Conversing is an essential method for understanding the problem, but sometimes the problem is so complicated that you need to take a different tactic. If the code is complex or difficult to understand, then it’s time to try and change the behavior to test your understanding.
Okay, so you’ve tried a bunch of stuff, and it’s not working how you expect. You don’t know why and every input you’ve been attempting to give the code just isn’t making any sense. Your next step is to change the code a little. Here is what you do:
This is a brilliant way of understanding why each function is in place for very complicated algorithms. Change a little, and investigate why it doesn’t match your expectations. Only now, you’re not investigating the whole algorithm; you’re just looking at one little step. When debugging in programming and the code is complex, making micro-changes and predicting their outcome is an excellent way of practically assessing the code’s behavior and can break up those long, monotonous staring competitions that engineers often find themselves in.
However, if all else fails, there is one age-old debugging technique aiding engineers since we first started building things.
Newton didn’t discover gravity when an apple hit him on the head, but the myth has a sensible moral. Sometimes, ideas just hit you on the head, and no amount of brute force thinking will speed up that discovery. When you focus for a long time, the assumptions you make begin to pile up. It can become difficult to see through tunnel vision.
To get away from this, take yourself away from the problem for 10 minutes. Make a coffee, go for a walk, go to the gym – just do something that lets your mind work on the problem in the background. Your mind has a startling capacity for passive problem solving, and it is one of the most underutilized debugging skills.
Debugging can be one of the most rewarding engineering experiences, that warm sensation of enlightenment when you finally discover the actual workings of your solution is hard to beat. So the next time you run into a problem, don’t panic – just remember to be methodical, focused, and relaxed. You’ve got this.