The hard part of debugging software is finding a bug to fix. Actually fixing the bug is easy. However, as with many things in life, the fact that it’s easy doesn’t make it simple. Here are a few guidelines I learned while reading Code Complete on fixing bugs while staying sane.
1. Understand the problem before you fix it
The best way to make your life difficult and corrode the quality of your program is to fix problems without really understanding them. Before you fix a problem, make sure you understand it to the core.
Many times, I have caused more work for myself by devising a solution based on my incomplete understanding of the problem. Almost always, it will come to bite you back. It’s worth making that initial investment of time and energy to understand exactly the problem you are trying to solve.
2. Understand the surrounding codebase
If you understand the context of the problem, you are more likely to solve the problem completely, rather than only one aspect of it. Having an understanding of the program behavior and the surrounding context gives the programmer best possible chance to fix the bug and prevent it from happening it in the future.
I have been burned before by just focusing on the local behavior of the bug, learning the related code only as I needed to. Most of the time, I patched a symptom of the bug, and completely missed the root cause. As expected, the bug popped up again in future, causing more work and wasted efforts.
However, this doesn’t mean that you should try to understand a million line codebase completely before you attempt to fix a defect. It does suggest that you should understand at least the surrounding code in the vicinity of the bug.
3. Confirm your diagnosis
Before you rush to fix a defect, make sure that you’ve diagnosed the problem correctly. Reproduce the problem a couple of times to prove your assumptions and disprove competiing hypotheses.
4. Don’t fix the bug in a rush to get it out
Hurrying to fix a bug is one of the most time-ineffective things a programmer can do. It leads to rushed judgments, incomplete defect diagnosis, and incomplete corrections. Wishful thinking can lead you to see solutions where there are none. The pressure, often self-imposed, encourages haphazard trial-and-error solutions and the assumption that a solution works without verification that it does.
5. Fix the problem, not the symptom
The focus should be on fixing the underlying problem rather than patching a symptom of the problem. If I don’t thoroughly understand the problem, then I am not fixing the code, I am only fixing a symptom. This usually makes the code worse.
- The fixes won’t work most of the time.
- The code degrades over the long term and becomes unmaintainable.
- When code is special-cased to work around the errors, the special cases become the code’s most prominent feature.
6. If it ain’t broken, don’t fix it
This advice is contrary to the last advice of fixing it. Sometimes, we are tempted to fix/change the doe at random until it seems to work. Change the code only for good reason. As popular this practice is, it isn’t effective. You aren’t learning anything, but just goofing around.
7. Make one change at a time
When you make a bunch of changes, they can introduce new errors which can be hard to differentiate from the original bug you are trying to fix. By restricting yourself to one small change at a time, you allow yourself to go back if things didn’t work out, and also to verify that the change you just made indeed improved the solution.
8. If possible, add unit test for the fix
Not all bugs are unit testable. However, if it can be done, it’s wise to have a unit test in place once you fix the issue, so that it doesn’t happen later.
9. Look for similar defects
When you find one defect, look for others that are similar. Defects tend to occur in groups, and one of the values of paying attention to the kinds of defects you make is that you can correct all the defects of that kind. Looking for similar defects requires you to have a thorough understanding of the problem.
10. Relax, and go home
If you have spent too much time trying to fix the bug without any luck, just go home, take a good night’s sleep and come back to it later. This works most of the time. When it comes to thinking, exhaustion is the enemy. Fatigue slows brains. It triggers errors, lessens concentration, and leads to shortcuts that create bad habits. When exhaustion creeps in, it’s time to quit.