Peter Marklund

Peter Marklund's Home

Wed September 03, 2008
Programming

Modularizing Your Rails App with Concerns

In his keynote here at RailsConf Europe 2008, David (DHH) talked about living with legacy code, how we should enjoy it instead of trying to avoid it, and how it can give us new insights by showing us how we have grown as developers. I loved the keynote and it resonated really well with my own experiences. It's also highly relevant with my current work at Newsdesk and Simple Signup.

As an example of refactorings you might find yourself doing in legacy Rails apps, David showed us how to break a big application helper or a fat model into Ruby modules. The idea was to find groups of methods that represent a certain concern or aspect of your app and collect those in a module. This is typically not done for reuse but to make your code more readable and easier to navigate.

Last week I found myself creating a plugin for a certain aspect of my application, namely the acceptance of terms of its service. It was a minimalist plugin with just a helper method and a controller filter method. The code was highly application specific and thus it felt wrong to keep it in the plugin directory. After all, plugins are supposed to be shared across applications and my plugin was inherently tied to the application. Still, I wanted to have the ability to keep an aspect of my application in its own directory, especially when the aspect spans across several layers of MVC. The solution I came up with was to create a new directory RAILS_ROOT/app/concerns with a sub directory and an init.rb file for each concern, very much like with plugins. I then generated a concerns plugin to make sure my concerns get loaded:

Dir[File.join(RAILS_ROOT, "app", "concerns", "*", "init.rb")].each do |init_file|
  require init_file
end

I talked to David (DHH) about this approach and the funny thing was that he had experiemented with it too. David says the approach can be appropriate if you use it wisely. If you overuse it your concerns directory will end up being a new "garbage can" and bring you back to the problem that you were trying to solve with concerns in the first place... :-)

Comments

Joel said over 5 years ago:

Cool, I feel I struggle with this kinds of design decisions quite often nowadays, not a bad solution at all..

Soo.. how long are you in berlin for? The whole of winston design has moved here for a few months and we are currently located at the office of the great soundcloud.com dudes. Send an sms or something if you wanna meet up for a pint or two (given you stay for a day or two ofc =)

--------------------------------------------------------------------------------

Dr Nic said over 5 years ago:

Perhaps the app/helpers folder needs to be split into:

<pre>app/views/helpers
app/controllers/helpers
app/models/helpers
</pre>

helpers == concerns, etc

Then it guides ppl as to where they extract "concerns" into their app hierarchy?

--------------------------------------------------------------------------------

Henrik said over 5 years ago:

I know you've seen it, Peter, but for others, here's one example of breaking a model into modules: http://henrik.nyh.se/2008/02/rails-model-extensions

I've considered making that more DSLy, but I've yet to come up with a way that is not overkill compared to just using modules.

I've been toying with the idea of an app-specific plugin dir as well, though I've never gone ahead and implemented it. "concerns" is a good name. For now, I just use plugins prefixed by the app name: "myapp_foo_system" etc.

--------------------------------------------------------------------------------

Henrik N said over 5 years ago:

Came up with a decent API for the modules: http://github.com/henrik/augmentations/

--------------------------------------------------------------------------------