Rod Waldhoff's Weblog  

< Tuesday, 1 July 2003 >
Re: Test Driven Development versus Component Reuse #

Over on the Software Craftsmen blog, Mike Hogan asks what is meant by "the simplest thing that could possibly work". For what it's worth, Beck actually addresses this point directly in Extreme Programming Explained [ISBN:0201616416]:

Here is what I mean by simplest--four constraints, in priority order:

  1. The system (code and tests together) must communicate everything you want to communicate.
  2. The system must contain no duplicate code. (1 and 2 together constitute the Once and Only Once Rule).
  3. The system should have the fewest possible classes.
  4. The system should have the fewest possible methods.
[...]

If you view the design as a communication medium, then you will have objects or methods for every important concept. You will choose the names of the classes and methods to work together.

I have my own issues with that definition that I hope to pick up in a later post. (For starters, define "everything you want to communicate".)

Mike goes on to question whether there are times when TSTTCPW conflicts with design for reuse.

I think this misses the test first aspect. Consider approaching the Grep example test first. A small set of tests that might lead to the first Grep implementation is:

static final String TEXT = "This is\na simple test";
Grep grep = null;
BufferedReader reader = null;
 
void setUp() {
  grep = new Grep();
  reader = new BufferedReader(new StringReader(TEXT));
}
 
void testDoesContain() {
  assertTrue(grep.contains(reader,"is");
}
 
void testDoesNotContain() {
  assertFalse(grep.contains(reader,"is not");
}
 
void testPatternsSplitAcrossMultipleLinesAreNotFound() {
  assertFalse(grep.contains(reader,"is*a");
}

Mike asserts that the Grep implementation would be more useful if it could interoperate with multiple regular expression frameworks, and provides an example "Inversion of Control" approach for doing so. Want to make that Grep implementation work with multiple regular expression frameworks? Great. First, write a test that fails:

void testGrepWithJakartaRegexp() {
   RegexpProvider rep = new RegexpRegexpProvider();
   ReusableGrep grep = new ReusableGrep(rep);
   assertTrue(grep.contains(reader,"is");
   assertFalse(grep.contains(reader,"is not");
}
 
void testGrepWithJakartaOro() {
   RegexpProvider rep = new OroRegexpProvider();
   ReusableGrep grep = new ReusableGrep(rep);
   assertTrue(grep.contains(reader,"is");
   assertFalse(grep.contains(reader,"is not");
}

(Alternatively, (1) define a "mock" instance of RegexpProvider for the purpose of this test rather than using specific implementations and (2) define an abstract getRegexpProvider method in your test class, an implement these tests as concrete extensions of that abstract test case, but I digress.)

Now we can justify the creation of the RegexpProvider interface, and ReusableGrep still meets the "simplest" criteria. (Ignoring that ORO and Regexp likely support slightly different syntaxes.)

I think Mike's first instinct--simple is "the smallest amount of code" that will "get the test case[s] running and refuses to concern itself with any potential future requirement" is the right one. Have additional requirements you'd like to assert? Then express them as tests and this simple rule allows you to support them. When approaching development test first I think a lot these questions about "what is simple" simply fade away, as does much premature generalization. (And I say that without taking a position on whether ReusableGrep represents premature generalization or not. I recognize that it's meant as a trivial example.)

PS: I can't resist the tempation to plug a commons-functor approach to this Grep implementation. How about something like:

Lines.from(reader).contains(RegexpMatch.of("my expression"))

Re: "Test First Design With UML" and who's recepetive to test first development #

I ran across David Hussman's "Test First Design With UML" in a list of bookmarks, though I'm not sure where I picked it up originally (likely another blog, I suppose).

This brief (two page) but interesting paper had two points I found especially worthy of note:

First, Hussman suggests that every story card be accompanied by a sequence ("lollipop") diagram, right on the back of the card (and further suggests a protocol for implementing that card using that diagram). As a frequent but informal user of sequence diagrams, I find this idea appealing.

Second, Huffman makes this incidental comment:

"I think that most developers that have gravitated toward test first design, have done so because it matched (or formalized) their development habits."

I find that a rather insightful statement, and I wonder what it means to those of us who'd like to convince developers to whom test first doesn't come naturally to follow this approach. (Cf. this post, its comment thread, and others.)