"The Best Programming Advice I Ever Got" with Rob Pike
I can’t agree more with this advice.
Debugging by thinking is as important an educational tool as it is a development tool. If you’re used to jumping into the debugger right after you compile, try something different: As soon as your program exhibits unexpected behavior, step away from your computer. Formulate a hypothesis that might explain why your program behaves the way it does. Return to your computer only after you have a hypothesis. Don’t open your debugger just yet. If possible, try giving your program a different input and predict the results according to your hypothesis. Don’t open the debugger yet. With the additional information and your hypothesis in mind, go back and read your code. See if you can find the problem or refine your hypothesis to blame a specific module or function. If you think you’ve found the problem, try fixing it and repeating. If you’re only able to narrow the problem down to a module or function (or you’re seriously stuck and need more info), set some breakpoints and start debugging. Stop debugging as soon as you have more information and repeat the process. The absolute worst thing you can do is use the debugger to help you fiddle with code to patch a symptom without understanding a problem’s root cause.
By the way…like a debugger, unit testing is another development crutch; however, it has measurable benefits. Work done in a debugger is lost as soon as you complete it–nothing persists to convey your understanding of a program’s model to another developer or to check your assumptions as you change the model. Unit testing leaves behind an executable framework that does just this. But, as with the debugger, developers can fall into bad habits with unit tests: when a program fails to behave as expected, you can add more test coverage to get more visibility and then just fiddle with the code until the tests pass and the program behaves as expected–without improving your mental model of the code.
Don’t underestimate the power of thinking.