This 2008 book on Design Patterns covers what they are, how to write them in Ruby, why (or not) to use them, and where you can find common applications of them in the Ruby world. If you’re an experienced programmer new to Ruby, or a Ruby programmer interested in Design Patterns, I highly recommend it.

I spotted Design Patterns in Ruby one day on O’Reilly Learning when GoF and the blog posts didn’t give me enough to implement a pattern that I thought was relevant… in Ruby. I thought it was just going to be a dip in and out, but the book really grabbed me.

What are Design Patterns?

For the uninitiated, Design Patterns (in software) are a set of well-understood solutions to common problems. An algorithm with a lot of steps in common but one part that varies could be handled by the Template Method pattern, or complicated object construction scattered in many places could be encapsulated in a Builder. Normally they’re described as code you would add and how it connects to the code you already have.

They’re well thought-out solutions, but also great for establishing dialogue between programmers: “That thing over there sounds like it’s too expensive to load every time, what about using a Proxy?”

As with all other discussions of patterns, I’m obligated to give you the completely useless fact that “Design Patterns” as a proper noun was coined by a fellow called Christopher Alexander in some books about architecture (buildings, not software). No-one who tells you that has ever read those books, apart from my former colleague Wilhelm Kirschbaum. No. One.

In software their use originates with a book called Design Patterns: Elements of Reusable Object-Oriented Software, known as the Gang of Four book (GoF for short) because it has four authors. That book does its examples in Smalltalk and C++, and of course there are numerous follow ups for other languages by various authors, including this one.

My journey with patterns

(this part does not have much to do with the book - skip to the next section if that’s all you’re here for)

Design Patterns have been a Thing I Should Know About since before I started working. At University they were hinted at in software engineering courses, and I did some vac work for someone who taught a whole course on them in Java. Strangely, when I started working, the experienced programmers around me weren’t that interested, and I had my head full just learning all of the things that are new when you start working as a Java programmer: persistence and so many web frameworks and dependency injection containers and and and…

Two other things happened that derailed my learning on the topic:

First, I started reading Hacker News where everyone was complaining about the overuse of patterns with jokes about people who write classes named FactoryAdapterProxyBuilderImpl. It turns out Design Patterns are notoriously overused by programmers who just want to try something new.

Second, I adopted a copy of the GoF book when the late Ken McGregor retired at UCT and cleaned out his office. You’d think that this would be a positive step, but the problem was that I started reading it.

Less flippantly, the examples in GoF are often related to topics that were distant to me (e.g. desktop GUIs written in C++ and Smalltalk). Also I foolishly started with random chapters: Observer seemed like a cool idea, as did the Command Pattern, but these are far from the simplest topics.

If I’d started with the Template Method pattern, I would have realised that I’d already used it on my very first professional programming project ever. I wrote some reporting logic that was mostly identical except for the data that was passed in, so I used an abstract method that was implemented by every subclass of my Report class. I would also have learned about how to handle the problem that doing everything with inheritance was inevitably going to break down as more and more change occurred.

In any case, I meandered along, occasionally dipping into GoF or some blog posts as a reference, building an implicit understanding and enough knowledge to have a (boring) cocktail conversation. Jokes on them, I don’t drink cocktails anyway.

Finally, I spotted Design Patterns in Ruby one day on O’Reilly Learning when GoF and the blog posts didn’t give me enough to implement a pattern that I thought was relevant… in Ruby. I thought it was just going to be a dip in and out, but the book really grabbed me.

Surprisingly up to date

For a 2007 book, the examples are astonishingly relevant. This has a lot to do with it being recent enough to be on the web development train (so no desktop GUIs). Another factor is the dominance of Rails in the Ruby world, so all of the examples are relatable to pretty much every Ruby programmer: ActiveRecord migrations are an exampe of the Command pattern, ActiveRecord manages to give a database agnostic connection to multiple database with an implementation of Adapter, etc.

The thing that is slightly out of date is that Ruby in 2007 was a bit different to how it is now, but I can only think of one glaring example: apparently [] on a String used to return ascii numbers instead of character objects. Who knew?

Easier and more practical (for Ruby Programmers) than GoF

The writing is very simple and pleasant to read, so much so that it almost feels a little insulting compared to how much work other technical books require.

Every chapter covers the same elements in the same order: how the pattern was originally described (its purpose and class diagram without Ruby magic); how to implement it in Ruby (crucial: Ruby’s blocks and duck typing make a lot of things easier); things to pay attention to; how not to use the pattern (also crucial); and examples in the Ruby world.

This structure is really engaging. ActiveRecord? Why, I use ActiveRecord! I’ve been using code that implements that pattern and I didn’t even know it!

Bonus chapters for Ruby’s specialities

The book also includes three chapters on techniques that are not typically discussed in the Design Patterns conversation, but Olsen sticks with the structure of the rest of the book: DSLs, metaprogramming, and convention over configuration. These are all very visible in the Rails code and are a helpful guide to things that Ruby is particularly good at. These topics are all interwoven, since of course metaprogramming helps us to write DSLs and build frameworks using convention over configuration.

The value of patterns

I’ve mentioned a few times that Rails implements various patterns, and so as Rails programmers we are standing on top of not just Rails, but also the GoF. The same is true for every other framework that developers use, trivially so in the case of all the frameworks that borrowed heavily from Rails: Play (Java/Scala), Django (Python), Laravel (PHP) etc.

I think that understanding the patterns at the bottom will make us better at the job of programming, and able to translate knowledge from one situation to the next.

A danger is that programmers think that the only place where patterns are applicable are in framework code. If we think their usefulness ends there, we may not consider how to structure the rest of our code.

In a world where people write thousands of lines of code in Rails models, lib folder, or controllers, there is a lot of code that is not conveniently written for you in a framework. If you think about it, if your business needs could be met without lots of code that isn’t in the framework, everyone who installed Rails would instantly be a competitor.

Code that is not framework code is also the code that changes the most, so you need something to help you structure it well. Design Patterns (when used and not abused) are one strong option for this. (But don’t overuse them for simple things!)

Two audiences: new to patterns, or coming from another language

If you’re an experienced programmer new to Ruby, or a Ruby programmer interested in Design Patterns, I highly recommend the book.

My understanding of the patterns covered has been solidified, and I now have some new ways to understand the source code of the various Open Source frameworks I use.

Since the topics are universal to OO, I’d also recommend this as a starting point to say a Python or Java programmer (especially the latter) who wants to see The Ruby Way of applying familiar problems.