Just wrapped up a book club on Head First Design Patterns (HFDP). Here’s a summary of what I shared at our Lightning Talks.
I read the “Gang of Four” (GoF) book, “Design Patterns: Elements of Reusable Object-Oriented Software“, in the early 2000s. That was a tough read for me; very dense, and hard to relate to. Good book, but not what I needed at the time.
Then ran into the 1st edition of HFDP in 2005:
I loved the way the book taught the concepts, using a good mix of analogies with real-world things I can immediately relate to, principles, and some code in between. I’ve been recommending that book to whoever asked, and wanted to revisit it to see how well it aged.
For the book club, we picked up the 2nd edition, published in 2021:
As with the 1st edition, all the source code is Java, which I’ve never worked with. But that doesn’t matter because the code is there only to give examples of the concepts (the most important thing) explained. The knowledge acquired is transferrable.
With that said, there was one chapter that I think spent too much time explaining some very specific aspects of Java, but that didn’t affect my enjoyment of the book, as I could visualize its counterpart in .NET. I do see that section being a little harder to grasp for developers who may solely focus on the frontend, though.
Going through the book this 2nd time, I realized that when I read it the first time I still didn’t know about the SOLID principles; that I learned a couple of years later. This time, I noticed I was anticipating where they were going with some explanation, and eventually, they’d drop in things like “Dependency Inversion Principle”. While the book calls out DIP, it never mentions SOLID. I can’t recall if the 1st edition mentioned anything related to SOLID at all. Anyway, I enjoy learning in a spiral, and it was good to revisit the content from this perspective of having acquired more knowledge and experiences over the years.
Speaking of experiences, the book club had a good mix of previous experiences; some members already had a lot, others were just getting started, some had more experience with backend than frontend development, some had more with functional programming than object-oriented programming languages. It all added to our having great conversations.
Here are some of my key takeaways…
The book does a good job at sharing not just patterns, but also principles, which help us understand better why certain patterns exist. Here are a few examples of principles that were brought up:
Program to an interface, not an implementation
That’s the D in SOLID: Dependency Inversion Principle, or DIP, already mentioned earlier.
Favor composition over inheritance
I first learned OOP in Visual FoxPro in a very inheritance-heavy way. It took me a while to understand and internalize why I should favor composition over inheritance.
This is what made the lightbulb go off for me:
Swapping behaviors with inheritance is done at compile time.
Swapping behaviors with composition is done at run time.
There are other things to consider, such as composition making it easier to follow the Single Responsibility Principle, but understanding the power it brings to run time behavior is huge.
Principle of Least Knowledge
Aka Law of Demeter, I kind of like Principle of Least Knowledge better.
For a common example, let’s try this one:
The code above doesn’t do things to the cart; it does to the cart’s Items property. Is that a list, a collection, or what? That’s excessive information. How about this version, instead?
That way, the code only knows of the cart and it adds a product to it; how it stores the items is none of our business.
A simplistic way to think about it: too many dots reaching into an object means bad!
The book covers one pattern per chapter, including Strategy, Observer, Decorator, Factory, and Command.
There’s a chapter on Compound Patterns, more specifically, Model-View-Controller (MVC). That one mentions other patterns that are often part of MVC: decorator, adapter, abstract factory, observer, strategy, composite, and iterator.
The very last chapter lists “leftover” patterns (about 10 of them). What was interesting to me is that there are a few patterns that would probably not be considered leftovers if the book was focused on .NET, such as Mediator, Builder, and Chain of Responsibility.
OOP vs FP
I’ve been seeing a number of people putting OOP down in favor of Functional Programming, steering away from content on design patterns because “that’s what the old folks do”. Why not leverage both?
Take as an example this snippet that uses the Command pattern:
That’s the OO way of implementing it, with classes, methods, and interfaces. Since the Do method takes in an ICommand interface, that parameter could also be wrapped in a decorator(s) or adapter, implemented as different strategies or created by factories, etc.
One could argue that if the ICommand interface only has one method, Execute, it could be replaced by a function, represented in the snippet below as an Action:
Action is a delegate, which in C# is an object that represents a reference to a method (or function). Those can also be created by factories, wrapped in decorators, etc. So we’re in OO land, but approaching it with a functional perspective.
When working in functional languages, one can also leverage knowing design patterns, and their intent, and then consider whether they’d be appropriate in solving a problem there. Concepts such as commands, adapters, proxies, and factories, are out there and may come in handy, regardless of language, syntax, you name it.
Patterns in life
I like how the book uses things from life, such as restaurant menus and TV remotes, to explain the concepts.
It’s a fun exercise to look at other things around us and how they relate to some patterns.
Take this image as an example:
The plug and the outlet work together based on agreed interfaces; the outlet sees the plug, and the plug sees the outlet.
What if we want to put a timer to shut off the outlet after a certain time? We use something like this…
Or we could also use something like this:
Heck, we could even use both. The plug and the outlet wouldn’t care; they wouldn’t even know those decorators were there.
What if the plug and the outlet conform to different interfaces (standards)? We use an adapter (but we can also still use those decorators)!
I really like how the book defines anti-patterns:
An Anti-Pattern tells you how to go from a problem to a BAD solution.
One of the main reasons to learn design patterns is to build a shared vocabulary; we can condense full sentences, paragraphs, and long explanations, down to a single word. That is, as long as everybody in the room knows what that pattern is! If people aren’t familiar with it, that’s an opportunity to learn and grow together.
I like the book’s list of great places to leverage the shared vocabulary:
- In design meetings
- With other developers
- In architecture documentation
- In code comments and naming conventions
- To groups of interested developers
Zen mind is a Beginner mind
Do not let all that pattern knowledge overly influence design decisions.
Yup, always go with the simplest solution. Let patterns emerge.