I'm about halfway through Design Patterns: Elements of Reusable Object-Oriented Software, and it's pretty good. I can't read Smalltalk very well, so that's an impediment, but most of the code is C++ so it's OK. The book itself is very well-written. The patterns are laid out in a clear and thorough format, explaining pros and cons, giving good examples of when to use each pattern and when not to. The patterns are grouped by what purpose they're trying to serve, and similar patterns are compared / contrasted. The book sounds almost like it's trying to prove to the world that design patterns really are practical and relevant, which is amusing in hindsight because they obviously succeeded in doing so, at least among some large portion of programmers today. The "Lexi" example program used to introduce patterns in the first third of the book is pretty dated at this point, based on what looks like Motif and Windows 3.1 widgets etc., which isn't surprising given that this book is from 1994.? But the catalogs that come after are still very relevant and a joy to read.
I've been struggling with something in a Rails app I've been working on. It has to do with how to organize a hierarchy of parallel "model" classes. I had a sort of Eureka moment reading Design Patterns, when I realized one of the patterns is exactly what I need to solve this problem. That's always good. My original solution was a horrendous hack involving runtime editing of classes to inject methods into them, and it was entirely broken when pushed beyond a certain point.
For some reason I tend to overlook inheritance as a "decision-making" tool.? Saying "I'll take any object that implements this interface" or "I'll take any object of this class or its subclasses" is a nice open-ended yet well-structured way of implementing a conditional.? "When you give me an object, if the object meets these criteria (by nature of being of a certain type or implementing a certain interface), proceed, else fail immediately."? You let the compiler or interpreter do the work for you.? And if the object meets the criteria, you can use it while blindly assuming it'll work as expected.? I'm always muddling up my code and trying to juggle a million things at once and doing other classes' work for them in all the wrong places, instead of letting classes properly handle their own business independently.? I definitely have some bad programming habits that I'm trying to unlearn, with some success I think.? If nothing else, I have experience doing things the wrong way and clearly seeing how and why they're wrong and the price of being wrong, so hopefully in the future I can avoid the same mistakes.
So, the book is largely about design decisions.? Not just breaking a problem up into parts, but breaking them up into parts with the right granularity, and with the right relationship to other parts, and with the ability to be easily used in the future to solve other problems.? That's the hard part of programming, I guess: making those design decisions.? For me anyways, at this point.? The book is helpful in that regard.
It's interesting how so many of these patterns have little or no relevance to Ruby. For example, the Abstract Factory pattern. The book uses Smalltalk as an example of a language with classes that are themselves objects like any other objects; a language with class objects can just use the class objects themselves as factories. As the book says, a class object is already a factory: a factory that produces objects of a single sort. And produces them very nicely, for that matter.? But other patterns do apply to Ruby. Obviously it also depends somewhat on the specific problem you're trying to solve, but it's fun to try to think of which patterns might be more relevant than others given how different a language like Ruby is from a C++ or Java or what have you.