We believe that Schoenfeld’s categories can be transferred from the domain of mathematical problem solving to that of software debugging in a straightforward manner.
Debugging tactics are programming skills that produce information. Programmers who are competent in debugging have an inventory of tactics they can quickly match to situations. They can apply those tactics automatically without requiring contemplation.
Debugging heuristics are techniques for making progress on unfamiliar problems or rules of thumb for effective problem solving. Heuristics aren’t guaranteed to produce a result. Programmers who are competent in debugging use a variety of means to generate ideas on the root cause of a bug.
Debugging strategies are global decisions regarding the selection and implementation of heuristics and tactics. Programmers who are competent in debugging plan their diagnosis activities and know when to give up on a line of analysis and try a different approach.
One way to look at these three levels is with a military analogy. Military analysts look at three levels of activity: strategic, operational, and tactical.
Strategic decisions are made at the top of the organizational hierarchy. Strictly speaking, only one strategy is being employed at a time, although in an extremely large undertaking, there may be a second level of strategy in independent areas of operation.
In World War II, the strategy of the United States and the United Kingdom was to force the Germans to surrender unconditionally first, and then do the same with the Japanese. Within the European Theater of Operations, the strategy was to liberate Western Europe by a cross-channel invasion from Britain. Within the Pacific Theater of Operations, the strategy was to bring the war ever closer to Japan through a series of “island-hopping” actions from the periphery of Japan’s empire. Strategic decisions cover the largest scope geographically and often take months, or years, to implement.
Operational decisions are made at the mid-level of the organizational hierarchy. Operational decisions cover a smaller scope geographically than strategic decisions, but still can cover a large area. Operational decisions can involve large organizations, but unlike strategies, a number of operational decisions can be enacted independently and simultaneously. Operational decisions take days or weeks to implement.
Tactical decisions are made at the bottom of the organizational hierarchy. They cover only a small geographic scope and involve the actions of individual soldiers and pieces of equipment. Tactical decisions take only minutes or hours to implement.
Another way to look at these three levels is with respect to hypothesis generation and evaluation. Strategies tell you which hypothesis to explore. A good strategy will tell you how to choose a hypothesis, how to validate it, how to refine it, and when to discard it. Previous works on debugging don’t recognize the concept of strategies as such.
Heuristics suggest new hypotheses or new tactics to employ. Heuristics are most useful when our current hypothesis has proven false or insufficiently precise. Rather than stare at a problem in the hopes that a new hypothesis will leap from the page, we get out our list of heuristics and employ one.
Since there is no guarantee that a heuristic will yield a result, there is no guarantee that employing a debugging heuristic will suggest a hypothesis to us. Experience has taught us, however, that the probability is high that if we employ several heuristics, one of them will help us to see the problem in a new light. Previous works on debugging don’t distinguish heuristics from tactics as such.
Tactics tell you about the state of the program when it’s running, so that you can validate or invalidate the current hypothesis. Tactics aren’t helpful if you’re working with a pseudohypothesis, that is, a statement that can’t be completely proved or disproved. Previous works on debugging usually don’t articulate the relationship between tactics and the current working hypothesis.