Debugging
- The closer the failure occurs to the actual point of error, the
easier it is to find the problem. Use everything you can to trap it
sooner rather than later.
- Know what the program is supposed to do. If there's no
specification, how can it be wrong? This applies to test cases,
too: it's too easy to convince yourself it works if you don't
really know what the right answer should be.
- When you have a problem, find the minimal input that will
reproduce it. Use "binary split" to reduce large input files: try
it on the first half of the data, see if it still fails. If so, cut
the data file in half and try again. This will let you work your
way down to a much smaller file. If this doesn't work, try
eliminating certain classes of input.
- Use the debugger to see what things are like when they're
wrong. If you're using the PRE/POST/ASSERT/OK definitions, it
almost certainly failed an assertion. Stop the debugger there:
check the stack trace and the state of the items.
- It's probably NOT the compiler! C-based languages have a lot of
looseness in how they can handle things (size of basic objects,
storage layout, results of many operations). If you think it is the
compiler's fault, cut the program down to something so small it can
be checked, and file a bug report. (Not that compilers don't have
errors, especially around the dark corners, but too often the
problem is the user's.)
- The debugger usually has facilities for setting breakpoints on
procedures, and watchpoints on locations. Both can be useful.
Debuggers often let you change a variable and continue execution;
this can be helpful too.
- I've heard bug-checking likened to a scientific search where
you generate and test hypotheses (sorry - no ref.) But that is the
attitude you need. ("If I set this to this value, this should
change; let's check it.")
- Maintain a log of errors. I document each one with
"Date/Symptom/Cause/Fix/Lesson". You tend to make the same sorts of
errors, so this can highlight that.
- In C++ in particular, watch out for improper recompilation.
When I've had a mysterious bug, deleting all the object files and
rebuilding everything has often fixed it. (If you're using a system
that doesn't figure out source dependencies for you, it's hard to
get them all right.)
- When commenting out code, use "#if 0/#endif" to bracket out
sections of code. This ensures no interaction with comments. (I
might use "//" to comment out a single line in C++, though.)
- Run the profiler. Usually you can set it up to give you counts
of how many times the various routines were called, and you can
compare this to your expectations.
|