Monday, February 21, 2005

Variations on TDD

TDD is the cornerstone of XP. TDD requires one to write tests ahead of code. The basics of TDD are laid out in books by Kent Beck (Test Driven Development By Example) and others. However, as time has gone by and XP has evolved, it appears as though different ideas about how to write code test-first have emerged, all claiming to be TDD. Since I am a strong advocate of XP and TDD, I thought I'd lay out some of these variations I've seen in the wild:

  1. Traditional TDD: Development is done one simple test at a time. Refactoring is applied frequently at a small scale. One starts with an intentionally naive design and allows the addition of new tests to guide the evolving design to greater levels of complexity. One can do some up front thinking about a problem, including brainstorming, using diagrams or crc cards, but the focus is to keep the design as simple as possible with each new test
  2. Proactive TDD: Proactive TDD is similar to traditional TDD in that one uses small-scale tests. However, one generally develops a fairly established design ahead of time and the tests are written to realize that design. This approach is less flexible than traditional TDD, but the feedback cycle is still short and provides the opportunity to re-think the design if it looks as though it is going in the wrong direction.
  3. End-To-End TDD: In this variation, one does not write small-scale tests. Instead one starts off working with what are essentially acceptance tests: High level tests that cover the execution of code for a story or a substantial part of a story. Such tests may use something like the FIT framework or they may involve calling a high level API inside of xUnit. To make one test pass, quite a bit of code must be written through all the layers of the application. The presumed goal of this approach is to avoid having to modify many small tests as the application logic changes. The drawback is that this is not really a good design technique since one cannot apply a short test-code-refactor cycle. Overall I would say this approach discourages frequent refactoring and leads to low quality code. If one does decide use this approach, In my opinion one should be prepared to do a lot of careful design up front.
  4. Mock-Driven Development: I am unfamiliar with this approach, but there appears to be a school of developers who produce even more granular tests with the extensive use of mock objects. The sense I get is that this kind of development is perhaps more similar to Design By Contract and ties tests very closely to the implementation details of an API. So far I can't evaluate this method, but I have to admit that I am biased in favour of testing state before and after a test rather than worrying about the actual calls made.
Based on my experience thus far, I consider Traditional TDD to be the best approach in most cases and Proactive TDD to be acceptable in some cases. I believe that all in all traditional TDD minimizes the risk of ending up with unmanageable code. While I am a strong supporter of acceptance tests, I believe that all application code should be developed using a short test-code-refactor cycle, and therefore one should use traditional TDD techniques to write the code that will eventually make the acceptance test pass. Without the traditional TDD, one loses the ability to frequently refactor the code in small chunks and to get a good sense of its overall effect on the design.

Monday, February 14, 2005

Appropriate Metaphor For Software Engineering

Jeanette Winterson is one of my favourite writers, especially her novel The Passion. This is from the monthly column she writes for her Web site:
My friend Mona Howard, who is 84, told me she had been to see the film Touching The Void, about the mountaineers, one of whom makes an incredible survival journey with a broken leg. He got through it by setting himself only what he could achieve without agony giving way to despair. So he would hop for twenty minutes, then rest, then hop again.

Saturday, February 12, 2005

What makes a successful XP team?

I've recently had the experience of working with a productive team and I thought I'd share the characteristics that I believe were important to its success at delivering on time with a low defect rate:
  • Avoid politics: Everyone on the team was always thinking of ways to improve the quality of the product and the code. There was no sense that people were motivated because they were trying to impress a boss.

  • Do not over-engineer: The focus was on getting results, not on stroking one's ego or on doing software engineering for its own sake. All too often in the OO world, I see over-engineered code that seems to be developed out of some desire to be clever or to copy something from a book.

  • Remain critical: There was a strong desire to root out problems in the design. In other words developers did not fall in love with their designs, regarded the code critically, and were eager to make changes to improve it.

  • Allow some slack: Developers were able to negotiate periods of time to focus on cleaning up the design of the application rather than pushing forward with user stories. Sometimes it is necessary to go in and thoroughly clean up, especially when dealing with a legacy codebase.

  • Maintain discipline: Discipline and focus was very good. Planning was done in 2 week sprints and people were not getting constantly interrupted during a sprint. One could count on the estimates provided for stories.

  • Have a separate QA group: A separate QA group producing automated end-to-end tests was very useful. Together, the end-to-end tests produced by QA and the more granular tests produced by the developers provided a high degree of confidence in the code and allowed fairly significant refactorings to be done.

  • Promote a team culture: Developers maintained high morale by taking an easy-going approach to the project, even at times of high pressure. On our team, the developers and QA people played video games at lunch and during the last half-hour of the day. Any kind of activity along these lines promotes a sense of team-identity. Whatever it might be, it is a good idea to come up with something non-work related the team can do together on a regular basis.