Of course, everyone has heard about RAD, RUP, CASE, iterations, waterfall, etc. and some people are even experts in these things. But wait! Software developers also need service and support, the most important part of which is debugging. Who knows what percent of development effort is spent in debugging during the whole software life-cycle? You can find estimates in various articles and books, but it's apparent that the percent is high! Unfortunate, but that is the reality...
In this article I'm trying to describe the process of debugging, generalizing my experience. Debugging is a less formalized activity than development and I would like to change that, since one of advantages of formalizing a process is the possibility of improving the process. I will also give some suggestions on improving the debugging process based on its formal description.
Unlike software development, debugging is inherently iterative. (I mean development in general, realizing that in complex projects development can and should be iterative, too). Debugging, in general, consists of three main stages:
- Describe the bug.
Maybe this isn't part of debugging itself, but it's so important that I include it here. You should get as much detail from the user as possible: product version, OS version, all conditions needed to reproduce the bug.
- Get the program snapshot when the bug 'appears'.
Try to reproduce the bug and catch the state (variables, registers, files, etc.) and action (what the program is doing at the moment, which function is running). Sometime this is simple: e.g. the program crashes and you can just switch to your debugger to see the problem. But in other cases you have to perform many iterations to catch the snapshot. You maybe even have to return to 1 in some cases. In other cases you will return here from the next step.
- Analyze the snapshot (state/action) and search for the cause of the bug.
It is possible that the state and action might be wrong, so a substep in this stage is to determine whether they are correct or not. The following state/action combination classification can be useful in guiding further analysis ('+' & '-' indicate 'correct' & 'wrong', respectively ):
- +/+ : unreproducible bug;
You have an incorrect description or different environments (OS, etc.)
- +/- : a simply found bug;
You have to add some checking (NULL pointer, divide by zero, etc.) or additional implementation of something
- -/+ : a bug requiring a search for its source, origin;
Methods you can use include
- tracing from previous moments,
- tracing of places where the state components are used/changed
- tracing with different input data
- your experience may indicate key places in the program (e.g., the start of user input processing)
- -/- : same as -/+ plus additional difficulty, but due to the difficulty of situation in some cases some work-around may be enough decision, i.e. making action correct (+).
- Fix the bug.
Ideas about bug fixing may occur at any stage of the debugging process, but only one may be implemented, which 1) fixes the class of bugs which the described one belongs to, and doesn’t introduce other bugs in other places and/or with other input data.
Experience and knowledge of the program play key roles in all stages of debugging. This knowledge can help both in getting the program snapshot and searching for the bug's origin. Examples of key places to look include the start of user input processing, multi-functional procedures, etc. Therefore the following ideas can be useful to keep in mind.
To Improve Debugging
- Build smarter debugging tools. Since these tools would be used in almost all stages of debugging, it would be useful to “teach” them the program and the program itself should help debuggers.
- Create a system/DB of key documentation about the program useful in debugging, for example "If there is a problem in aspect A, then look (set breakpoints, etc.) in key places A1, A2, … ". The DB should support searching.
Have a nice Debugger!