My Response to Scott Dockendorf's Response to Me in Response to his Article
Damn it's been a great week of Test-Driven Development dialog in .NET land!
Scott Dockendorf took the time to address my review of his article in the December '04 issue of DNDJ.
Here's the text of the reply that I posted to his post where he posted to my post:
My contention, then, is the definition of a second approach to TDD. While Approach #2 has some elements of TDD, it would be more appropriate to say that it’s “TDD-like” or “TDD-ish”, or that it “borrows from TDD”. To say it’s not “classic” TDD reciprocally manifests a “new” TDD out of thin air that is differentiated from the original. This is where I sense the danger in introducing ambiguity. To wit, I can’t see any advantages to Approach #2 that I can’t get out of Approach #1, furthermore, I see risks in Approach #2 that I don’t see in Approach #1. Additionally, Approach #2 looks like the transitional attempts at TDD that happen along the way to TDD from architecture-centric development.
I’m also a Domain-Driven Design fan and a former UML addict. Nonetheless, the presence of diagrams and docs doesn’t preclude the TDD process. As low-level design, TDD validates the higher-level design. I don’t see much of an advantage for either implementing, generating, or otherwise transforming skeletons from high-level design artifacts that have yet to be validated by low level design (programming). The en-masse model transformation step is what YAGNI talks to in the context of architecture-centric development.
Because you can easily go to code through a transformation tool (or other means) doesn’t mean you have to. Otherwise, you’re just dumping high-level design artifacts into a low-level design contexts verbatim without consideration for the dissonance between these model levels. It’s this dissonance that TDD seeks to resolve. BDUF and code generation from BDUF artifacts just perpetuates the problem. You have to recognize and heed the implications and risks in model dissonance in models at levels of abstraction before any of this will take hold. Doing thorough design up front is wasted time if you recognize model dissonance.
There's a fine line where an amount of design becomes too much design and it has to do with whether any more detail you add to your high-level model will actually survive the transformation to working code. Any effort expended after crossing this line is almost assuredly wasted time and money. The API you started with at the high-level design isn’t likely going to be the design you end up once the low-level work is done, so why design details that aren’t likely to survive?
The other significant risk in starting the TDD coding process with low level design artifacts (test fixture) that was transformed verbatim from a high-level design artifact is the cognitive lock-in that developers will undergo when they see and begin to work with an API in code. They will attach to it, identity with it and start to design the rest of the code to fit into it rather than use the low-level design techniques inherent in TDD.
That's not to say that you can’t arrive at a pretty rigorous definition and understanding of an API before hand, it's just that it's a pretty rare need considering the sweet spot of team size where TDD and XP are the right fit. In a situation where there are multiple teams of 10 people working on the same large project, then someone is going to have to architect the high-level API. To make TDD really sing in this case, you'd probably wanna make the API spec into a separate layer so that your coders can be free to refine the underlying implementation with TDD. The implementation of that unifying API layer might even be done by an architect not using TDD (likely), while the teams building the internals would be free to engage in TDD.
I don’t think you can introduce an Approach #2 into the TDD sphere. There are too many things that are antithetical to TDD's tenets. I think the approaches that you outline are likely to be amenable to the Softies who are going to try TDD for the first time with the advent of VSTS, but it shouldn’t be called TDD just as MSF shouldn’t be called RUP. The processes have elements that are fundamentally contradictory. And again, Approach #2 looks like the stuff that happens on the way to the TDD a-ha moments. Test-Driven Development isn’t a loose definition of a practice like process frameworks like RUP and MSF. TDD is a specific instance of a programming process. I don’t believe that it leave as much open to interpretation as Approach #2 seems to take license with. Approach #2 is Approach #2. I think it should have a life of it's own rather than indulge in borrowing TDD's identity.
I’m not coming at this from a semantic puritanism. We seem to be treading dangerously close to muddying the waters in the .NET space around the ability to have a shared understanding of this TDD thing. Introducing new definitions for something during a time when the common understanding of it has barely taken root in .NET developer culture seems a bit irresponsible to me. How can I teach developers the finer points of TDD if they already believe that they're doing it? It's spanks of a marketing tactic that Microsoft is very skilled with - linguistic assimilation.
I don’t think there's anything inherent in Whidbey that causes a greater amenability to Approach #2. I haven’t had an install of Whidbey since PDC '03, but we got a pre-public preview of the unit testing tools in VS 2005 at the MVP Summit in April '04. At that time, there was support in the C# IDE for generating a target method from an invocation in a test fixture in support of TDD. I think I heard that this capability is now a part of the C# refactoring tools.
There is a huge problem in the Microsoft world where developers choose their convenience over common sense practices. Visual Studio allows developers to drag data components on to UI's and so they do it. It's a bad idea, but they do it. VS 2005 will allow developers to build an API and generate test skeletons for it. Good tool support, but a lack-luster approach considering what TDD brings to code design.
VS 2005 is an architecture-centric tool suite. It's got a bit of support for TDD, but it's architecture-centric at its core. TDD isn't an architecture-centric process. Microsoft has architecture-centric leanings when it comes to cutting code. Architecture-centric thinking is great for doing architecture - I'm not so sure it applies to doing code.
To bend TDD to fit VS 2005 Team Test/Developer changes TDD so that it's no longer a design discipline, much in the same way that VS .NET's RAD bends web apps so that they're no longer n-tier and component based. The only way to get n-tier out of VS .NET is to not rely on the tool for little more than laying out UI's. The only way to get TDD out of VS 2005 is to not rely on the tool for little more than the test attribution and execution framework.
Would you use Approach #2 if VS 2005 didn’t give you the capability? Is this capability more valuable than the micro-iterative rigor of TDD? Is the convenience of embedding data access into web forms more important that n-tier and components?
When code-generating tools start dictating practice, we end up abandoning professionalism in favor of convenience. Why don’t more .NET developers engage in n-tier? Because there's no n-tier widget in the VS .NET toolbox.
Ok. All that vehemence aside, I certainly appreciate the opportunity that this exchange is providing to put these ideas down in black and white. Some of what I'm doing here isn’t necessarily directed at your article or response. I got started brain dumping and figured I'd better keep going lest I loose the momentum. I should say also that I love a good debate and I'm apt to get quite engaged in something like this.
Please say hi to Chris M when you see him. And let him know that he better not promulgate any of this test-gen-is-TDD stuff when he speaks on VSTS at ADNUG this summer :)
-s
