A couple of days ago I finally wrapped up an assignment in the Logic Programming course. It took me some time, since I couldn’t find a nasty bug in it. Very embarrasing.
The assignment itself was a classic case of model-driven development, at least in its raw form: The model was half-a-dozen or so statements in first order logic. Based on this model I wrote about 100 lines of Prolog code. The Prolog program generated several hundreds of CNF clauses. A CNF solver took these clauses as a long list and gave a solution. The only problem was, of course, that the solution was wrong.
I looked for the bug inside my 100 lines of Prolog code, in vein. It wasn’t there. The Prolog program was just a simple CNF generator that worked well. It took some data and generated CNF clauses according to those logic statements that I wrote. That’s it.
The bug was, of course, in the model. The first-order logic formulas were wrong. I used a redundant logic variable that created un-needed constraints. I removed this variable and simplified the formulas, and then re-wrote the Prolog program. It took a couple of hours and, amazingly, worked perfectly from the first run.
The size of the bug was a single letter. My original formulas contained the variables “N”, “E”, “C”, “V” and “B”. “C” was redundant. Removing it and re-writing the statements solved the problem.
Moral: Models matter. Every program is based, explicitly or implicitly, on a set of ideas and assumptions. In this assignment I had to write them down, so I got a glimpse of their power. A single wrong assumption can be the difference between “working” and “not working”.
The Devil’s programer would say: “We, at hell.com, solved this problem. We don’t have a model for our programs, so the model cannot be wrong.” He’s lying, of course. All programs derive from a model. In most cases, it is a mental model. It doesn’t mean that it does not exist or that it cannot be wrong. It just means that it is much more difficult to debug it.
Guy Wiener on March 8th 2009 in Programming