Debugging is a drag. I think we can all agree that working on new code is generally more fun and interesting than debugging or maintaining existing code. But the fact is that much of our time is spent doing the latter. When estimating time required a project or feature, it is practically impossible to predict the time required for debugging.
Estimating development time, while still not simple, is much more approachable. So it makes sense to spend as little time debugging as possible.
The first step is to figure out how to reliably reproduce the problem. This is typically easier to do during development than trying to figure out an issue in production, which can be a separate process altogether.
Don’t Create Bugs in the First Place
This probably seems obvious. Nobody wants to write buggy software, but it may not always be clear how to go about that. There are a number of strategies that can help, but three I have found most useful are:
Write clean code Unit test Refactor mercilessly
These three principles are related to one another. Writing clean code lends itself to unit testing because things are broken down into logical units. Unit testing makes refactoring and other code changes easier since it provides a high level of reassurance that nothing has broken. And refactoring helps to maintain the clean state of the code.
Write A(nother) Unit Test
This won’t work for all problems, but if the issue happens under very specific conditions, a unit test is faster to run and may provide an easy way to check your solution as you debug. When you’re finished, it will have the added benefit of protecting against regressions.
Find a Way to Visualize the Problem
It’s much easier for me to reason about something if I can see it, or at least some representation of it. This might mean drawing a diagram of how I expect the system to work and then reading through the code to see how it matches up.
Or, it might mean literally visualizing the problem by adding drawing commands. Whether it’s due to poor documentation, implementation quirks, or phases of the moon, I often have some difficulty getting UI code right the first time. Sometimes, it’s enough to insert some quick-and-dirty logging statements to see the actual size or position of a UI element, but often, it would be much more useful to draw a line or box or something to visualize these measurements. (The drawback is that this takes more time than the log statements.)
Talk It Out
If you’re fortunate enough to have a pair who is also very familiar with the code you’ve been working on, they may know how to fix it already. In any case, simply talking about the problem may force you to think it about it in a new way (so talking to a rubber duck may actually be just as effective as talking to a person).
Understand the Cause
It’s very easy to be tempted to implement the first fix that appears to work. However, if you don’t understand why it worked, you may end up introducing new issues. Also, whatever special case is now handling the bug will likely get in the way when the code is refactored.
Sometimes, time pressure or other factors require a shot-in-the-dark solution. Just realize that your codebase will be healthier in the long run if you’re able to understand the root cause of the issue.
Don’t Get Frustrated
This is probably the hardest one for me, especially if I’ve been working on the same bug for hours and not making any progress. It’s easy to think, “This doesn’t make any sense!” and just wish the problem away, but this sort of thinking can also cause me to make bad assumptions or neglect checking simple things. Usually, this means I need to walk away from the problem for a while, either by actually leaving my computer for a bit, or just working on something else.
I definitely still find myself stymied by bugs that are difficult and time-consuming to root out. However, when I think back to a time before I focused on writing clean code, thorough automated testing, and refactoring, I realize that I do spend much less time debugging than I used to. If you have any additional tips that have helped you cut down on debugging time, please feel free to share.