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