I enjoy debates about TDD and Brian Harrys blog post is no exception. Brian sounds out what he likes and dislikes about TDD and it's the dislikes I'll focus on.
The idea of having unit tests that cover virtually every line of code that I’ve written that I have to refactor every time I refactor my code makes me shudder. Doing this way makes me take nearly twice as long as it would otherwise take and I don’t feel like I get sufficient benefits from it.
Refactoring your tests to match your refactored code sounds like the tests are suffering. Too many hard dependencies with no SOLID concerns are a sure fire reason you would do this. Maybe at the start of a TDD cycle you would need to do this as your design evolves and you remove these dependencies but this should quickly be resolved as you refactor. If you find your self still doing it then stop and look back at your design.
Don’t get me wrong, I’m a big fan of unit tests. I just prefer to write them after the code has stopped shaking a bit. In fact most of my early testing is “manual”. Either I write a small UI on top of my service that allows me to plug in values and try it or write some quick API tests that I throw away as soon as I have validated them.
The problem with this is that a UI can make assumptions on your code that then just unit test around and very quickly the design becomes bad and you technical debt sweeps in. If you want to blackbox test your code with a UI then do so after your TDD cycles not before.
This is probably by biggest issue with a literal TDD interpretation. TDD says you never write a line of code without a failing test to show you need it. I find it leads developers down a dangerous path. Without any help from a methodology, I have met way too many developers in my life that “back into a solution”. By this, I mean they write something, it mostly works and they discover a new requirement so they tack it on, and another and another and when they are done, they’ve got a monstrosity of special cases each designed to handle one specific scenario. There’s way more code than there should be and it’s way too complicated to understand.
I believe in finding general solutions to problems from which all the special cases naturally derive rather than building a solution of special cases. In my mind, to do this, you have to start by conceptualizing and coding the framework of the general algorithm. For me, that’s a relatively monolithic exercise.
TDD is an development pratice not a methodology, the danger is that the solution becomes a mass of different things that violate DRY. TDD won't solve these problems, only good communication and practices like pairing will help. Above all else an assumption that TDD replaces a methodology is a mistake, combine it with what ever works for your team\business but only good communication will help. A good naming scheme\structure for folders, files and tests can help you and your team isolate what tests are for what.
I was at DevWeek last week, it was a great week and I got a chance to speak with some of my geek heroes (Jeff Richter is a walking, talking CLR). One of the folks I most enjoyed listening to was ThoughtWorker Neal Ford who gave a session on emergeant design in TDD. Something struck me about the RGR cycle in TDD in that design could either be missed or misplaced if the refactor phase is never carried out and after the inital green phase the design is considered done. In TDD the emergant design that evolves as part of the cycle is key to the approach. Neal talked about using cyclometric complexity as a measure of your emerging design but other considerations would surely include SOLID and DRY during the cycles. As you refactor to these kinds of design principles your design evolves.
VS2010 is right around the corner and thoughts now turn to the next version of VS. One thing I am seeking dear reader is how in the next version you would like to improve how VS interacts with test frameworks and tools, could that be made better and what would you most want to see (better reporting, better interaction with TFS, better templating support for test frameworks etc)?