So you’ve got a bug in your code? How in the world do you find the thing? Here are some of the techniques I use to identify the offending code.
Was the bug introduced fairly recently? If so, you can jump back in the code to a time when the bug was known not to exist. Using the
git bisect command, you can perform a binary search through your code base until you find the commit where the bug was introduced. Looking at that diff should give you a fairly small amount of code to dig through. This is a fantastic technique when you are working in a new or unfamiliar code base.
Explain the problem to a teammate
Speaking is thinking. Oftentimes, just forming the words to describe the bug to a teammate will lead you right to the source of the problem. A good colleague will ask you probing questions to help you think about the problem in a new way.
I began my career programming signal processing microprocessors in assembly. (Fun, right?) In any assembly language it can be pretty hard to keep track of what was what (no named variables!). In signal processing, you get a data sample for a time period, transform it with a pipeline of algorithms, and pop out an output sample. When I would need to find a problem in a calculation, I had to step through the code, instruction by instruction, verifying the intermediate results in the registers along the way.
All code can be looked at like a signal processing chain. Something happens that then causes something else to happen, and then at some point you are expecting the correct output or side effect. To debug with this method, start at the beginning of your buggy scenario. As a mental exercise (or with a debugger or series of print statements), step through each method, function, or transformation one at a time until you find the problem. Granted, it may take you a long time if your problem is toward the end of your process, but you always know where you have been and where you are going.
Test-Driven Bug Finding
There are a lot of assumptions you have about your code. Hopefully, most things you know are covered by a test; but if you suspect a problem somewhere, try poking at it with a new test. Maybe there is an unconsidered corner case or some unwritten assumption that was violated.
It is easy to fall into the trap of guessing where the problem is, then looking there and not finding anything. Then, you jump over to somewhere else. You do that a couple of times and you have no idea where you’ve been, and you keep looking back at the same thing over and over. Try one of these techniques to keep track of where you've been and help you find the bug.
What more? Check out the rest of this series: