Code design, ruby, and design patterns

So, in a previous post, I talked about a nice design involving a proxy/delegator object that impersonates the result of a closure passed into it. This was to solve a problem with configuration settings dependent on other settings that can change.

I ended up realizing that the ruby standard library provides a really nice class to help you create a proxy/delegator/impersonator object like this:  the Delegator

Holy multiple inheritance, batman!

I took it a step beyond what the Delegator seemed to do, and overroad is_a?, instance_of?, and kind_of? to make sure that if anyone was checking my DependentConfig delegator using these methods, it would really seem to be the type of it’s delegated object. Wow, this is effectively multiple inheritance in ruby. Use these powers only for good, not for evil, luke.

Providing an object which in all respects possible impersonates another object like this could be considered the ultimate example of ‘duck typing’.  This thing isn’t really a duck, but not only does it quack like a duck, it also flies, waddles, swims, and does everything else just like a duck. Or a mammoth, or whatever else you initialize it with.

Poor behavior in Rails render?

Interestingly, the main reason I thought to override these methods, is because Rails render, when passed one of my DependentConfig delegators which was impersonating a string, intended to be the name of a template to render — was refusing to recognize the argument as a string, instead of trying to instantiate the view template named, it kept trying to do weird things with the actual class of the object. Perhaps the render argument can take an instantiated object or a string, and was deciding my argument was an instantiated object, not a string.  But how is it deciding this?

I don’t have time to get to the bottom of it in the Rails source code, but apparently it’s not using kind_of? or is_a? (which themselves people often say you should avoid to be consistent with ruby’s ‘duck typing’ ethos), but perhaps actually looking at the actual .class of the argument?  That would be about as inconsistent with duck typing as you can get. Whatever it’s doing, it’s not good.  Ruby/Rails’ liking for arguments that can be of multiple types, with different effects depending on the type — sometimes ends up not playing well with duck typing, if not implemented carefully.

What’s design patterns got to do with it?

Speaking of code design practices and ruby, I’m still mystified by many of my colleagues apparent dislike for the idea of “design patterns”, thinking that ruby is somehow the antithesis of design patterns. I blame their bad experiences with Java, which uses design patterns very poorly. In fact, to my perspective, the ruby standard library, and Rails too, are full of effective use of design patterns.  The classic original book on Design Patterns is this one, often called the “gang of four” or GoF for it’s four authors.

The preferred languages of the authors of the GoF was smalltalk, and to my perspective ruby actually looks an awful lot like smalltalk.  The true power and flexibility of design patterns becomes most apparent in a really dynamic language like smalltalk or ruby. (I wonder if Matz was influenced by smalltalk in designing Ruby. I’m fairly confident that the designers of Rails were heavily influenced either by the GoF, or by a framework like WebObjects that was based on design patterns principles.)

One of the priciples of the GoF book is to prefer composition over inheritance in your design. Composition essentially just means one object keeping a reference to another object, and calling methods on that other object in order to provide functionality in the first. Basically both composition and inheritance are ways of providing functionality defined elsewhere in a class. But composition, where possible, is much more flexible and extensible as the class defined is used in unexpected and novel ways. This preference goes double for use of ruby modules, which I would describe as just another type of inheritance. (A kind of multiple inheritance where you can only multiply inherit from _certain_ classes, those defined as modules).

In ruby, it’s possible to “monkey patch”, to open up a class again at run-time and redefine certain methods in it. I’d say if it’s a good principle to prefer composition to inheritance, it’s triply true to prefer either of those to monkey patching. Monkey patching should really be a last resort. It leads to code that is hard to debug, hard to understand, and hard to flexibly extend later.

(As the Rails1 debacle with monkey patching of the Logger class demonstrates, making it pretty much impossible for particular Rails apps to easily customize the Logger themselves. This has only been partially fixed in Rails2, although they tried.)

It’s good that monkey patching is possible, but it ought to be a last resort, mainly when working with libraries that you don’t have control over–never included as an intentional design in the architecture of a library you do have control over!

The excuse for monkey patching or inheritance/modules instead of using composition is probably that it’s simpler and easier to code.  (Monkey patching especially is certainly not easier to understand or debug!).   But the ruby standard library provides, not only the Delegator class, but also the incredibly convenient Forwardable module,  which makes it very easy to use composition to provide module-like behaviors, with elegant, short, and easily understood code.

Consider using it! Consider reading the GoF book! Don’t let your ideas of Java scare you off of design patterns. It would be like deciding that because your crazy uncle uses a sledgehammer to open beer bottles, you’re going to swear off pre-made tools in general, and custom design and fabricate a unique tool for everything you need to do!  Design patterns are like time-tested tools in your toolbox for handling certain kinds of problems.


4 thoughts on “Code design, ruby, and design patterns”

  1. This is probably what ruby is doing:

    case thing
    when String
    … do things on a stringy thing ….

    Problem is that String#=== is being called which calls Object#=== which searches the ancestor hierarchy and does not call #is_a?(String) on your object.

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )


Connecting to %s