In their excellent book, The Pragmatic Programmer, Andrew Hunt and David Thomas have a section on "Programming by Coincidence". Although their book is jammed with useful tips, I think this is one of the most important ones.
Recently, I had a deadline for a large university project. Since my class partner and myself both have jobs, we really had to stretch ourselves to finish the project in time. This included a 30 hour sprint to finish the damn thing before the deadline. Programming in such conditions is always, shall we say, interesting. Despite the hour, I was actually able to catch myself programming by coincidence.
So what is Programming by Coincidence (PbC)? I'll try to explain.
It is well known that the best way to solve a maze (the ones you find in children magazines) is to start in the end, and work your way backwards. I've always favored a similar technique for solving logic problems - first you find the solution, and then you go back and understand why its the solution. This is not as silly as it sounds. Most logic problems can be solved using brute force by a 10 line computer program. But, as I've learned the hard way, this is the path to the dar, erm, programming-by-coincidence side.
So, a logic puzzle analogy to PbC is to start guessing solutions, and hope you stumble upon a correct solution to the puzzle at hand. The catch and downfall of logic-puzzle PbC practitioners is that, although a correct solution is found, no real understanding is gained. Even if, after finding a solution, one tries to understand the solution, all reasoning will be biased towards the known solution.
The flaw in my maze analogy is that solving a maze backwards is just a technique for finding the solution. The maze end is not the solution. The path is the solution. So there is no real correlation between the two.
In programming, PbC is similiar. It mainly involves guessing, finding a working solution, and then moving onwards to the next task. The problem is that the set of working programs is quite huge, but the set of good working programs is much, much smaller. If we don't truly understand what the problem is, why our solution works, then we're PbC.
And the danger of PbC is that things start to break down. Making changes in one place results in unit-tests failing in completely unrelated locations (you are using unit-tests, right?). This is a symptom of many software development problems (tight coupling, for example), but also of PbC. Many times, hacked together solutions work because of bugs in other people's code, or non-standard behaviour. When that changes, a once working solution a zillion lines of code away stops working.
If, instead of taking the trial and error path to finding a solution, we were to take a step back, look at the big picture, understand how everything fits together, and then think of a correct solution, then we wouldn't have such problems.
And I must confess that after 25 hours of coding, I knew I was PbC, but I kept at it, frustrated as I was. Lukily for me, my project partner is more experienced, and he had the sense to call a full stop, until we really understood the problem, and only then did we start looking for a solution.