Rails’ Unusual Architecture

There has been surprisingly little written about how Rails is implemented. If you Google for “architecture Rails” you’ll find plenty of articles that describe Rails as a web framework based on the classic Model-View-Controller design pattern. And you’ll find plenty of links about Rail’s constituent parts – ActiveRecord, ActionController, ActionView, ActiveSupport, etc. But you’ll find precious little about how Rails is put together.

Which is shame, since Rails is constructed in a very unusual manner. So let’s dig into Rails and see what makes it unusual.

What Does a Web Framework Have to Do ?

Let’s start by considering what a web framework has to do. If you were to build your own framework, the absolute minimum requirements are:

  • Read requests via http/s
  • Unmarshall client provided data – the data may be url encoded, gzipped, etc.
  • Figure out what the client is asking
  • Do what the client is asking
  • Return the answer in a client specified format such as xhtml, xml or png

But such a bare bones framework would leave much to be desired. To be truly useful, you would also have to address a number of additional issues, including:

  • Authentication
  • Authorization
  • State handling (generally via sessions)
  • Error handling
  • Logging
  • Performance (timing, caching, pooling, threading, etc)

So how can you meld all this functionality into a cohesive system that is easy to use and easy to extend?

Decorator

The standard answer is use the Model-View-Controller pattern. But that still leaves many questions to be answered – particularly on the controller side. How exactly do you implement the controller piece?

A common approach is to use the Decorator pattern made famous by the Gang of Four. The basic idea is to create a chain of decorators as shown in the diagram below.

Decorator Pattern

Each decorator deals with one issue. So you’d have one decorator for unmarshalling, one for authentication, one for session management, etc.

The Smallworld Internet Application Server uses this architecture. Apache Axis and Apache Cocoon use this architecture. And although I’ve never used Django, its middleware classes require a common API which is a telltale sign that they are really decorators in disguise.

So why is the Decorator pattern so popular? Because it let’s you modularize your framework, making it possible to add or remove functionality as needed based on a particular application’s requirements.

Aspect Oriented Programming

Another approach, albeit much rarer, is to use Aspect oriented programming, or AOP, to combine multiple behaviors. Like many computing technologies in use today, aspect oriented programming was invented at Xerox Parc. But it found its home in the Java world via the AspectJ project, which is now part of Eclipse.

There are plenty of articles that explain aspect oriented programming in-depth so I won’t rehash them. But the basic idea is to use a domain specific language (DSL) to combine different pieces of functionality without touching the original code.

The classic example is logging. Adding logging statements to each method is tedious and error prone. Even worse, if your logging API changes you have to go back and touch every part of your system. Thus logging is an example of a cross-cutting concern, something that affects every part of a system.

With a little thought, its easy to see why aspect oriented programming could make it easier to write a web framework. And its appears there is such a thing – the Spring Framework. Although I’ve never used it, the documentation makes it look like it relies heavily on aspect oriented programming.

The Rails Way

So how about Rails? Rails is unusual because it uses Ruby’s limited aspect oriented support to mimic the Decorator pattern.

Ruby supports aspect oriented programming? Well not really. But it does offer a very crude approximation via its alias method and support of modules. Rails leverages this basic support for all its worth – it forms the very heart and soul of Rails.

To see what I mean let’s look at an example. Here is the basic skeleton of Rails session handing functionality, found in actionpack\lib\action_controller:

module ActionController #:nodoc:
  module SessionManagement #:nodoc:
    def self.included(base)
      base.extend(ClassMethods)
      
      base.send :alias_method_chain, :process, :session_management_support
      base.send :alias_method_chain, :process_cleanup, :session_management_support
    end

    module ClassMethods
      # Class methods go here
    end

    # Instance methods go here
  end
end

The important things to notice are:

  • Behavior is specified using modules instead of classes
  • Rails uses Ruby’s include method to add methods defined in a module as instance methods in a host class. By convention the host class is called Base – thus ActionController::Base, ActionView::Base.
  • Rails uses Ruby’s extend method to add methods defined in a module as class methods (called static methods in other languages) in a host class. By convention class methods are defined in a sub-module unsurprisingly called ClassMethods.
  • Rails uses a custom method called alias_method_chain, which is based on Ruby’s built-in alias method, to chain method calls together.

Rails then loads this code in actionpack-1.13.3\lib\action_controller.rb like this:

require 'action_controller/session_management'

ActionController::Base.class_eval do
  include ActionController::SessionManagement
end

The end result is that ActionController::Base now has the following method chain:

process -> 
process_with_session_management_support -> 
process_without_session_management_support

Voila. Rails has created a Decorator using Ruby’s limited aspect oriented programming support.

If you look through the Rails source code you’ll see this pattern repeated over and over.

Is This A Good Idea?

Rails implements the Decorator in such an unusual way that its worth asking if it is a good idea or not. In my opinion it isn’t. I don’t see any advantages in Rails’ implementation – do you?

But I do see several disadvantages. The biggest one is that its removes an obvious extension point from Rails. Once two methods are linked together using Ruby’s alias method you can’t break them apart. For example, if A aliases B then you can’t insert C between them. This might not seem like a big deal, but for some extensions it quite important. For example, when I wrote our REST controller implementation last year I struggled mightily to fit it into Rails aliases method calls and finally gave up and took a different approach. Its worth noting that its often possible to work around this problem since Ruby is such a flexible language. Instead of adding a new decorator, in many cases you can replace the original method to achieve what you want. Its not nearly as elegant, but it usually does the trick.

A second disadvantage is that it complicates Rails architecture. What’s the difference between a decorator and a filter? Nothing. By using the Decorator pattern you could merge Rail’s filter functionality with its method chaining functionality, thereby reducing its overall code base.

A third disadvantage, albeit a minor one, is that the method chains Rails creates are hidden. You can’t look at a single piece of code, or configuration file, and see the method chains. The closest is action_controller.rb and action_view.rb, but I can’t get a handle on a chain object at runtime and say “please print yourself on STDOUT so I can see what is happening.”

The fourth, and last, disadvantage is much more subjective and personal. I think Rails is trying to be too cute for its own good. When faced with a standard problem use a standard solution – that is the whole point of design patterns. By trying to be too cute Rails provides a solution that is less flexible and less obvious than the standard approach.

Update – Peter rightly pointed out in the comments that I mistakenly used the Chain of Responsibility Pattern instead of the Decorator pattern. There is a subtle, yet extremely important, difference between the two. In the Chain of Responsibility pattern the first handler that can process a request will do so and the rest of the chain will not be executed. In the Decorator pattern every decorator in the chain will process a request.

I’ve decided to update this entry since I think accuracy is more important the maintaining the original version. Thanks for your feedback Peter!

  1. Jim Cropcho
    September 5, 2007

    Oh, so _that’s_ how the hell Rails works. It really is an interesting implementation, caveats and all. Great post!

    Reply
  2. Jeff
    September 5, 2007

    Great post. Can I ask a question?

    Why do they do this:

    ActionController::Base.class_eval do
      include ActionController::SessionManagement
    end
    

    instead of simply re-opening the class?

    class ActionController::Base
      include ActionController::SessionManagement
    end
    

    Is there a difference or is it just a question of style?

    Reply
  3. Peter Williams
    September 5, 2007

    To be fair I think it is a bit stretch to say that the architecture of
    SIAS was a chain of responsibility. We were certainly influenced by
    that pattern but in practice it turned out to be extremely difficult
    (to the point of impossibility) to make a pure chain of responsibility
    work as the basis for a web application framework.

    If you are looking for a pattern to base a web application framework
    on I think decorator would be a *much* better choice. In fact, not
    that I think about it that is the pattern you are describing, not
    chain of responsibility.

    Reply
  4. Jacob
    September 5, 2007

    the problem with re-opening a class is that is may not have been loaded yet.
    If this happens:

    class ActionController::Base
    include ActionController::SessionManagement
    end
    and ActionController::Base is not already defined then a new class will be defined and the logic that runs on self.included may run and not find a process method for `alias_method_chain` to work on. (in which case you’d get an exception)

    Whereas if you do:

    ActionController::Base.class_eval do
    include ActionController::SessionManagement
    end
    You are asserting that ActionController::Base is already defined before you open it. (if it’s not, rails const_missing will find and load it) Thus forcing it to be fully loaded before you go and change it.

    Reply
  5. James Britt
    September 5, 2007

    Could you explain how Java manages to support AOP, yet Ruby does not?

    Reply
  6. Alan Shutko
    September 5, 2007

    There’s been a lot of tricky work done on Java to make it support it. The original AOP work had a precompiler you needed to turn your source into Java source. Spring has a more limited form of AOP built in which relies on dynamic proxies (or building proxy byte code at runtime with cglib). It’s hidden from the user, but requires a lot of work behind the scenes, and you have some strange situations where it doesn’t work as you’d necessarily expect (like when an method calls another method on the same object).

    It seems to me that Ruby’s made it easy enough to modify behavior that nobody has needed to build out the machinery for “full” AOP.

    Reply
  7. Ezra
    September 5, 2007

    alias_method_chain is evil. Not only does it make it very hard to extend a feature that has already been aliased but it just adds additional method call overhead(which is expensive in MRI) and it deepens the stack for no beneficial reason.

    Down with alias_method_chain!

    Reply
  8. Charlie Savage –
    September 6, 2007

    James – Its done by modifying Java byte code – see [http://www.eclipse.org/aspectj/doc/released/progguide/implementation.html](http://www.eclipse.org/aspectj/doc/released/progguide/implementation.html).

    Alan – Thanks for the info about AOP and Java.

    There has been some work on adding more AOP features to ruby – including an [RCR](http://rcrchive.net/rcrs/1), [AspectR](http://aspectr.sourceforge.net/) and [Aquarium](http://aquarium.rubyforge.org/).

    Reply
  9. Charlie Savage –
    September 6, 2007

    Choonkeat – Nice link, thanks!

    Reply
  10. Peter Williams
    September 6, 2007

    The main difference between the chain of responsibility and a
    decorator patterns are the end point.

    In a pure chain of responsibility the first thing that was able to
    handle the request would do so and the rest of the chain would not be
    executed at all.

    In a pipe and filter pattern, which is structurally very similar to a
    chain of responsibility, the entire chain would be execute with each
    step doing one thing and then passing the request/response on to the
    next filter. So the request starts at the first element of the chain,
    and ends at the last element. Control never returns to a step after
    it has been executed.

    (req/resp) -> init_session -> controller_action -> (req/resp)

    In a decorator pattern each step wraps the steps below it. So
    handling a request would start at the top decorator and it would
    finish when that method returned. The decorator pattern is a more
    direct match to the way `alias_method_chain` works in that you can do
    work before and/or after, or even modify the results of, the step
    below you.

    Reply
  11. Charlie Savage –
    September 6, 2007

    Hi Peter,

    Ah. Just reread the Gang of Four:

    >The first object in the chain receives the request and either handles it or forwards it to the next candidate on the chain, which does likewise.

    So yup, its the decorator pattern. Although Chain of Responsibility sounds so much better.

    Reply
  12. Justin George
    September 6, 2007

    It’s funny you should reference design patterns with regard to ruby. There was an interesting article pointing out that most of them (iirc all but 3) were hacks to get around things that modern languages should have by default.

    Ruby does, in fact, have those defaults (well, if you consider blocks and lambda to be fully first class functions), and thus talking about it is probably not the time to be citing GoF as gospel.

    Reply
  13. September 6, 2007

    Great post!

    FWIW, Aquarium effectively uses the Decorator pattern to chain “advice” calls. There is a type of advice called “around” advice (in addition to the more intuitive “before” and “around” advice…), where you wrap a method call and you must explicitly invoke the wrapped method. If you don’t, then it behaves like Chain of Responsibility πŸ˜‰

    Aquarium doesn’t yet provide a way to insert advice between already chained advices, but the pieces are there already. Another thing you would like to do (which AspectJ provides) is the ability to prioritize execution of advices acting on the same method. For example, maybe authentication should always be first!

    Reply
  14. Dean Wampler
    September 6, 2007

    Uh, I meant “before” and “after” advice…

    Reply
  15. http://kurtstephens.com
    September 6, 2007

    This coding pattern is common in Rails and Ruby. This is a great way to package functionality into reusable units.

    But, this is not AOP, Decorator or Chain of Responsibility.

    It is an exercise in first-class modules and module delegation, which Ruby supports very well. It is a chain of methods packaged in modules, not objects collaborating; i.e. composition of class and module singletons, versus instantiated behavioral objects. The latter is far more flexible.

    There are no Decorator objects being created. There is no Chain of Responding objects. It is not AOP because the advice is not specified orthogonally, outside the subject class.

    The Ruby gem aquarium looks like a good AOP framework. Found it just after I wrote my own method advice package. πŸ™

    Reply
  16. Rick
    September 6, 2007

    You mention that ruby has limited support for AOP, which is true, but you fail to mention that, generally, intended effect of AOP is to implement cross-cutting-concerns. In this capacity ruby is incredibly adept. It utilizes it’s trademark feature, the closure, to add functionality (such as logging, auth, even the decorator pattern) It accomplishes this in a much more elegant fashion than standard AOP practices, IMO. Interesting article by the way.

    Reply
  17. Charlie Savage –
    September 6, 2007

    Hi Justin,

    Yes, its a bit of a meme that dynamic languages reduce the need for many design patterns. Do you have a link to that article?

    However, that doesn’t mean that all design patterns are useless. And in this case particularly, they help understand some of the possible approaches to building a web framework. Using a more functional approach(blocks/lambda), like you mention, would also work. But I would guess it would end up fairly un-Ruby like. So if you’d prefer that approach its probably better to use a functional language.

    Reply
  18. Charlie Savage –
    September 6, 2007

    Hi Dean,

    Thanks for the info on Aquarium. Do you use it often, and are you a developer on the project? Looks like a very interesting project, I’ll have to give it a try.

    Reply
  19. Charlie Savage –
    September 6, 2007

    Hi Kurt,

    Great comments.

    > It is a chain of methods packaged in modules, not objects collaborating; i.e. composition of class and module singletons, versus instantiated behavioral objects. The latter is far more flexible.

    Yes, that is an excellent way of putting it. I should added a paragraph explicitly calling out that difference.

    > There are no Decorator objects being created. There is no Chain of Responding objects.

    Agreed. The effect is similar, the implementations are very different.

    > It is not AOP because the advice is not specified orthogonally, outside the subject class.

    That is an interesting point. Including the modules into a base class is sort-of-kind-of outside the subject class. But of course you have to do it via class_eval.

    Reply
  20. Charlie Savage –
    September 6, 2007

    Hi Rick,

    >generally, [the] intended effect of AOP is to implement cross-cutting-concerns…It utilizes it’s trademark feature, the closure, to add functionality (such as logging, auth, even the decorator pattern)

    Sort of. You still have to add in the code to hook in the functionality (such as Benchmark) versus AOP where that is done orthogonally (as emphasized by Kurt).

    But I agree that Ruby does give you the tools to make that less painful than many other languages.

    Reply
  21. September 10, 2007

    Chain of Responsibility and Decorator are so similar they’re almost the same. Their difference only lies in the implementations not the architecture of the pattern. Decorators can behave like Chain of Responsibility (COR for short) because they can always choose not to forward a request onto it’s delegate.

    In web frameworks sometimes you want to stop processing a request due to some condition. Consider, error handling, authentication, etc. In these cases your request is processed more like a COR rather than Decorator. A decorator pattern is equivalent to COR and vice a versa.

    I have found it very difficult to figure out what’s actually happening in the Rails code by looking at the source. The use of adding dynamic methods is very hard to track down who’s calling whom. Being able to view the method decoration at runtime would be really cool. Maybe using something like [this](http://www.dogbiscuit.org/mdub/weblog/Tech/Programming/Ruby/MethodMissingMagic) could help:

    At runtime you could instantiate a controller object that acts like a camcorder, and at the end would print out all of the methods processed to HTML. Maybe turn it on with a ViewHelper: < %= request_method_chain %>.

    Reply
  22. JB Brown
    September 11, 2007

    This seems more like a Pipeline/Pipes-and-Filters pattern than Decorator or CoR. You’ve expressed the consequences of the Pipeline/Pipes-and-Filters pattern in your post along with what I believe are misplaced frustrations about things you’d expect to be in a Decorator pattern implementation but aren’t.

    An early post stated that pipleine doesn’t augment behavior before and after; but rather only before. I’d say this is a limited view of Pipes-and-Filters and that it really depends on the diretionallity of the intended Pipe; in, out, or in-and-out. Pipeline / Pipes-and-Filters can be for returning a response to a request just as well as it’s coloquial description of processing a request.

    http://jb-brown.blogspot.com/2007/09/cage-match-decorator-pipeline-chain-of.html

    Reply
  23. JB Brown
    September 11, 2007

    After further understanding the alias_method_chain implementation I agree that in OO patterns this is most acurately described as the Decorator pattern. I was misguided with my Pipeline view. I’ve updated my blog with the same.

    Reply
  24. Michael Schuerig
    February 1, 2008

    There is one very big advantage in the way Rails implements the decorator pattern: It keeps the sense of self intact. The classic GOF-decorator, implemented as one decorating object wrapped around another object, suffers from schizophrenia. When a decorated method is called from the outside, it goes through the decorator; when the same method is called from within the inner object, it goes straight to the original implementation, bypassing the decoration.

    The Rails implementation, using method chaining, avoids splitting the meaning of self by keeping everything to a single object.

    See my other, earlier musings on [self-conscious decoration in Rails](http://schuerig.de/michael/blog/index.php/2007/02/12/self-conscious-decoration/).

    Reply
  25. Charlie Savage –
    February 3, 2008

    Hi Michael,

    That is an interesting point that I hadn’t considered – and thanks for the link to your earlier blog post that I had missed when I orginally wrote this.

    In the case of Rails, I’m not sure it matters since the method being decorated tends to be process. But I can see how it would be important in other cases.

    Reply

Leave a Reply

Your email address will not be published.

Top