- Rails Routing is Broken
So, after having worked with Ruby on Rails for a few weeks, I can now safely say that it doesn’t live up to the hype. Yes it does some things very nicely, which I appreciate. But it also does some things very, very badly.
Now if you read this blog, you know that I like to rant a bit about software that is broken in some way or another. Since I won’t be able to avoid rails for some time to come, and I’ve found more than one annoying detail in it that is rant worthy, I figured I better start another one of my occasional and possibly soon abandoned series: Railing on Derailed Rails.
This here is the first entry, and it’s on rails routing.
So, first a very quick introduction is in order. Rails adheres strongly to the MVC paradigm of structuring web UI code. You don’t need to know much about the details of that beyond understanding that for each, well, let’s call it “entity” in your web app there’s a corresponding ActiveRecord-based model, an ERB view, and an ActionController-based controller. And for the purposes of this article, we’ll only focus on the latter.
The rails developers appear to have drunk the REST Kool-Aid, but on closer inspection managed to miss a significant point: REST deliberately avoids imposing a strict mechanism by which resources on the web server are accessed. If I may quote some applicable parts of Fielding’s paper:
Several attempts have been made to model the Web architecture as a form of distributed file system (e.g., WebNFS) or as a distributed object system. However, they exclude various Web resource types or implementation strategies as being “not interesting,” when in fact their presence invalidates the assumptions that underlie such models. REST works well because it does not limit the implementation of resources to certain predefined models, allowing each application to choose an implementation that best matches its own needs and enabling the replacement of implementations without impacting the user.
The resource is not the storage object. The resource is not a mechanism that the server uses to handle the storage object. The resource is a conceptual mapping — the server receives the identifier (which identifies the mapping) and applies it to its current mapping implementation (usually a combination of collection-specific deep tree traversal and/or hash tables) to find the currently responsible handler implementation and the handler implementation then selects the appropriate action+response based on the request content. All of these implementation-specific issues are hidden behind the Web interface; their nature cannot be assumed by a client that only has access through the Web interface.
It is the nature of every engineer to define things in terms of the characteristics of the components that will be used to compose the finished product. The Web doesn’t work that way. The Web architecture consists of constraints on the communication model between components, based on the role of each component during an application action. This prevents the components from assuming anything beyond the resource abstraction, thus hiding the actual mechanisms on either side of the abstract interface.
Another conflict with the resource interface of REST occurs when software attempts to treat the Web as a distributed file system. Since file systems expose the implementation of their information, tools exist to “mirror” that information across to multiple sites as a means of load balancing and redistributing the content closer to users. However, they can do so only because files have a fixed set of semantics (a named sequence of bytes) that can be duplicated easily. In contrast, attempts to mirror the content of a Web server as files will fail because the resource interface does not always match the semantics of a file system (…)
So what is it exactly that the rails developers failed to understand here?
- REST in no way equates a resource as being a database or application object; in fact, it actively discourages such a direct modeling in order to more easily provide for stable web APIs, or actions on a resource.
- REST in no way requires or encourages you to expose object hierarchies you may model in your database or application as nested resources on your web server.
- REST does not limit the amount, or the form of actions you may take on a resource (that’s the web file system example).
- REST does not require servers to hold application state; in fact, not requiring this is one of the most fundamental principles in REST.
Let’s look at those in some more detail.