Skip to content

step 9 / 32 · 5 min

Finding a bug on purpose

Most people debug by changing things until it works. That sometimes works and teaches nothing, and it frequently introduces a second bug.

The method

1. Reproduce it reliably. A bug you cannot trigger cannot be verified as fixed. If it happens once in fifty, find what varies: a specific input, a timing, a user's data.

2. Narrow it down. Halve the search space repeatedly. Comment out half the pipeline, test with a smaller input, check whether it happens on another machine. Binary search applies to code as well as arrays.

3. Form a hypothesis you can test. Not "something is wrong with the parser", but "I think the date is parsed in the server's timezone rather than the user's". A hypothesis names an expected observation.

4. Test it. Print the value, set a breakpoint, add an assertion. If the observation contradicts the hypothesis, that is progress: you have eliminated something.

5. Fix the cause, not the symptom.

java
if (result == null) result = new Result();   // symptom

That line makes the crash stop. It does not explain why result was null, and whatever produced the null is still producing it somewhere else.

6. Add a test that would have caught it. Otherwise it comes back.

The tools, in rough order of usefulness

ToolBest for
A stack trace, read properlymost crashes, and it is free
Logs with a request identifierproduction, where you cannot attach
A debuggercomplex local state
git bisect"this used to work"
strace, network inspectionit is not my code

git bisect deserves more use than it gets. Given a good commit and a bad one, it finds the guilty commit in about log2(n) steps, and can run a test script automatically. Twelve steps over four thousand commits.

Read the error message

It sounds too obvious to say. A large share of time lost to debugging is lost by skimming an exception, assuming what it means, and investigating something else. The message usually names the file, the line and the condition.

When you are stuck

Explain the problem out loud to someone, or to nothing. Articulating the assumptions forces you to check them, and the answer arrives mid sentence often enough that the practice has a name.

And stop after an hour. A break is not giving up; it breaks the fixation that is keeping you on the wrong hypothesis.