At their March 25 SD West tutorial, “Evolutionary Design with Java, Testing,
Refactoring and Patterns,” Joshua Kerievsy and Russ Rufer, Extreme Programming Coaches at
Industrial Logic, stirred a potent soup. Urging attendees to develop only what needs to be done at the moment,
leaving the rest as stubs to be filled in later, Kerievsky also touted frequent
testing, with continuous refactoring and integration to up the ante. But quantity
bows to quality: “It’s not about writing tests; it’s about
writing good tests,” he specified.
Rufer added that test-driven development “allows programmers to be more
daring … trying things that you’d never try without a suite of tests
to act as your safety net.”
He acknowledged, however, that the test-driven approach is a huge paradigm switch
that isn’t easy to make. When asked how long it took for him to be convinced,
Rufer said that he'd been practicing Evolutionary Design since 1998,
but had been convinced of the current test cycle style only last
year.
The Forest for the Trees
Striving for design simplicity, Kerievsky claimed, is another useful factor
for reducing risk, noting that if you find yourself saying “It can’t
be this hard,” something’s wrong, and you should retrace your steps
and match the complexity of the solution to the complexity of the problem. An
attendee described standing in front of an orchard and seeing only a random,
mindless jumble of trees; then suddenly perceiving the order of the grove spring
into evidence when he stepped to the side. Stepping back, Kerievsky explained,
reveals another, simpler solution to the problem. Backtracking not only helps
you to consider other alternatives, it allows you to rewrite, aggressively refactor
and prune any dead code.
Studying, living and breathing code is at the heart of evolutionary design: Developers should devote maximum attention to improving the code—evolving it from a rudimentary system that, though primitive, provides end-to-end functionality—what Kerievsky and Rufer call spanning the system. This simple working application is a thin, vertical slice of the project that offers insight into both essential and unnecessary features. Kerievsky and Rufer asked Mary Poppendieck, fellow conference speaker and author of Lean Software Development: An Agile Toolkit (Addison-Wesley, in press), to offer an example: “Say you’re going to implement a hotel reservation system; you might first implement a program that reserves just one room before developing the whole system.” These small iterations can be viewed as embryonic versions of the system, and can be taken to the customer for feedback. SD contributing editor Rick Wayne noted that this is the antithesis of RAD—instead of throwing your code away, you evolve it.
Evolutionary design also enables developers to consider a multiplicity of design and selection, like the photographer who takes 10 rolls of film to find the perfect shot. To supplement this “survival of the fittest” technique, Kerievsky and Rufer also stressed the practice of dead reckoning—navigating without explicit instructions by heading in roughly the right direction and using feedback to make adjustments and to motivate backtracking.
To effectively illustrate evolutionary principles with the test-driven approach, Kerievsky and Rufer used JUnit to analyze a simple blackjack problem. To span the system, they chose just one case with two known hands and incrementally built the system to accommodate the full deck. The process elicited much audience interaction, as several attendees pondered how to implement the approach in the real world, and reveal the challenges of making the leap to a test-driven approach. According to Kerievsky, this approach works best in small teams or networks of small teams.