In the past week, I read a couple of posts that made me really want to respond with a coherent explanation of how I build modular Ruby code.

The first post, by Nick Kallen of Twitter, gushed about the benefits of PerQueryTimingOutQueryFactory and called out Ruby (and a slew of other "hipster" languages) for using language features (like my "favorite" alias_method_chain ) and leveraging dynamicism to solve problems that he argues are more appropriately solved with laugh-inducing pattern names:

In a very dynamic language like Ruby, open classes and method aliasing (e.g., alias_method_chain) mitigate this problem, but they don’t solve it. If you manipulate a class to add logging, all instances of that class will have logging; you can’t take a surgical approach and say “just objects instantiated in this context”.

If you haven't read it yet, you should probably read it now (at least skim it).

As if on cue, a post by Pivot Rob Olson demonstrated the lengths some Rubyists will go to torture alias_method_chain to solve essentially the same problem that Nick addressed.

In short, while I agree in principle with Nick, his examples and the jargon he used demonstrated exactly why so few Rubyists take his point seriously. It is possible to write modular code in Ruby with the same level of flexibility but with far less code and fewer concept hoops to jump through.

Let's take a look at the problem Rob was trying to solve:

module Teacher def initialize puts "initializing teacher" end end class Person include Teacher def initialize puts "initializing person" end end # Desired output: # > Person.new # initializing teacher # initializing person

This is a classic problem involving modularity. In essence, Rob wants to be able to "decorate" the Person class to include teacher traits.

Nick's response would have been to create a factory that creates a Person proxy decorated with Teacher properties. And he would have been technically correct, but that description obscures the Ruby implementation, and makes it sound like we need new "Factory" and "Decorator" objects, as we do, in fact, need when programming in Java.

In Ruby, you'd solve this problem thusly:

# The base person implementation. Never instantiate this. # Instead, create a subclass that mixes in appropriate modules. class AbstractPerson def initialize puts "Initializing person" end end # Provide additional "teacher" functionality as a module. This can be # mixed into subclasses of AbstractPerson, giving super access to # methods on AbstractPerson module Teacher def initialize puts "Initializing teacher" super end end # Our actual Person class. Mix in whatever modules you want to # add new functionality. class Person < AbstractPerson include Teacher end # > Person.new # Initializing teacher # Initializing person

Including modules essentially decorates existing classes with additional functionality. You can include multiple modules to layer on existing functionality, but you don't need to create special factory or decorator objects to make this work.

For those following along, the classes used here are "factories", and the modules are "decorators". But just as it's not useful to constantly think about classes as "structs with function pointers" because that's historically how they were implemented, I'd argue it's not useful to constantly think about classes and modules as factories and decorators, simply because they're analogous to those concepts in languages like Java.

The Case of the PerQueryTimingFactoryFactory

Nick's example is actually a great example of a case where modularity is important. In this case, he has a base Query class that he wants to extend to add support for timeouts. He wrote his solution in Scala; I'll transcode it into Ruby.

Feel free to skim the examples that follow. I'm transcoding the Scala into Ruby to demonstrate something which you will be able to understand without fully understanding the examples.

class QueryProxy def initialize(query) @query = query end def select delegate { @query.select { yield } } end def execute delegate { @query.execute } end def cancel @query.cancel end def delegate yield end end

Then, in order to add support for Timeouts, he creates a new subclass of QueryProxy:

class TimingOutQuery < QueryProxy def initialize(query, timeout) @timeout = timeout @query = query end def delegate begin Timeout.timeout(@timeout) do yield end rescue Timeout::Error cancel raise SqlTimeoutException end end end

Next, in order to instantiate a TimingOutQuery, he creates a TimingOutQueryFactory:

class TimingOutQueryFactory def initialize(query_factory, timeout) @query_factory = query_factory @timeout = timeout end def self.call(connection, query, *args) TimingOutQuery.new(@query_factory.call(connection, query, *args), timeout) end end

As his coup de grâce, he shows how, now that everything is so modular, it is trivial to extend this system to support timeouts that were per-query.

class PerQueryTimingOutQueryFactory def initialize(query_factory, timeouts) @query_factory = query_factory @timeouts = timeouts end def self.call(connection, query, *args) TimingOutQuery.new(@query_factory.call(connection, query, *args), @timeouts[query]) end end

This is all true. By using factories and proxies, as you would in Java, this Ruby code is modular. It is possible to create a new kind of QueryFactory trivially.

However, this code, by tacking close to vocabulary created to describe Java patterns, rebuilds functionality that exists natively in Ruby. It would be equivalent to creating a Hash of Procs in Ruby when a Class would do.

The Case: Solved

Ruby natively provides factories, proxies and decorators via language features. In fact, that vocabulary obscures the obvious solution to Nick's problem.

# No need for a proxy at all, so we skip it module Timeout # super allows us to delegate to the Query this # module is included into, even inside a block def select timeout { super } end def execute timeout { super } end # We get the cancel delegation natively, because # we can use subclasses, rather than separate # proxy object, to implement the proxy private # Since we're not using a proxy, we'll just implement # the timeout method directly, and skip "delegate" def timeout # The Timeout module expects a duration method # which classes that include Timeout should provide Timeout.timeout(duration) do yield end rescue Timeout::Error cancel raise SqlTimeoutException end end # Classes in Ruby serve double duty as "proxies" and # "factories". This behavior is part of Ruby semantics. class TimingOutQuery < Query include Timeout private # implement duration to hardcode the value of 1 def duration 1 end end # Creating a second subclass of Query, this time with # per-query timeout semantics. class PerQueryTimingOutQuery < Query TIMEOUTS = Hash.new(0.5).merge("query1" => 1, "query2" => 3) include Timeout private def duration TIMEOUTS[query] end end

As Nick would point out, what we're doing here, from a very abstract perspective, isn't all that different from his example. Our subclasses are proxies, our modules are decorators, and our classes are serving as factories. However, forcing that verbiage on built-in Ruby language features, in my opinion, only serves to complicate matters. More importantly, by starting to think about the problem in terms of the Java-inspired patterns, it's easy to end up building code that looks more like Nick's example than my solution above.

For the record, I think that designing modularly is very important, and while Ruby provides built-in support for these modular patterns, we don't see enough usage of them. However, we should not assume that the reason for the overuse of poor modularity patterns (like alias_method_chain) result from a lack of discussion around proxies, decorators, and factories.

By the way, ActionController in Rails 3 provides an abstract superclass called ActionController::Metal, a series of modules that users can mix in to subclasses however they like, and a pre-built ActionController::Base with all the modules mixed in (to provide the convenient "default" experience). Additionally, users or extensions can easily provide additional modules to mix in to ActionController::Metal subclasses. This is precisely the pattern I am describing here, and I strongly recommend that Rubyists use it more when writing code they wish to be modular.

Postscript: Scala

When researching for this article, I wondered why Nick hadn't used Ruby's equivalent to modules (traits) in his examples. It would be possible to write Scala code that was extremely similar to my preferred solution to the problem. I asked both Nick and the guys in #scala. Both said that while traits could solve this problem in Scala, they could not be used flexibly enough at runtime.

In particular, Nick wanted to be able to read the list of "decorators" to use at runtime, and compose something that could create queries with the appropriate elements. According to the guys in #scala, it's a well-understood issue, and Kevin Wright has a compiler plugin to solve this exact problem.

Finally, the guys there seemed to generally agree with my central thesis: that thinking about problems in terms of patterns originally devised for Java can leave a better, more implementation-appropriate solution sitting on the table, even when the better solution can be thought of in terms of the older pattern (with some contortions).