The first, of course, is the famous Gang of Four book on design patterns. Almost every programmer has heard of it, and it is considered the definitive work on software patterns. The second is less well known, but provides great insights and is quite well-written and easy to read. Each of them stands on its own as a great book of design knowledge, but together they can really improve the way you approach software design. Let's take a look at each one and then see how they fit together.
Design Patterns: Elements of Reusable Object-Oriented Software
The basic premise of this book is that software design has a number of recurring patterns that can be systematically described and cataloged. Once you know the names of the patterns, you can easily discuss them without having to describe the design in detail, and other software engineers will know what you're talking about. Since these patterns come up again and again, there is no need to redesign them from scratch. The implementations given in the book can be applied to new designs to quickly solve common problems with known solutions. Convenient!
The bulk of the book is the catalog of 23 design patterns. The authors go through every aspect of each pattern from why you would use it, how to apply it, what are the advantages and disadvantages of it, and a concise example of it. It's all very methodical, but I really got into it. I was amazed at how many patterns applied to the code base I'm working on. Factory Method, Adapter, Facade, Command, and the infamous Singleton were all present, and learning about them greatly improved my understanding of the code I was working on. I could categorize entire sections of code based on the pattern used, and as a result, I had a much more organized picture of the code in my head.
I could also see where things could be improved. After reorganizing one set of classes into the Strategy pattern, I was able to easily extend it with a ton of new functionality that was just a bunch of additional strategies. The next thing I want to tackle is the state machine that currently manages the overall execution of the program. Right now it's a giant switch statement that's just crying out to be refactored into the State pattern. It would be so much more maintainable and understandable. I love books that are immediately applicable to what I'm working on.
Object-Oriented Design Heuristics
This book addresses object-oriented design from a different angle. Instead of categorizing design problems and solutions into a set of patterns, it lays out a set of heuristics to guide you while making the nitty-gritty choices that go into designing software. Since they're more what you'd call guidelines than actual rules, the heuristics can sometimes be contradictory, and intentionally so. Through the heuristics, Riel brings out the tension inherent in all design trade-offs in software engineering.
Bringing this tension to the forefront really helps crystallize your understanding of the reasoning behind design choices, and why you would make one choice in this situation, but take the opposite route if the requirements changed slightly. There are rarely definitive answers, only shades of gray. Sometimes it's better to encapsulate behavior into lower level classes. Other times doing so would make things messier because the necessary data is spread out among numerous classes. In that case it might be better to move that behavior up a level and just access the data from the lower-level classes.
I'm making decisions like these constantly while programming, and having a well-thought out set of heuristics is invaluable. I can see much more clearly what the design trade-offs are, and my designs are much cleaner and more elegant as a result. I certainly have a long way to go on improving as a programmer, but this book has helped me suck less in the last year.
Putting Them Together
How do these books complement each other? They attack software design from different angles. Design Patterns gives you a collection of patterns to choose from when you're trying to organize a program at a higher level, either when doing the architectural design, or more likely when refactoring after you actually know how the program works and fits together. On the other hand, Object-Oriented Design Heuristics gives you a collection of heuristics to use when deciding where to put this data or that function, and is incredibly useful while actually writing code.
Patterns help organize in larger chunks while heuristics help refine and massage the design at a finer level of detail. Their interplay is similar to how a house is constructed. The patterns would be like the foundation and frame of the house. They provide its structure and support, and the rest of the house hangs on that structure. The heuristics are like the fit and finish of the house. The shelving, trim, paint, and floor coverings that give the house its look and feel. They're both necessary, and when they're both done right, you have a beautiful, functional home.
So how do you build a better house? Reading about these patterns and heuristics isn't enough. You have to put them into practice to really understand them and see how they work. The examples in the book are nice and clean and well thought out, but they likely won't transfer exactly into your own designs. Don't be afraid to experiment and see how they can be implemented in your own projects. At the same time, don't try to force them into a design that doesn't really need it. Patterns especially can be overused and abused if you're not careful, so don't over-engineer. Simpler is almost always better. If a particular pattern doesn't provide the benefits necessary to outweigh its complexity, use a simpler pattern or none at all. How will you know? The only way to find out is to give it a try.