Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

What an awesome way to advocate for code change. Very pretty.

Unfortunately, I also think it's faulty. First, it doesn't actually advocate anything concrete. There's some hand-waving to Sinatra and other Rails features, but nothing concrete. If you're going to make such a pretty proposal, it should come with a call to specific action that people can get behind.

This is double true when it comes to API design. It's all fine and good to general ideas and principles guiding you, but when the code hits the editor is when all the constraints and trade-offs are revealed. I could fill a book with all the premature ideas I had for API rewrites that turned out not work when applied to the tough reality of real code.

But I'm wearing too far into hand-waving territory too, so let me address a few of the points raised:

1) "Not specifying URLs directly leads to poor [URL] API design and other ills": There are only so many (reasonable) ways to specify a URL if you want to follow REST principles. You name your resource and you give it an identifier.

/products/1-some-perma-id became a pattern because it was both simple, repeatable across models, and extractable. Why spend time coming up with a unique URL structure for every model that you want to expose when they follow the same pattern of using the model name as the url identifier?

This is exactly what Rails does and always have done. Spot patterns currently done by hand, extract said pattern into a convention, allow people to move on from thinking about how to do X until they hit an exception. This, in my mind, is exactly what leads to great API design and simple solutions. You do the same as everyone else when the choice is less important than the consistency.

Now I welcome the praise for Sinatra. I think it's completely awesome. I'd use it for smaller projects myself. But that's exactly where conventions don't give you that much. If you're exposing, say, 20 urls to the public, you don't gain a bunch from having a convention that follows a set pattern. In fact, cutting out the middle man of an abstraction can make the code seem easier to read and more immediate.

That trade off flips when you have 100, 500, or (as is the case of Highrise) 2000 routes exposed to the public. When 95% of those follow the same pattern, there's big gain in the consistency of a convention. The last 5% are handled by outlet valves that allow you to declare whatever exceptions you need.

2) "The Seven Action Names Don't Help": I think the default constraint of 7 is the most important part of the positive effects you get from following REST in Rails for internal organization. Again, this isn't theory, but extracted experience from practice.

Rails used to require you to map everything by hand. Lots of people ended up with mega controllers that had 25 actions because there was no easy pushback. By the time the controller was too big it felt like too much of a hassle to break it up just to add "one more action". We still have GlobalController in Basecamp to remind us of what that was like.

Having the default conversion that turns /product/1 into show is also just pretty code. The two alternatives lined up are not very pretty. I'll take "def show" over "get(:member) do |id|" or "get "/api/v1/report/:id" do |id|" any day when it comes to a large, consistent URL surface.

3) "Assets are resources": I completely agree here. This will be addressed in Rails 3.1 when we get the asset pipeline going.

But as always, the proof is in the code. I'd love to see an even simpler routes system, but none of the arguments presented in the article gives any indication that the proposed ideas will lead to that. I've been both surprised and wrong before, though, so please do investigate.

Again, though, kudos for the presentation. I wish more people passionate about API design would take the time to do something as pretty. But with more concrete code examples, please ;)



I think it is advocating something concrete: Drop the separate routing layer. Then it gives two concrete examples of how to handle urls: Sinatra-style and HTTP-style methods in the controller. I think the biggest problem in the article is its use of an ugly url in the examples.

I actually like the HTTP-style method approach. You mention pushback to prevent people from creating mega-controllers, and I think this takes it even a step further. It really ties the controller to the resource. As mentioned in the article, this is already how the methods are called in the tests.


A necessary component of mass production is consistency. Like it or not, Rails has reached the masses of web developers and enforces its constraints and conventions to facilitate the production of new web applications. I empathize greatly with DHH when he talks about large apps and the need for conventions. The truth is that most web developers will never devote as much attention to URLs as some people think they should. Full stop.

With that in mind, stable conventions are of paramount importance if Rails is going to maintain its practicality when building large web applications. On the spectrum of poor conventions to good ones, Rails has been much closer to the idealistic end of pushing REST principles and the concept of resources over haphazard URLs and actions. We owe a debt to Rails and its designers for the abundance of REST in production today.

That said, I empathize infinitely with Adrian Holovaty. I love URLs and I want them to always be beautiful everywhere. It's true that Rails gives less obvious control over URLs than Django or Sinatra, but it does so for the reasons mentioned above. There are probably small changes that could be made to make Rails more URL-aware for those of us who would like to craft every URL with loving adoration, but those changes absolutely must be compatible with the consistency already embodied in the Rails routing system. I haven't thought much about what those changes might look like, but I agree with DHH that the post above feels very hand-wavy in the proposal department.

Just remember that we URLophiles are a minority. Rails must work well for the majority and they will never care about URLs.


I'd be curious what hand-crafted URLs you feel aren't possible with the new Rails 3 router. We've gone far to allow all kinds of hand-crafted urls. For example, here's an example:

get 'something/fun/:id', :to => "controller#action"

You can map just about anything that falls outside of the conventions with a variety of that.


At that point, I suppose it is just a matter of taste: should the routes be specified inside each controller class, or should they be specified in a separate configuration file.

The over-engineer in me likes the way Rails 3 does it. That way I can pretend that my code is reusable, as the URL is decoupled from the code that eventually implements its handler.

But I suppose there is also something nice about a controller which self-defines the way in which it can be accessed.


The over-engineer in me likes the way Rails 3 does it. That way I can pretend that my code is reusable, as the URL is decoupled from the code that eventually implements its handler.

You don't have to pretend ... it actually is reusable. I don't get what's "over-engineer"ed about it.


Whenever I've tried to reuse the same controller for two URLs, I usually end up with some conditional logic within the controller to handle difference in parameters available from the URL.

I think a better approach would've been for me to subclass one from the other, or have a common parent class, and then handle the parameter differences within each subclass. At that point you'd end up with a 1:1 mapping between controller class and URL anyway.


That 1:1 mapping is a good thing, but I don't think that's a reason to completely do-away with routing altogether. Sticking the route in the controller just makes the code harder to follow.


I don't understand how a monolithic route mapping layer & a separate resource layer is more reusable than a modular resource + route layer. Care to explain?

I find the Sinatra approach leads to less code and less complexity, especially for larger apps. This is because it is easy to extract middleware using Sinatra, since I break up separate resources anyways, instead of the single Application object.


Well said. As soon as an application hits ~100 routes everyone would be writing their own routing layer just to be able to flexibly manage it all.

Convention born of common usage is a strength of Rails.


This applies even with Rails routes. Our routing scheme does not match that of Rails (we want seo friendly routes, that does not always fit the /collection-name/:collection_id paradigm).

I think simple routing systems, like Sinatra, are the way to go here.

From a simple library that does not get in the way, it's not too difficult to come up with a convention that matches your needs. The overall application then becomes simpler because I don't have to fight a heavy-weight routing system that misses the point.


The main argument is flexibility and acknowledging what the role of the controller actually is in a resource-oriented application

Idea 2 is the way to go because it's resource oriented and you get useful stuff like 405's for free which you don't with the sinatra approach.

Please don't remove routing. Having routes is important - it makes the code more descriptive and easier to follow. All a route needs to do is map one URI pattern to one controller, i.e:

/blog -> BlogController

/blog/:post -> BlogPostController

/blog/:post/comments -> BlogPostCommentsController

I wrote a hack for Zend Framework last year to prove how this would work:

http://restafari.blogspot.com/2010/04/restful-php-applicatio...


"get(:member) do |id|" or "get "/api/v1/report/:id" do |id|" have the virtue of being pretty damn explicit.

As far as ensuring API consistency (a fine goal), it wouldn't be altogether difficult to have a rake task that prints the full set of routes to STDOUT for app's using such a framework. Load all of the controllers, make a route table, then emit said route table. This provides a holistic view of Sinatra-like routes similar to "rake routes".

Just the same, I can see how for apps with many types of resources, remembering the precise URL incantation would PROBABLY be more difficult than remembering Rails generated path/URL helpers.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: