TDD for teams

I strongly suspect that TDD for teams is different than TDD for individuals.

There’s a proverb in software development to the effect that:

“TDD is a design technique, not a testing technique”

I agree. But that doesn’t mean it’s the only design technique we need. And it doesn’t also mean that everyone will use it equivalently or get the same results with it. For example, take a look at the approaches used by Seb Rose, Ron Jeffries and Alistair Cockburn to solving the Letter Diamond kata. (Click on their names to read their blog posts, then hop back here if you still have any energy left.) They each tackled the same set of requirements in completely different ways. Each used TDD, and yet their designs were completely different.

In fact, while I was drafting this post, George Dinwiddie had a go too, and Ron made a second attempt. So now we have 5 different design approaches to one toy kata from 4 developers, all in the space of one weekend. (And there are probably more that I haven’t heard about.) Of course, it would have been weird if they had all produced identical designs. We are all different, and that’s definitely a good thing. But I worry that this can cause problems for teams doing TDD.

A couple of years ago I remember doing a performance kata in which I paired with Mark Kirschstein to tackle the supermarket checkout kata. My role was to write the tests and Mark’s was to make them pass. At the beginning of the session I made the bold claim that I could get Mark to implement the checkout in a way he had never seen before, with a design that he had not conceived. The audience, and Mark, were skeptical. They were used to thinking of the problem as framed by the tests in Dave Thomas’ original problem statement. And so they were expecting the first test to be something like this:

public class CheckoutTests {
  @Test
  public void oneA() {
    Checkout checkout = new Checkout();
    checkout.scan("A");
    assertEquals(30, checkout.total());
  }
}

But in fact my first test was this:

public class CheckoutTests2 implements ScannerListener {
  int priceReported = 0;
  String productReported = null;

  @Test
  public void oneA() {
    Scanner scanner = new Scanner(this);
    scanner.scan(new SKU("A"));
    assertEquals(30, priceReported);
    assertEquals("A", productReported);
  }

  public void itemScanned(String product, int price) {
    productReported = product;
    priceReported = price;
  }
}

(expressed using the SelfShunt pattern, as anyone who has attended any of my training courses will recognise immediately). Mark, to his surprise, was gradually led to creating a checkout implementation based on notifications and listeners, and with no getters or setters.

[Supplementary challenge: implement the supermarket checkout kata without conditionals!]

While this was (I hope) great theatre, there’s a deeper message in all of this when it comes to whole teams working on non-trivial problems: If a team is to produce software that exhibits internal consistency and is understandable by all of its developers, then somehow these individual differences must be surrendered or homogenized in some way. Somehow the team must create designs — and a design style — that everyone agrees on.

Does it make sense for teams to operate as isolated pairs, each programming away on their specific tasks, without regard for how their designs will integrate with those of their team-mates? I see too many teams doing just that; ditching design sessions on the basis of reading TDD books and blogs in which a single person or pair did all of the thinking. I see far too many codebases in which personal style is the major design force; where the same domain concept is implemented in two or more radically different ways; where duplication is thus very hard to spot, and even harder to remove.

Perhaps we need more published examples of team-based TDD, showing techniques for creating and sharing Just Enough Design Up FrontTM.

XP includes the key practices of Coding Standard and System Metaphor; are they enough to solve the problem? How can pairs Refactor Mercilessly if there is no team consensus as to what constitutes “good” and “consistent”?

What does your team do to balance the needs of “enough design” and “too much design up front”?

Advertisements

14 thoughts on “TDD for teams

  1. Nice post, i’ve definitely seen code where it’s clear that different developers working on it have had different ideas about what the design should be. As well as perhaps teams doing a bit more design work / thinking up-front, do you recommend some kind of mob-programming approach, perhaps especially to begin with whist the ‘skeleton’ of the design is created?

    • @ryanwgough I like mob programming as a “togetherness” tool. I like promiscuous pairing (especially with the Least Knowledgeable Developer rule). And I like story breakdown into tasks to be a whole-team design session. And I like to have enough standups during the day (one is rarely enough).

  2. A good point, well made. We are all at the mercy of influences and nudges. The more interactions we have, the more influences we have. I encourage teams to use this to their advantage and avoid inconsistencies by “rolling” pair programming, rotating one out of the pair at least every day – first one then the other. This way some sort of consensus is achieved since you get to work with everyone. The more people do this, the more ideas get cross-pollinated until everyone more-or-less knows how things hang together. When differences of opinion cannot be resolved in the pair, call a team timeout to reach a mutual, team-level agreement. For really “interesting” design challenges, again, call a team timeout and discuss the options. This approach, although not infallible (but then, what is?) seems to work well. The usual caveats apply – small team, sane cooperative developers etc etc….

      • One word. Discussion. Maybe I’ve been lucky with who I have worked with over the years, but I’ve found that it is rare to find two totally irreconcilable points of view with this approach. If it ever happened, I would suggest taking another approach – eg majority view, most experienced dev(s) decide, development by convention, (temporary) parallel development. But if the rift is so deep nothing can bridge it after all this, then do you really have an effective team?

  3. I have a lot of experience with the checkout kata, done it myself maybe 30 or 40 times and used it as an interview exercise for dozens of people. This approach was first (only?) time where the solution lent towards a tell, don’t ask approach.

    I find it interesting, that whilst I prefer the production code that came out of your approach, I prefer the tests in the style that Dave Thomas gives as examples to the kata. I prefer them because they’re framed in such a way that is useful to a user of the system, it’s a feature, a piece of business of value. Make this test pass, and we can ship something of use. More over, these are the type of tests we would want to preserve until our requirements change, but we may wish to rework/refactor our internal messages.

    • Yes, I agree. The “standard” test is a specification of the external behaviour, while the second test is driving the implementation (and thus more brittle). But it did serve to make a point… :)

  4. Pingback: Priorities | silk and spinach

Leave a Reply

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

WordPress.com Logo

You are commenting using your WordPress.com 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 )

Google+ photo

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

Connecting to %s