Book now

Hexagonal Rails – Introduction

A few months ago, development of http://relishapp.com reached what is a familiar but rather unpleasant plateau for me. Up until that point, it had been developed using conventional Ruby on Rails idioms, with controllers that talk directly to ActiveRecord class methods to make queries, then set instance variables to pass the results of those queries to view templates for rendering. It’s all very procedural, and very tightly coupled.

This post is an introduction to a forthcoming series which will explain how I’ve been tackling this.

Let me start by saying that the coupling in my Rails application is not necessarily a bad thing. In fact, to get the product off the ground and give RSpec’s amazing living documentation a place to call home, we needed to be able to put Relish together very quickly. This is where Rails absolutely dazzles: the early stages of a project are so easy that adding features is a delight.

Unfortunately, the very forces that make adding features to a new Rails application so easy are the same ones that start to hold you back as the number of features grows. That conventional Rails style is what Kent Beck has called a connected design style, Quoting from that article:

In a connected system, elements are highly available to each other (via global state, for example). Adding the first feature to a connected system is cheap. All the resources you need are available. However, the cost of all those connections is that subsequent features are very likely to interact with previous features, driving up the cost of development over time.
The alternative to a connected design style is what Kent calls a modular design style. He contrasts these using this chart:

Cost of Features in Connected and Modular Designs (from http://www.threeriversinstitute.org/)

For the first few features, a connected design style is cheaper than a modular design style. In fact, using what might be referred to by software design snobs as ‘poor design’ could give you a competitive advantage in the early stages of your product’s development. The trick is to recognise when it’s time to switch styles.

So, while I love Rails for what it is, I also recognise its weaknesses. To make the Relish codebase habitable in the long term, I need to move beyond its connected design style and establish a more modular design. But how? It’s a question that many different people are asking at the moment, and I’ve been diving deep into what they are saying. Here’s a sample:

For my part, I re-read the outstanding Growing Object-Oriented Software Guided by Tests (GOOS) by Steve Freeman and Nat Price. In that book, Steve and Nat advocate a ports-and-adapters or hexagonal architecture, which keeps your core application logic separate from any technical details needed to connect the application to the real world; technical details like databases, or web user interfaces.

I think it’s easier to use an architecture like this in Java or C#, where packages and interfaces make it easy to see and enforce separation between chunks of the application, than in Ruby where it’s harder to make clear boundaries around areas of the system. But that doesn’t mean it isn’t possible. For the past couple of months I have been experimenting with refactorings in the Relish codebase to move it towards a more hexagonal architectural style. The overall goal is to make the Relish codebase habitable, which for me breaks down into:

1. Fast tests

I never add features without tests, and I want those tests to run fast. The goal of the hexagonal architecture is to have the most interesting (and frequently changing) logic implemented in plain old Ruby objects that have no dependency on any other libraries so they are easy to understand, and can be quickly spun up in a test.

2. Modularity and encapsulation

Ruby is an object-oriented language with great support for functional programming, and I want to make the most of that to keep Relish’s code easy to change.

3. Clean and well-organised

I want a structure that communicates what each part of the system is doing, and makes it easy for new team members to jump in and start hacking on the code.

I’ll start the series by explaining a couple of key concepts from Steve and Nat’s GOOS book, and about hexagonal architectures in general. Then we’ll get down to some practical work refactoring a typical Rails controller. Stay tuned!

Agile / Lean Software Development
Hexagonal Rails
Relish
Ruby Programming

Comments (6)

Permalink

Two Truths I’ve Learned About Writing Clean Rails Apps

In summary:

  • Implement every feature without javascript first, add javascript as a progressive enhancement
  • Stick to REST. Always.

Now I’m as suspicious of absolute rules as you probably are, but these two have served me extremely well in keeping my Rails code clean and easy to maintain. I’m happy to push the boat out and call them truths, my truths anyway.

Let me explain.

Progressive Enhancement

When I first started at Songkick, Cucumber was just emerging and webrat was the new kid on the testing block. Although using Selenium for full-stack javascript testing was possible with webrat, it wasn’t easy and we quickly made a decision: we would build the first iteration of every feature to work without javascript. This was mainly driven by pragmatism: we could easily use webrat to test the app through Rails integration testing stack, and these tests ran quickly rather than waiting for a browser to start up.

What happened surprised us. We would receive fancy designs from our designers which could only be implemented with fairly complex javascript. Because of our rule, we had to figure out how to deliver the same behaviour using basic HTTP posts and gets of forms and URLs. This required us to simplify the designs for our first iteration. We got a little push-back at first but we were a tight team and the designers quickly caught on. Especially when we started shipping these iteration one features quickly and reliably. And funnily enough, it turned out that often these simple HTTP-only versions of the features were actually fine, and the designers decided we should move onto other stuff, instead of building all that complex javascript that had been implied by their earlier designs.

So this rule had helped us to do the simple thing. We shipped features and moved on.

When we did have to add javascript, we added it on top of the existing working HTTP-only implementation, and we got another surprise: it was easy! Nearly every time, because we’d built the server-side infrastructure to a clean, standard pattern, the javascript we needed was clean and simple to write.

Which leads me to my next truth…

Stick to REST. Always.

I’ve always felt a little uncomfortable with Rails’ controllers. They violate the Single Responsibility Principle for me. I’d prefer a pattern where I had a separate Request class for each action, rather than a few largely unrelated methods on the same controller class. But Rails is there and there’s a lot else to like, so let’s not get into that.

We all know it’s a bad idea to let our controllers bloat and something I’ve been enjoying greatly lately is Jose Valim‘s Inherited Resources. By sticking to this pattern, you push all the logic into your domain model, and keep the controllers focussed on what they need to do: handling web requests.

You end up with more controllers, and more models too. You create model objects that — Gosh! — don’t represent database tables, but represent other domain concepts instead. Altogether though, you end up with smaller, more focussed classes that are easier to test and easier to read and understand.

Ruby Programming

Comments (3)

Permalink

Rails Tip: Use Polymorphism to Extend your Controllers at Runtime

Metaprogramming in Ruby comes in for quite a bit of stick at times, the accusation being that code which modifies itself at runtime can be hard to understand. As Martin Fowler recently described, there’s a sweet spot where you use just enough to get some of the incredible benefits that Ruby offers, without leaving behind a minefield for future developers who’ll have to maintain your code.

One of my favourite techniques uses the Object#extend method, which allows you to mix in the methods from a module to a specific instance of a class at run-time. In my quest to eliminate as much conditional logic as possible from my code, I’ve seen a common pattern emerge a few times. Here’s an example from a refactoring session I paired on with my colleague craig.

We start with a Rails controller which handles user authentication. Over the passing iterations, it has grown to support not only bog-standard logins from users of the main web application, but a form that’s displayed on a 3rd-party partner site, as well as during the installation of a rich-client GUI app. All these clients need slightly different behaviour – different templates or layout to be rendered, and different destination pages to redirect to when the login has succeded.

Sadly the hackers passing through this controller have not been great boy scouts, and the code has started to get pretty unpleasant. This code is simplified for clarity:

class SessionsController < ApplicationController
 
  def new
    if params[:installer]
      render :layout => 'installer_signup', :action => 'installer_signup')
    else
      render :layout => 'modal'
    end
  end
 
  def create
    if params[:username].blank?
      flash[:error] = "Please enter a username"
      return render_new_action
    end
 
    unless user = User.authenticate(params[:username], params[:password])
      flash[:error] = "Sorry, that username was not recognised"
      return render_new_action
    end
 
    set_logged_in_user(user)
 
    if params[:installer]
      @username = user.username
      return render(:template => 'installer_done', :layout => 'installer_signup' )
    elsif params[:third_party]
      return render(:template => "third_party/#{params[:third_party]}")
    else
      return redirect_to(success_url)
    end
  end
end

Notice how the conditional logic has a similar structure in both actions. Our refactoring starts by introducing a before_filter which works out the necessary extension:

class SessionsController < ApplicationController
 
  before_filter :extend_for_client
 
  ....
 
  private
 
  def extend_for_client
    self.extend(client_exension_module) if client_exension_module
  end
 
  def client_extension_module
    return InstallerClient if params[:installer]
    return ThirdPartyClient if params[:third_party]
  end
 
  module InstallerClient
  end
 
  module ThirdPartyClient
  end
end

Notice that we don’t bother extending the controller for the ‘else’ case of the conditional statements – we’ll leave that behaviour in the base controller, only overriding it where necessary.

Now let’s extract the client-specific code out of the create action into a method that we’ll override in the modules:

class SessionsController < ApplicationController
 
  ...
 
  def create
    if params[:username].blank?
      flash[:error] = "Please enter a username"
      return render_new_action 
    end
 
    unless user = User.authenticate(params[:username], params[:password])
      flash[:error] = "Sorry, that username was not recognised"
      return render_new_action 
    end
 
    set_logged_in_user(user)
 
    handle_successful_login
  end
 
  private 
 
  def handle_successful_login
    if params[:installer]
      @username = user.username
      return render(:template => 'installer_done', :layout => 'installer_signup' )
    elsif params[:third_party]
      return render(:template => "third_party/#{params[:third_party]}")
    else
      return redirect_to(success_url)
    end
  end
 
  ...

Finally, we can the client-specific code into the appropriate module, leaving the default behaviour in the controller:

class SessionsController < ApplicationController
 
  before_filter :extend_for_client
 
  def new
    render :layout => 'modal'
  end
 
  def create
    if params[:username].blank?
      flash[:error] = "Please enter a username"
      return render_new_action 
    end
 
    unless user = User.authenticate(params[:username], params[:password])
      flash[:error] = "Sorry, that username was not recognised"
      return render_new_action 
    end
 
    set_logged_in_user(user)
 
    handle_successful_login
  end
 
  private 
 
  def handle_successful_login
    return redirect_to(success_url)
  end
 
  private
 
  def extend_for_client
    self.extend(client_exension_module) if client_exension_module
  end
 
  def client_extension_module
    return InstallerClient if params[:installer]
    return ThirdPartyClient if params[:third_party]
  end
 
  module InstallerClient
    def new
      render :layout => 'installer_signup', :action => 'installer_signup')
    end
 
    private 
 
    def handle_successful_login
      @username = user.username
      return render(:template => 'installer_done', :layout => 'installer_signup' )
    end
  end
 
  module ThirdPartyClient
    def handle_successful_login
      return render(:template => "third_party/#{params[:third_party]}")
    end
  end
end

Polymorphism is one of the power-features of an object-oriented language, and Ruby’s ability to flex this muscle at run-time opens up some really elegant options.

Ruby Programming

Comments (1)

Permalink

MagLev: Death of the Relational Database?

I just got around to watching Avi Bryant’s talk on MagLev, a new Ruby VM built on top of GemStone’s Smalltalk VM.

http://www.vimeo.com/1147409

Presumably this is the kind of thing Smalltalkers have been able to do for decades, but to me the prospect of having this kind of freedom on a Ruby platform is very exciting. Terrific stuff. I wonder what performance is like.

Agile / Lean Software Development
Ruby Programming

Comments (0)

Permalink

Behaviour-Driving Routes in Rails with RSpec

One thing that isn’t documented very well for RSpec is how to test your routes.

I came across an old post on the rspec mailing list which described a great way to do this:

describe TasksController "routing" do
 
    it "should route POST request for /tasks to the 'create' action" do
        params_from(:post, "/tasks").should == {:controller =>; "tasks", :action =>; "create"}
    end
 
end

Very nice.

Agile / Lean Software Development

Comments (0)

Permalink

DataMapper: A Better ORM for Ruby

One of the things that’s always irritated my about rails’ ActiveRecord framework is the way that the domain model lives in the database.Don’t get me wrong: it’s very clever, and a great showcase for ruby’s metaprogramming features, which will blow average C# / Java mind the mind when they first see it.

In rails, you build a database of your domain model, and create empty classes with the names of the domain entities (conventionally the singular of a database table name) which inherit from ActiveRecord. ActiveRecord then looks at your database, and using the magic of metaprogramming, hydrates your object with a bunch of properties that map to the database fields.

But I prefer to write my models in the code, and if you do too, you might want to take a look at DataMapper.

Agile / Lean Software Development

Comments (3)

Permalink

Painless RMagick Install for Ruby on Rails

One of the ironies and frustrations I find of working with open-source software is that things are changing so fast (yay!) that the documentation you find is nearly always out of date (boo!).

Trying to figure out how to get the rmagick component of the handy file_column rails plug-in to play nice, I came across numerous gruesome posts involving 3 hour sessions building rmagick from source, sacrificing goats, etc. Yikes.

Then I came across this great piece of news and suddenly things clicked into place. Ahhh.

Ten minutes later, a sprinkle of this, and I have thumbnail images all over my site. Too easy!

Uncategorized

Comments (0)

Permalink

Nested Controllers and Broken link_to

So my first little rails app is taking it’s baby steps in the wild today, and some users should hit the site over the weekend… Exciting stuff.

I’ve written an admin area for the site, and with only a tentative grasp on the whys and wherefores, I’ve copied something I saw in the mephisto source code and used ‘nested controllers’ to keep the admin code tucked away from the rest:


$script/generate controller admin/users
$script/generate controller admin/stuff
For want of a better way, I put a base class for the admin controllers into the application.rb file (can’t remember where I picked this tip up) and put a one-line before_filter on that class to check whether the user has the appropriate rights. Sweet.

The little gotcha with this was that a lot of my existing linkto and redirectto calls didn’t work from within the admin area, because I guess the :controller value in the options is relative. Adding a forward-slash to the controller name fixes it up:


<%= link_to 'home', :controller => '/home' %>
Looks like not the only one to have hit this little bump.

I think I need a new rails book: I’m starting to leave my trusty pragprog book behind. Any recommendations out there people?

Uncategorized

Comments (1)

Permalink