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) [1]. 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 [2], 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 [3].
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: My first real insight into object-oriented programming came from reading Scott Meyers' Effective C++. In that book he has a guideline that says, "Make sure public inheritance models 'is-a.'" That guideline helped me truly understand inheritance for the first time. However, a later Effective C++ guideline says, "Model 'has-a' or 'is-implemented-in-terms-of' through composition." That guideline didn't help me as much to figure out what to do with composition.
In the GoF book, however, I found several more concrete prescriptions for using composition. GoF talks about using composition to model relationships like "adapts-a," "proxies-a," and "decorates-a." If you just look at the UML diagrams in GoF, a lot of them look similar. Most of them use composition with interface inheritance. Where the patterns differ is in the problem you are trying to solve with those composition and inheritance relationships. Even though the class diagram might look similar, the design intent is different. What is the role of intent in design patterns?
Erich Gamma: A pattern is always a problem-solution pair that can be applied in a particular context. Although the solutions might look similar in different patterns, the problems they are solving are different. In fact from ten thousand meters most patterns solve a problem by adding a level of indirection. What is interesting is how this indirection comes about and in particular why it needs to happen. Therefore if you just look at the solution to the problem, it isn't that enlightening and everything starts to look the same. When we wrote design patterns we often had this feeling—they all started to look like the Strategy pattern.
Initially we described only solutions. We had an initial catalogue of about 20 pages. Experienced developers had no problem understanding what we were up to and they rewarded us with comments like, "Yes, I've done that." However, we noticed that the rest had a hard time to get it at all. We showed different flavors of indirection. We showed a delegation. But basically we had a solution looking for a problem. Alexander's [4] view on patterns combined with the feedback from early readers helped us to not only focus on the solution but also on the problem part. A pattern has a problem and a solution, and you need to see both. For example, strategy and state have the same solution: you delegate to a separate object, and use a class hierarchy of objects conforming to an interface to vary behavior. But the problem is different. Strategy is about plugging in an algorithm, and state is about changing behavior when a class's state changes, as in a state machine.
Bill Venners: In the GoF book, you say, "Knowing the design patterns in this book makes it easier to understand existing systems." How?
Erich Gamma: You can explain an existing system with patterns way more compactly than without. Patterns help you compress a dialogue about design. A good example is what Kent Beck and I did in the last section of our Eclipse book [5]. We described some of the Eclipse designs with patterns. It was really amazing how compact you can get. You can say, "that's a composite." You don't have to say much more about it. People know what it is.
What's interesting is that we did this pattern analysis on an earlier version of Eclipse, and the analysis is still correct for the latest version. So while the screenshots are out of the date the patterns we identified are still up to date.
Once you understand that the system is using a certain set of patterns, and you know that those patterns have certain limitations and liabilities, you're in a better position to understand the intent of the developer that came up with the solution. The pattern tells you about the intent but also about the tradeoffs. Once you know the limitation of a design, you're in a better position to be a good citizen of say a reusable design like a framework. One of the worst things that can happen is that you start to fighting against a design, because you didn't really understand what it was, not honoring its intent and you start sounding a little like Frank Sinatra "I'll do it my way".
Bill Venners: You just said that patterns tell us about tradeoffs. What do you mean by that?
Erich Gamma: Design is always about tradeoffs. There are alternatives and each alternative has different consequences. When I design, I always make decisions. And each decision has advantages and disadvantages. That was also an important lesson we had learned when we wrote Design Patterns. Initially we were so excited about the patterns; we only saw the positive effects. It took some time until readers pointed out that this isn't realistic. So we made another pass, and also discussed the liabilities. At this point we also learned that identifying a pattern is much simpler than actually writing it. So here is an example: you have just added the Strategy pattern, and you have more flexibility. But the tradeoff is that you now have more objects and an additional level of indirection. Right? Everything has a price in engineering. That's what I mean by tradeoff. One of the key values of a pattern is that it captures these tradeoffs so that you don't have to do the analysis again. When you're walking along in a design flow, a pattern can act as a signpost. If you go this way, then you know that this is the tradeoff. I think this is highly valuable.
Bill Venners: In the GoF book you and your coauthors say, "Knowing these design patterns can make you a better designer." How? Don't I still need to know when to apply them?
Erich Gamma: Yes, do not turn off the brain; your creativity is still required. It isn't always clear when to apply a design pattern. In addition you also need to know which variation of a pattern to apply, and how to tweak the pattern. You always need to adapt a pattern to your particular problem.
This might be a good spot for a little confession about Design Patterns—in the book we only tell when to apply a pattern, but we never talk about when to remove a pattern. Removing a pattern can simplify a system and a simple solution should almost always win. Coming up with simple solutions is the real challenge.
Bill Venners: A lot of people want to become a better designer, and they want to go to this book to help them get there, but just reading the book doesn't...
Erich Gamma: ...doesn't make a better designer. I agree. Learning patterns—and even more important, design—from reading books just doesn't work. And, these days there are also several other interesting pattern books, so don't stop pattern reading after the GoF book.
Bill Venners: What does make them a better designer? What do they need to do?
Erich Gamma: In addition to reading books, you need to read and understand lots of code, see how existing systems solve a particular problem and what experienced designers did. Basically what design patterns do is to tell you what these developers have done. But, just reading about it isn't enough. You become a master by mimicking the work of excellent developers. There are many interesting open source projects available that can serve as interesting reading material. Eclipse is just one of them. It also doesn't hurt to contribute to an open source project. Not only do you learn about a particular development process you will also learn how to communicate about a design in a group of developers. As a good designer you not only come up with good designs you also communicate and defend them. You have to practice, like an apprentice in a way. Over time you'll become as experienced as experienced designers.
Bill Venners: In the GoF book, you write, "It is easiest to see a pattern as a solution, as a technique that can be adapted and reused. It is harder to see when it is appropriate—to characterize the problems it solves and the context in which it's the best solution." How do new designers figure out that. Let's say they go through the book, and they understand the patterns. Now they've got to do their job. How do they learn to know when it is appropriate to use a pattern versus when they are succumbing to the "patternitis" disease of trying to use as many patterns as possible?
Erich Gamma: Unfortunately, a lot of this you only learn later on in the game, once you can look back on what you did—with experienced eyes. If I were a new developer, I'd want to have a mentor or buddy. I'd program with them, and then the mentor would say, "Ping, now this is really ugly," or "oops, you have just expressed the same again that you expressed over there" . The mentor provides immediate feedback and provides pointers to dig deeper. This is just one flavor of pair programming. It's also an excellent way to improve your skills. I always learn something from a pair programming session and I wish I would do it more often.
Bottom line is that you learn patterns by programming. And, not just toy examples; real life examples. But no, you cannot learn patterns just from reading a book. With just a book you might not initially understand them fully. Once you start applying a pattern to one of your own programming problems, you start to understand it a lot better and are ready for the next
Come back Monday, June 13th for the next installment of this conversation with Erich Gamma. If you'd like to receive a brief weekly email announcing new articles at Artima Developer, please subscribe to the Artima Newsletter.
[1] Erich Gamma is co-author of Design Patterns: Elements of Reusable Object-Oriented Software, which is available on Amazon.com at:
http://www.amazon.com/exec/obidos/ASIN/0201633612/
[2] Erich Gamma is co-creator of JUnit, the defacto standard Java unit testing tool:
http://www.junit.org/index.htm
[3] Erich Gamma leads the Java development effort for the Eclipse tool platform:
http://www.eclipse.org/
[4] Christopher Alexander described architectural patterns in works such as, A Timeless Way of Building. Oxford University Press, 1979, available on Amazon.com at:
http://www.amazon.com/exec/obidos/ASIN/0195024028/
[5] Contributing to Eclipse: Principles, Patterns, and Plug-Ins, by Erich Gamma and Kent Beck, is available on Amazon.com at:
http://www.amazon.com/exec/obidos/ASIN/0321205758/
Have an opinion? Readers have already posted 3 comments about this article. Why not add yours?
Bill Venners is president of Artima Software, Inc. and editor-in-chief of Artima Developer. He is author of the book, Inside the Java Virtual Machine, a programmer-oriented survey of the Java platform's architecture and internals. His popular columns in JavaWorld magazine covered Java internals, object-oriented design, and Jini. Bill has been active in the Jini Community since its inception. He led the Jini Community's ServiceUI project, whose ServiceUI API became the de facto standard way to associate user interfaces to Jini services. Bill also serves as an elected member of the Jini Community's initial Technical Oversight Committee (TOC), and in this role helped to define the governance process for the community. He now edits the brand new magazine, Leading-Edge Java.
Artima provides consulting and training services to help you make the most of Scala, reactive
and functional programming, enterprise systems, big data, and testing.