Sponsored Link •
Developers are often faced with decisions about how much flexibility to design into their software. In this interview, Erich Gamma, co-author of the landmark book, Design Patterns, talks with Bill Venners about the attitude he believes developers should adopt towards flexibility and reuse.
Erich Gamma lept onto the software world stage in 1995 as co-author of the best-selling book Design Patterns: Elements of Reusable Object-Oriented Software (Addison-Wesley, 1995) . This landmark work, often referred to as the Gang of Four (GoF) book, cataloged 23 specific solutions to common design problems. In 1998, he teamed up with Kent Beck to produce JUnit , the de facto unit testing tool in the Java community. Gamma currently is an IBM Distinguished Engineer at IBM's Object Technology International (OTI) lab in Zurich, Switzerland. He provides leadership in the Eclipse community, and is responsible for the Java development effort for the Eclipse platform .
On October 27, 2004, Bill Venners met with Erich Gamma at the OOPSLA conference in Vancouver, Canada. In this interview, which will be published in multiple installments in Leading-Edge Java on Artima Developer, Gamma gives insights into software design.
Bill Venners: The first sentence of the GoF book is, "Designing object-oriented software is hard, and designing reusable object-oriented software is even harder." How important is reusability?
Erich Gamma: Nobody ships applications today without reusing system level class libraries. Our environments are too complex to build applications without them. It is obvious that reuse is important, we just do it. An interesting question is whether there is a larger scale reuse than system level class libraries. When we started exploring frameworks years ago, we had big hopes for them. We thought the way to create software was to build high-level, domain-specific frameworks, and then you just customize them and reuse all the design that is codified into them. That was the reuse nirvana. Since then, I've gotten a little more realistic, because I have learned that it's hard to create highly reusable frameworks. They become complex, hard to learn, and even harder to maintain. I was on both the framework consumer and the framework producer side, and it can be hard from either perspective.
A key challenge in framework development is how to preserve stability over time. The more miles a framework gets the better you understand how you should have built it in the first place. Therefore you would like to tweak and improve it. However, since your framework is heavily used you are highly constrained in what you can change. At this point it is crucial to have well defined APIs and to make it clear to the clients what is published API and what internal code is. For published APIs you should commit to stability and for internal code you have the freedom to change it.A good example of how I like to see reuse at work is Eclipse. It's built of components we call plug-ins. A plug-in bundles your code and there is a separate manifest where you define which other plug-ins you extend and which points of extension your plug-in offers. Plug-ins provide reusable code following explicit conventions to separate API from internal code. The Eclipse component model is simple and consistent too. It has this kernel characteristic. Eclipse has a small kernel, and everything is done the same way via extension points. The combination of a component model and the focus on APIs is one of the key ingredients of Eclipse. Controlled extensibility is another important one.
Bill Venners: What do you mean by controlled extensibility?
Erich Gamma: The first object-oriented thing they told us was: OO is way cool. You can subclass and customize anything!" These days I consider this the attitude of object exhibitionists. You can go and expose everything, and people can change anything. The original Smalltalks had some of this flavor. The problems start when the next version comes along. If you have exposed everything, you cannot change anything or you break all your clients. That's why the component model, the API focus, designing what's internal and what's published, becomes so critical when it comes to reuse. Also when you study the Eclipse API you will find that we go further than just specifying which classes are published API. The Eclipse API also specifies whether a class is intended to be subclassed. A key lesson here is that API is not just a documented class. And, APIs don't just happen; they are a big investment.
The other important aspect of what we call controlled extensibility in the context of Eclipse plug-ins is extensions and extension points. An extension point defines where you can contribute to, and extend, a plug-in. An extension point has a name and comes with a specification that defines the interfaces you have to conform to when you make a contribution.. As a plug-in writer you are not done until you have also thought about the extension points your plug-in might offer.
Bill Venners: Define framework.
Erich Gamma: I see three levels of reuse. At the lowest level, you reuse classes:
class libraries, containers, maybe some class "teams" like container/iterator. Frameworks
are at the highest level. They really try to distill design. They identify the key
abstractions for solving a problem. They represent them by classes and define
relationships between them. JUnit is a small framework, for example. It is the "Hello,
world" of frameworks. You have
TestSuite and relationships defined. A framework is larger grained than
just a single class, typically. Also, you hook into frameworks by subclassing somewhere.
They use the so-called Hollywood principle of "don't call us, we'll call you." The
framework allows you to define your custom behavior, and it will call you back when it's
your turn to do something. Same with JUnit, right? It calls you back when it wants to
execute a test for you, but the rest is done in the framework.
Bill Venners: You said there were three levels of reuse?
Erich Gamma: Right, there also is a middle level. This is where I see patterns. Design patterns are both smaller and more abstract than frameworks. They're really a description about how a couple of classes can relate to each other and interact with each other. The level of reuse increases when you move from classes to patterns and finally frameworks.
What is nice about this middle layer is that patterns offer reuse in a way that is less risky than frameworks. Building a framework is high risk and a significant investment. Patterns allow you to reuse design ideas and concepts independent of concrete code.