2008-03-23 15:03 UTC Why Rails is total overkill and why I love Rack

Rails is total overkill. It tries to do "everything" in a massive framework where major components are tightly intervowen. Smaller frameworks like Merb and Camping have already shown you don't NEED this. I argue you don't need a framework at all - you need highly cohesive, loosely coupled components. That is why I love Rack - it does one thing and does it well, and leave me to write applications, not learn frameworks.

Why I love Rack

Rack is beautiful in it's simplicity. I've posted a couple of Rack middleware classes that shows how simple it is to extend. (check out my Rack tag for more)

It struck a chord with me because what it tries to do is very limited; it's simple; its model encourages layering and compositions of cohesive individual component as opposed to what "frameworks" usually does.

Rack is not a framework. If you want a framework you can plug it into Rack. If you don't, you can write to the bare Rack environment.

"Framework" is to me an euphemism for "Gordian knot of interdependencies". It doesn't have to be that way, but it ends up being that way more often than not. If a framework is engineered explicitly to be just a collection of libraries that share minimal interdependencies and are useful by themselves, then I have no beef with it.

While there are many common needs for various web apps, they are however largely orthogonal, and can easily be supported via independent, highly cohesive libraries. This is the case for most domains where people promote frameworks. Let me give some examples related to web apps:

  • Sessions: The basic requirement for session handling is the ability to persist objects or pieces of data, and to tie that persistence to a key extracted from a cookie or CGI parameter. There's no reason for this to not consist of a self-contained module to handle the persistence, and a tiny adapter from the CGI environment (whether provided by Rack, the CGI class, or something else) to the persistence code. Why intermingle it with "framework" code?
  • Database handling: Ok, so Rails too does the right thing here (mostly) and ActiveRecord can indeed easily be used outside of Rails. There's just no reason for the ORM or other database code to be tied to a framework. But Rails tie you pretty intimately to ActiveRecord. If you buy into Rails, the assumption is you'll use ActiveRecord. Which sucks if you don't like ActiveRecord or it's not suitable for your application.
  • Request processing: Exactly what is it people want here? For me request processing involves parsing the CGI environment and presenting it nicely packaged up. Possibly handling uploads. Some escaping/unescaping. Rack::Request handles all I need there.
  • Rendering/views: The plethora of different rendering libraries generating HTML output demonstrates quite clearly this can be done separately.
  • Routing/dispatching: It's at most a Hash mapping regexp's to classes and/or method calls. Hardly an earth shattering invention. The routing class I use for this blog is about 40 lines, and it's only that big because it's full of bells and whistles. It also has four and only four requirements of the outside world: You must pass it path_info, request_method and an object that will be passed on to the classes it dispatches to; the classes you want to route to must know how to respond to methods corresponding to the values of request_method OR call (so a proc will work); the classes must know how to deal with the request object you pass in. Minimize coupling. Always. Even for trivial code.
  • Form handling: I've not seen many good approaches here. At Edgeio we put together a generic forms class that did go some way in reducing the typing by extracting the values needed from the request and generating the data needed by the view automatically. It's tens of lines of code at the most, and can be done with very few - if any - dependencies.

There are more bits and pieces, but common to them all is that no specific dependencies are needed - all of these components can, and have, been implemented in ways that makes it easy to plug them into whatever environment you have.

Why rails is total overkill

I can piece together all I need easily from libraries I like. I don't need (or want) Rails to dictate what I use:

IF I need sessions, there's a lot of libraries handling persistence, and tieing it into Rails is less than 10 lines of code, and it's less than 10 lines of code I write once and will reuse elsewhere (but generally I'm getting more and more negative to sessions - if you need them so often you can't just persist them in your database without worrying about performance, you have a code smell that makes scaling hard).

For ORM's I've picked Sequel for my blog, but there's a number of alternatives.

For request processing, just plain Rack::Request meets all my needs.

Rendering views? I rolled my own in about 30 lines of code that's sufficient for this blog - for something larger I'd pick one of the huge number of templating languages (up to and including XSL, which I've used in the past because it has some nice properties such as being able to feed the XML + XSL straight to a browser to let you see the raw data passed to the view in the browser with "show source" during debugging).

Routing/dispatching I as mentioned needed a whopping 40 lines or so for, and now I have a reusable component that will plug happily in if I ever need to replace Rack, or even if I replace everything else.

I'm sure any Rails fans reading this (all two of you, judging by my number of subscribers at this stage) will be fuming and be aching to complain about how many extra things Rails gives them. The problem is I don't need more. I've written web apps in many languages (including C++ - I kid you not) over the years, and the above are all the web specific components I've needed.

Beyond that there are certainly a large number of libraries that may be useful for specific types of apps. But none of them are specific to writing web applications. None of them need interdependencies with a web framework.

To sum it up: A difference in philosophy

Applications should be composed of components that show:

  • High cohesion: Each component should do one or a small number of things that are tightly related and do them well, rather than trying to do "everything".
  • Low coupling: You should be able to replace any component with another one without having to reimplement a ton of complex interfaces.

Rails fail miserably there, and that makes Rails overkill to me. This blog is as small as typical "demo" Rails apps, and yet it doesn't use any framework, just independent libraries such as Sequel for the models, Hpricot for assorted HTML mangling etc.

It's only coupling to Rack is that it expects something to call the "call" method of the routing class with something resembling a CGI environment. Changing it to use the CGI class is about 10 lines of code. Changing it to bypass both Rack and the CGI class and parse the bits it needs of it's own environment is perhaps another 20.

Half the code is a collection of tiny reusable components - some are Rack middleware whose only dependency on Rack is the calling convention (one method call and the expected format of the result), and some are things like the 40 line dispatches.

That's why Rails is overkill: You can easily build web applications without the "magic", and without the interdependencies and all the rest that comes with it.

Could some things in Rails be useful? Yes, there are a lot of useful things in Rails, but they could practically all have been done as independent components, and we'd be all the better for it, being able to pick and choose the pieces we need rather than dragging in a huge framework and tons of dependencies and all kinds of other baggage that I for one do not want.



Comments - Newest first

2009-09-25 15:07 UTC
Hi, I applaud your commitment to giving out great information. Easy to read, engaging and spot on! Well done.
2009-02-10 21:14 UTC
Vidar Hokstad
Soh Dubom,

Thanks for the comment - I'll definitively write more about Rack when I have the time. Keep an eye on my Rack tag page.

The great thing since I wrote that post is that most Ruby frameworks now support running via Rack, so in most cases you can now pick and choose and use the framework for the "hard" things without giving up the ability to slot in Rack middleware.

2009-02-10 01:43 UTC
Soh Dubom
Hi Vidar. Sorry for the railers, but I completely agree with Vidar's thinking. But my case is that I don't have (yet) Vidar's know-how so I decided to go look for a framework that could act as a thin layer above Ruby ... actually there's a few choices and I decided to go with Ramaze. But as my knowledge and experience grows I would definitely try to do it with Rack and as a suggestion, it would be nice if Vidar could create a full tutorial or even write a book on how to do it with Rack ... that would be very nice ... cheers :-)
2008-05-26 09:02 UTC
It's similar to Catalyst.
2008-04-06 06:43 UTC
Matthias Georgi
I agree, that Rails is probably overkill, but in most cases I prefer having batteries included instead of wiring things together, as it gets your job done faster.

The degree of coupling in Rails is in my opinion not as high as you are stating. Only request processing and routing is hardwired, all other components can be easily exchanged.

Most of the convenience in Rails stems from the comprehensive library of helpers, which are in fact coupled to other components like ActiveRecord or Prototype.

So you are basically right, that request processing and routing should be cleaned up, so that they would only expose a small and simple interface for other componentents to work with.

2008-03-30 23:15 UTC
Vidar Hokstad
My point is that calling something a "framework" is usually an excuse for increasing coupling in places where it's not needed, and that increasing coupling reduces the flexibility. There's no reason to choose away the flexibility in web development because there are very clear natural boundaries between most of the key components that can be kept very clean cut with good design.

Doing so is a benefit because it allows developers to pick and choose individual components when needed, while it still doesn't hinder anyone from shipping a bunch of components together to make it easy for newcomers. It allows deferring a lot of decisions about suitability that needs to be made early on if you have to buy into a whole suite of components in one go.

The whole continuous discussion about Rails and scaling for example is only an issue because buying into Rails means buying into a whole stack instead of buying into a series of components with low coupling - the people who keeps dragging it out do so largely because if they do try to go for Rails and they run into problems they potentially face a large re-engineering effort rather than a minor inconvenience of replacing specific components.

The reality of whether their concern is justified or not isn't relevant (I've scaled Ruby apps to larger systems than most people, though not Rails, and I know it's perfectly doable, but I also know it's more work than scaling many other platforms - I still think it's worth the effort and becoming easier, but I understand why people worry)

So it's about coupling, as I've expounded on in the comments as well as in my entry here: Why coupling is always bad / Cohesion vs. coupling

2008-03-30 20:01 UTC
Early in your article, you say: "Rack is not a framework". Exactly. Rails is. What's your point exactly? That full-stack frameworks aren't for you?
2008-03-25 11:41 UTC
Vidar Hokstad
Ikan,

If a web app is well structured that is the case regardless of framework. I just started a new job in January as Director of technology for a web development agency who has a number of relatively large legacy apps. It took me minimal amount of time to learn the codebases, because they were all well structured. Only a small number of them used a framework.

"Convention over Configuration" is another matter, and it does in _no way_ preclude low coupling. CoC is a philosophy that can be applied just as well to individual components. In fact, if done properly, CoC can REDUCE coupling by ensuring that any components that comply with a minimal set of conventions will "drop right in".

Rack is actually a good example here: Rack's low coupling is entirely due to conventions. There is no configuration. You abide by a tiny number of conventions that are so simple you could write them on the back of a matchbox, and any component that follows those rules can be plugged into any application that use Rack to interface to the web server. Rack exhibits high cohesion and extremely low coupling: It does one thing, and does it well, and it knows nothing about the modules it connects to other than that they abide by the conventions.

Nothing prevents a framework from being packaged up with a full set of components suitable for a newcomer without giving up the low coupling. A loosely coupled set of cohesive components packaged up together remains a loosely coupled set of cohesive components - they don't magically fuse.

And personally, I did come from PHP when it came to web development, though I know a dozen or so other languages. Exactly because I've "rolled my own" several times, both in PHP, C++ and other languages, I know how little you actually need to get you the benefits.

That's exactly why I don't see much value in dragging a long a huge tightly coupled framework - it takes more time to properly learn a complex framework than piecing what's needed together from independent components. But it could be much easier if more focus went in that direction.

Rack isn't a replacement for Rails. It's not trying to be. That's the point. Rack is one element - one highly cohesive module. But one who's design and philosophy will hopefully be part of getting us away from the large frameworks.

2008-03-25 06:24 UTC
Vidar,

On many points, you are right, but the title of this blog is, in and of itself, overkill. One of the primary philosophies behind Rails is the idea of "Convention Over Configuration" - this idea that out of the box, a framework and applications built on that framework should be understandable by anyone familiar with the framework. I know for a fact that if I dropped off my current Rails project, any seasoned Rails developer could drop in. In fact, that's how I took on the current project I am working on - with minimal instruction from the original owner.

That's not to say CoC is the be-all end-all philosophy behind a framework. Perhaps a future iteration of Rails could include a default Spring-lite-like configuration with the default wiring between ActiveRecord and ActionPack being as they are. But the way it stands, much of Rails success is attributed to the fact that it just works out of the box for a newcomer. You DON'T need all the things Rails provides, save one thing that is still severely lacking in the Merb and Camping frameworks - the community. Rails' popularity has spawned a vast, knowledgeable, growing community. Maybe Rails is overkill for you (as the earlier commenter points out), but for someone coming from PHP or J2EE looking for an alternative solution to their web development problems, would you seriously recommend Rack? I wouldn't.

2008-03-25 01:48 UTC
I've been thinking the same thing for months ... I *love* Rack.

Rack is love.

2008-03-24 00:36 UTC
Vidar Hokstad
An issue was mentioned on DZone, and I added a clarification there - it's worth repeating here:

The purpose of a framework IS tight coupling.

I disagree - tight coupling is never a benefit. The purpose of a framework is high _cohesion_. The reason I linked to the Wikipedia entries for coupling and cohesion is that people tend to confuse these.

Tight coupling means that the components expose wide interface towards each other and/or depend on internal details. That is always a disadvantage, as it makes it harder to replace components with other components, even when the other components provide all the needed functionality, as any replacement also need to adhere to a wide set of interfaces or copy the internal architectural choices of the component it replaces.

The problem I have with frameworks is exactly that there are very few frameworks that doesn't achieve high cohesion by sacrificing low coupling. So also with Rails. It's a matter of discussion what the relative importance of high cohesion vs. low coupling is.

My problem with Rails (and most other frameworks) is that for web development I don't see _any_ value in sacrificing low coupling for a typical web app, because there's nothing in the typical model that requires high coupling to achieve high cohesion, meaning you can achieve practically all the benefits without the downside of locking yourself in to a specific set of components.

2008-03-23 16:30 UTC
Vidar Hokstad
Matthew, Thanks for the comment. I appreciate that Rails grew out of the needs of a single company, but the point is that tightly coupling such a large code base is a bad design decision.

I've made plenty of bad design decisions myself, and I strive to learn from them, as I try to learn from others. In this case, though, Rails -and most things that get labeled frameworks - are defying a design principle which is old and well understood.

High degrees of coupling limits choice and also limits the possibility of reuse. It also ties you into technology choices early on that may prove to be disastrous down the line.

That Rails is big isn't the problem. That it consists of tightly interdependent components is the problem. If you pick Rails, you make a huge number of technology choices in one go at a point where you don't know what you'll be facing 6 months or 12 months down the line, at which point you're stuck.

2008-03-23 16:17 UTC
Matthew Williams
I think a more proper title for this post should be "Why Rails is total overkill for _me_ and why I love Rack".

Rails isn't trying to be the catch all solution, for the most part it's simply serving the purpose of a single company, of which the framework came out of and anyone else wanting to use it is going into the framework knowing how tight a lot of it is and that it may contain unnecessary features.

About me

E-mail: vidar@hokstad.com Skype: vhokstad
Twitter: vhokstad
View my LinkedIn profile.

I was born April 21st, 1975, in Oslo, Norway. Since 2000 I've been living in London, UK. I'm married and we just had our first child, Tristan Ikemefuna Hokstad.

I'm working for Aardvark Media as Director of Technology. I'm also currently on the board of SpatialQ, a startup in the GIS space, and an advisor to Skoach, a startup doing a time management app for people with ADD.

Twitter Updates

    follow me on Twitter