Skip to content

A TDD talk from The Agile Workshop

September 24, 2009

I went to my first .Net Developer Network meeting this week; a talk on Test-Driven Development (TDD) by Stephen Oakman and Ronnie Barker, co-founders of The Agile Workshop. It was certainly a thought-provoking evening, although perhaps not for all the right reasons. I’m not entirely sure that I’m being entirely fair here, but since when has that stopped me?…

For me, there were two key areas where it went awry:

  1. No statement of intent – we didn’t know what we were doing
  2. Limited scope – we didn’t use the tools necessary for good software design.

No statement of intent

The was no real intro to the talk, just a sense of “let’s do some TDD and see what happens”. There wasn’t really any discussion of where we were starting, which object we were designing, or what responsibility our code was to fulfil. We just went straight from a fairly woolly user story to bashing out test code.

How can you go from story to object? You can’t. The stories tell you about your overall responsibilities. The responsibilities tell you about your objects. You take one responsibility, and think about the object that will fulfil that responsibility. What services does it need to provide (what’s its interface)? What does it need to do its job (what are its dependencies)?  Next, you name your object. That’s really important (you’ve read Clean Code, right?). Then you TDD. Then you think about the tests that will capture the responsibilities of your object.

Note that I’m not saying that you write your interface, and fix your dependencies, and then write your tests. The tests are the first lines of code that you write. The tests do drive the design of your interface, and the relationship your object has with its dependencies, but the thoughts you have about the responsibility of your object will guide your tests, and then those tests drive the actual design of the software. And yes, as the tests shape your thinking, then you might have to change the name of your object.

If we don’t think about what it is that we’re trying to design, which single responsibility our object under test is going to have, then we can’t hope to make a decent go of writing tests to drive the design of that object. This set us on the path to exactly the sort of poor design that TDD is intended to keep us from. To be fair, like many Agile methods, TDD exposes problems in the code, and in this talk the problems were there to see. It’s just a pity that they weren’t picked up on.

Also, without an introduction setting out what it was that they were trying to show, it was then difficult to know what it was we were to agree or disagree with. The problem, for me, was that I spent most of the lecture waiting for them show us what TDD is all about, and when they didn’t, it was already too late.

TDD is a software design methodology. We write the tests first because we believe that in doing so, we will end up with better-designed code than we would have done otherwise. But what do we mean by “better-designed”? We mean code that’s loosely coupled and highly cohesive. Code that’s open to extension and closed to modification. Code that’s reusable. Code that’s clean. Code that another developer can come back to and understand. Code that another developer can change, and be confident in their changes.

TDD doesn’t mean good code. TDD doesn’t guarantee well-formed software design. Like all Agile methods, TDD is designed to highlight software design faults. If you don’t then respond to what TDD is showing you, but just leave it as it is, then you’ll still get poorly-designed software. Some might argue that that’s ok; that change will break the poorly-designed software (good design is like good mental health, right?) and our existing tests, and further application of TDD, will drive our software towards greatness.

Screw that. TDD isn’t a religion. I’m not TDDing and forsaking all other design tools. I’m going to make sure that my object has a single responsibility. I’m going to invert my dependencies. I’m going to program to interfaces. I’m going to favour constructors over setters. I’m going to favour composition over inheritance. And yes, I’m going to do TDD as well, but I’ll do it with all those other things in place.

So, for me, TDD is a software design methodology that we use to help us produce well-designed code. If that’s the purpose of TDD, then the purpose of a talk on TDD should be to demonstrate how TDD helps us generate good, clean, well-designed code. The proof of the pudding is in the eating; the proof of TDD is in the design of the software it produces.

Well, that’s how I would have started and ended the talk, anyway.

Limited scope

Stephen and Ronnie stated quite early on that mocks and interfaces were beyond the scope of the talk. If interfaces are beyond the scope of a TDD talk, then programming to interfaces is beyond the scope of a TDD talk, and therefore well-designed software is beyond the scope of the TDD talk, and your TDD is destined to fail (assuming that well-designed software is the goal of TDD). For any non-trivial TDD example, you will need to program to interfaces. How do you expect to generate well-designed code otherwise?

And I haven’t even got onto the importance of mocks in TDD. If mocks are beyond the scope of the talk, then testing objects in isolation is beyond the scope of the talk, which means that unit testing is beyond the scope of a TDD talk. Wait a minute… TDD without unit testing? Yeah, good luck with that…

Someone once told me that “Agile is agile”; that you can pick and choose your Agile tools and methods like a kid in a sweetshop. No. It doesn’t work like that. Agile tools and methods work together; it is their combination that gives us the ability to write good code and ship good product. By excluding mocks and interfaces, Stephen and Ronnie took away two of the most powerful mechanisms for writing clean, reusable code; and, as a result, ended up with a fairly messy design instead.

In summary…

On reflection, the talk only really covered the mechanisms of TDD; they seemed so pleased with the scripts they’d installed for auto-completion and flashing keyboard short-cuts up at the audience that (for me) we didn’t get anywhere near the reasons for or results of TDD. Which is not to say that they didn’t have enough time to produce clean, purposeful code; just that when we reached the point at which I felt the benefits of TDD were only just beginning to kick in, they chose instead to plough on, generating smelly code and tests, concentrating on how to generate the next test, or move a class, or rename an object, or extract a method.

(This feels somewhat like sticking the knife in, but I can’t help but point out that for all their tools and plug-ins, they seemed unable to use the IDE to perform the simple renaming of a class. There were at least three occasions where the name of a class was changed, and then that name was copy-and-pasted on top of all existing references to that class. If you’re copying-and-pasting, you’re doing it wrong.)

I guess my point is that I think I know what TDD is about, and I’d be interested to know if Stephen and Ronnie had shared my perspective, and if not why not. As it is, I don’t even know if they know why they practice TDD, let alone whether the principles they apply, or benefits they derive from it, are the same that I do.

I have some really strong opinions on what TDD is and why we do it. I was hoping to maybe refine those opinions, maybe challenge them. Instead we ended up with some fairly mediocre code that wasn’t particularly well-designed, but there seemed to a general assumption in the room that, because it had been written via TDD, then it must be OK.


Those were pretty much my two biggest problems with the talk. There were a few other minor irritations. One member of the audience asked a question that basically amounted to “if I’ve got an object with loads of responsibilities, it’s hard to write the tests for it. What do I do then?”, the answer to which, of course, is that if it’s hard to test then it’s bad code, and you need to change it. IIRC, the answer given was something along the lines of “yeah, well, that can happen. Write lots of tests”, which wasn’t entirely satisfactory…

No comments yet

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: