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.
