TDD, Test-First, and Ravioli Code

I know that test-first and test-driven development (TDD) are popular methodologies these days, but something about those processes has always met with a level of mental resistance from me. Even though it sounds good in theory, I have been intuitively wary of the "test-first" mentality for some reason. My own approach is closer "remember to code so you can test it later" and then "test-last" after the API is mostly stable. This comment from Slashdot is a good summary of my feelings on the matter.

Thinking about testing early -- good. Writing unit tests -- good. The test driven development mentality (write tests instead of design, write unit tests before coding) -- bad. ... Thinking about testing early is useful, it may cause you to think about corner cases. But writing them first causes 2 problems -- you end up writing the code to solve the tests (rather than solving the problem) and/or you end up throwing away half the test suite in the middle when you refactor the design.

-- AuMatar

Just that you have tests does not guarantee that you're solving the right problem, or solving it well, or that your solution is comprehensible to others.

In the same conversation, someone brings up the term "ravioli code", which I had never heard before. The idea is that instead of long strings of procedural "spaghetti" that are difficult to untangle, there are lumps of methods jumbled together:

The problem is that it [Ravioli Code] tends to lead to functions (methods, etc.) without true coherence, and it often leaves the code to implement even something fairly simple scattered over a very large number of functions. Anyone having to maintain the code has to understand how all the calls between all the bits work, recreating almost all the badness of Spaghetti Code except with function calls instead of GOTO. It is far better to ensure that each function has a strong consistent description ... rather than splitting it up into smaller pieces ("stage 1 of preparing to frobnicate the foo part of the foobar", etc.) with less coherence. The principal reason why this is better is precisely that it makes the code easier overall to understand.

...

People who deliberately split code up into ravioli, and especially those who advocate that others do so, are "dangerous idiots" precisely because they've lost sight of the fundamental need for comprehensibility ...

-- dkf

I think that a lot of TDD and test-first idealists and evangelists* end up with ravioli code that is well-tested but still difficult to comprehend.

Some people will read this and think that I am against unit testing; that would be an incorrect interpretation. TDD and test-first dogmatism are what bother me, not testing per se.

(* Note that I said "idealists and evangelists" -- not all of the test-firsties are like this.)

Are you stuck with a legacy PHP application? You should buy my book because it gives you a step-by-step guide to improving your codebase, all while keeping it running the whole time.