While test-driven development began as a more iconoclastic approach to programming, it has since received mainstream attention agile development became more popular. It certainly has its share of both supporters and detractors, but the changing role of software in the enterprise merits a new look at the effectiveness of truncated software development lifecycles as a means of rolling out applications more fluidly. As programmers design with self-service end-user reporters in mind, it may make sense to adopt test-driven development as a way of making the overall process more inclusive and transparent. At the same time, there are some potential shortcomings in test-driven development that can quickly cripple the implementation procedure.
In a nutshell, test-driven development consists of short bursts of code writing that must fail before new code is written. A developer rewrites the code until it passes the test. Agile programming, in particular the creation of application source code and database development, can succeed on this process of efficient unit testing. It posits that writing simple unit tests is an effective way to validate the code's functionality before it is written, wrote SD Times founding editor Alan Zeichick. However, in a recent blog post provocatively titled "TDD is dead. Long live testing," programmer and Rails framework creator David Heinemeier Hansson argued that test-driven development is better viewed as "training wheels" - a valuable learning tool that an experienced programmer eventually outgrows.
"Maybe it was necessary to use test-first as the counterintuitive ram for breaking down the industry's sorry lack of automated, regression testing," Hansson wrote. "Maybe it was a parable that just wasn't intended to be a literal description of the day-to-day workings of software writing. But whatever it started out as, it was soon since corrupted. Used as a hammer to beat down the nonbelievers, declare them unprofessional and unfit for writing software. A litmus test."
What's the next step?
If test-driven development is in fact discarded as the viable approach to optimizing the SDLC, what will take its place? Hansson argued that testing-centric units create an "overly complex web of intermediary objects" based on the faulty principle that it is the fastest option for doing the job right. He wrote that he rarely tests units in the traditional test-driven development manner, instead using parallelization and controller test layers to directly test active record models. Creating a better way to conduct full system tests in the stack will be key to weaning programmers off of test-driven development, but Hansson closed by saying that it wouldn't be a good idea to dive headlong into a replacement "testing religion."
Zeichick, however, argued that while Hansson's observations contained some kernels of truth, it didn't quite read as the "knockdown blow" that Hansson intended. Zeichick proposed that thinking about test-driven development in a different way - namely that acceptance testing isn't mutually exclusive with test-driven development - can help programmers effectively wield it without feeling that it necessarily means a lack of communication with real-time or external data.
Redefining test-driven development
Dr. Dobb's contributor and programming expert Allen Holub also weighed in on the matter, but invited the participants in the argument to look at test-driven development in a different light. Instead of viewing test-driven development as merely a testing methodology, considering its implications as a mode of design can make more sense of its natural limitations. He even proposed calling it "test-driven design" instead of development. He wrote that testing is not enough because it only pinpoints an issue that makes code not function. It doesn't improve general code quality. Beginning with a working system, instead of code designed to fail, can help eliminate waste and make better use of the testing process.
"Rather than making something up and hoping that you get it right, imagine that you start with something real," Holub stated. "Take a small piece of a real story, and implement that piece as if the nonexistent subsystem that exposed our API did exist. You invent the API that you need to do the job at hand: no wasted arguments, no convoluted workarounds. The code just does what it does without fuss."