Sponsored Link •
Bill Venners: In an article you wrote with Kent Beck, called "JUnit: A Cook's Tour," [see Resources] you walk the reader through the design of JUnit by, as you wrote, "starting with nothing and applying patterns, one after another, until you have the architecture of the system." I thought perhaps this approach may be inspired by Christopher Alexander, whose work on patterns in architecture inspired the software patterns movement. Do you feel that layering one pattern on top of another until you're done is an effective way to design?
Erich Gamma: The Cook's tour is kind of synthetic. We reconstructed the design we did on JUnit. However, we didn't develop JUnit in such a pattern driven way, instead we did it in a strict test-driven way. What is true in JUnit is that there is a core abstraction for a test, and around that core abstraction you see several other design points emerge, which in turn are materialized by pattern instances. That's something you can often observe in mature designs. There are some key abstractions you often see as a design center, and around those key abstractions you want to achieve various things. So you see patterns growing out of such a center. But I wouldn't use this as quality criteria.
Bill Venners: Is that what you're referring to when you say, "pattern density?"
Erich Gamma: Yes, exactly, patterns popping-up around some central abstraction.
Bill Venners: You said
TestCase is the core abstraction in JUnit.
Erich Gamma: Actually it is the
Test interface which is implemented
TestCase, but yes we started with
TestCase and expanded from there.
Bill Venners: And then, could you define density? The number of patterns around it? You said the JUnit Cook's Tour was kind of synthetic.
Erich Gamma: Synthetic in the sense that the cooks tour is what is left over when you strip
out all the test activity that happened during our test-driven development. Therefore it is a very
compressed presentation. The density shows up in the patterns codified around
We didn't just string patterns together when we designed JUnit. We did it test-driven, starting with a test that we wanted to succeed and once it passed we looked into how we could improve the code. Developing a test framework in test-driven way isn't without its challenges, but once you have the basics working it goes surprisingly smoothly. You see, Kent and I were fluent in patterns when we designed JUnit. So of course, we'd say things like, "Hey, that's composite." Composite is a pattern in JUnit. We also use template method. That's a basic one. We have command. This is of course a key one. We started with test and said, "Oh, this is a command. Oh, this is a template." Because we were fluent in patterns, our conversation was going really fast, enabling a high-velocity design.
This actually illustrates nicely how patterns provide us with design vocabulary. Similarly when you look at a UML diagram, then you see boxes and arrows, but they don't really tell you the meaning behind these relationships. But once you know the pattern then it explains what these relationships are about. If it's observer, it's really clear why there is a link between these two classes. It's because this guy observes that guy. You know exactly what's going on. And I guess that's the key point. Patterns give us a language to talk about design. Actually, the JUnit journey isn't over yet and Kent and I are currently working on JUnit 4. We are continuing to evolve JUnit in a test-driven way. One of our themes is to lower the barriers to entry. To do so we are leveraging J2SE 5 features like annotations to make JUnit easier to use.