The fallout from Joel Spolsky’s “The Duct Tape Programmer” post still seems to be reverberating around the blogosphere. The dust has largely settled and Uncle Bob has resumed normal service on his usual insightful postings about testing etc. For a moment I thought he had gone way over the top and become excessively evangelical - even for him. He seemed to suddenly become a one man crusade to restore balance to the force and recruit legions to the cause of TDD. I saw him in person for the first time at the ACCU Conference last year and found him a truly compelling speaker.
As often occurs with a controversial issue such as this I discovered lots of useful discussion in the comments to his post, which I personally lapped up because I have only really been able to dabble in Unit Testing and TDD due to working on legacy systems with massive coupling. Also there were plenty of TLA’s flying about such as TFD (Test First Development), TLD (Test Later Development) and TDD (Test Driven Design/Development) along with BDD (Behaviour Driven Development) and DDD (Domain Driven Design) thrown in for good measure to keep any idle spectators on their toes.
The most useful post for me came a few days later when Uncle Bob (Echoes from the Stone Age) started to discuss the types of problems that you cannot tackle with TDD. This was hugely enlightening because this list pretty much mirrors a large part of what I do day-to-day. I felt somewhat relieved that I haven’t been “not getting the point” so much as attempting to squeeze the proverbial square peg into a round hole. And before you ask, it’s not that I haven’t mocked my interfaces to reduce my dependencies etc, it’s just that I don’t write a lot of what you might traditionally call Business Logic. The logic I do write is often heavily dependent on I/O, threads or 3rd party systems which pushes one more towards the ‘Functional’ rather than ‘Unit’ side of the testing spectrum to find real value.
Anyway, the one part of the discussion which I never felt was truly resolved, or that even the warring parties seemed to clarify their position on was what is the definition of “later” in TLD - Test Later Development. I got the general impression that some of the commentators had visions of old-school Waterfall style development where the “later” meant weeks, months or even years after coding had been completed. Does anyone really work like that these days? Did anyone really work like that? Certainly in my career to date the notion of “later” has pretty much meant seconds to minutes, with an hour on a rare occasion. I cannot imagine ever writing a non-trivial piece of code and not testing it in some way immediately. Yes, my tests may not have been truly exhaustive, but I do know that when a piece of code I wrote failed it was probably due to some fairly non-obvious scenario. I realise that sounds incredibly arrogant and I’m going to document my fall from grace in a follow-up post…
What was clear from the comments was that everyone in the discussion agreed that Unit Testing is A Good Thing – for some definition of unit testing. However it did also highlight that there is still much confusion about the various different forms of testing and what people call them. Some did not distinguish between TDD and Unit Testing which raised the ire of a few commentators. I myself have found the definition of “Unit” to be incredibly vague especially when trying to apply it to other development disciplines such as database scripts. I worked on a legacy system once where, due to the high level of coupling, the smallest testable unit was an entire .exe component.
I think I’m now beginning to “get” the TDD philosophy, but I’m not entirely sure it fits my style of working for two reasons. The first is that I have always found very lightweight modelling (in the way that Martin Fowler describes it as sketching in UML Distilled) to be incredibly useful for visualising a design first. The second is that I have 15+ years of experience to draw upon which means that many aspects of a design are in the realms of boiler-plate code. I find it very disruptive context switching between the boiler-plate and test code when I just want to rattle out the bog standard stuff first and use TLD to add the unit tests after. I can therefore save TFD for the new territory even though I often have a pretty good idea of where I’m heading because that’s why I sketched out the design in the first place. I’m sure it’s a fatally flawed argument and maybe I need to let go of the up front sketches and trust that I’ll still find my way via TDD and discover other benefits along the way. Old dogs can learn new tricks - you just have to tempt them with the right sort of biscuits.
Maybe I’m being too literal (it’s one of my more annoying traits) and perhaps we should just avoid the use of the TLD acronym and instead use TMLD (Test Moments-Later Development) and TMLD (Test Much-Later Development). Oh, wait, that won’t work… How about TRAID (Test Right After Implementing Development) and TAYFHIWD (Test After You’ve Forgotten How It Works Development). Hopefully there will be another TFD vs TLD flame war real soon and I’ll get the chance to fill in some more blanks and gain a further understanding of the Software Development Process. Heck, why am I waiting? Surely I can bait Uncle Bob with what I’ve just written… Now then, where’s his blog hosted again…