Rails之父DHH在RailsConf2006上的Keynote Address TRANSCRIPT Part 3 of 8
RailsConf 2006 Keynote Address
by David Heinemeier Hansson
01. Discovering Resources on Rails
02. Problem with CRUD?(DHH learns to stop worrying and love the CRUD)
03. Get, Post and Clean URLs(Don't Do Busy Work)
04. Accounts, Controllers and CRUD(Evaluating the richness of the domain)
05. CRUD is Not a Goal but an Inspiration(Not one paradigm captures all the world all the time)
06. Controllers, Design Patterns & MIME(Have one controller for many MIMEs)
07. Doing By Hand Leads to Good Design(IDE is not necessary)
08. Get, Find, Post Redux(Active record and assigning IDs)
03. Get, Post and Clean URLs(Don't Do Busy Work)
All of this should kind of raise a little bit of warning signals among some people. And that's good, we'll come to that in a minute.
[showing PPT page 15]
[showing PPT page 16]
Okey. Why really bother with all this busy work just to get those clean URLs and just to get that convention?
Well, that's the question I've been asking myself whenever I heard of the so called REST people clamor up about things being important. I didn't really get it actually. I didn't get why all of this work was worth that. Because there's one thing we've been trying to do in Rails, (it) is to make sure that everytime you spend any thinking moment about something, it actually means something -- you're not just doing busy work, you're doing something that's creating value.
First of all, it's consistency. It's pretty nice that the URLs themselves are consistent. But way more important is that the controllers now achieve a level of consistency that it didn't have before. I have quite a few controllers in my basecamp code and in most of the other projects that are somewhat sprawling messes. Controller of these things was never quite clear when you're supposed to put another action there. And when they're supposed to live under one controller, the other controller ... or whether it should be combine with something else all together(?)
If you follow this set of conventions, it suddenly becomes instantly clear. There's not even an argument about what's going on because the only thing you're trying to exposed to the world is CRUD. So, all controllers should just have the methods, of things like index, like show, like update and destroy -- and they should named exactly that, not something else.
Having that level of consistency and working with that for just a little while means that you can start to forget about it. That's the power of conventions in general in Rails. And one should picked(?) up that, tables are plural, classes are singular, you can't forget it. And that's the good part -- you forget that that's actually you used to be concerned, it used to be something you have to think about and make a decision.
Well, decisions are bad, because decisions take up your brain power and it requires brain cycles to consider which or the other. The more decisions you can take out of the whole thing, the more brain power you free up to consider the really important things.
That's of course how this leads to simplicity. It leads to simplicity in the fact that it's not even something you think about anymore.
There's a good couple of ...(?) why we're bothering with this in ...(?)real. Reveal(?) is going on but one of them is also discoverability(?). If everybody is doing the same thing in the same way, well, it means that you can easily go from one application to the other and expect the same things to happen. That's been actually the suprising big successes of Rails as being something silly as a direct structure. The fact Rails shipped with premade folders of where to put stuff, as being something that's led a lot of people just develop applications in exactly the same way and not even think about where they should put stuff. This is on kind of the same level.
[showing PPT page 17]
But all of these things are actually somewhat side effects of the grand prize of this. And the grand prize is a familiar theme among the most Rail-ers. And it's the fact that constraints are liberating. If you choose to adopt this set of conventions, if you choose to develop your applications in this way, you're putting yourself under a pretty heavy set of constraints. You basically are saying, hey I would like a whole world of just CRUD operations. Now the interesting thing is that, in some ways, that's a straight tie(?) for your mind, it's a way of encapsulating all the insanities that used to be around these things, and just free yourself to be happy about not even caring.
[showing PPT page 18]
Now, once you started to do all of these things, your controllers would look a little bit like this when we fletched out all of the seven most common operations you indulge in when you do HTML-based CRUDing.
You saw the four of them already, but there are few more. So for example, there's not a single represenation of most models. Most models have both the representation of showing something, and actually adding a thing or two, and creating a new thing of it -- and we need to represent that. That's been one of those things where people have sentence to pass that CRUD is simply not enough.
And they're right. There are few exceptions to these things. The exceptions were trying to represent something else in the main scheme. So as you can see the main scheme is that each URL, the hierarchical part of that URL, is just identifying either collection or element. "/people", that's the collection, that's what you're working on the collection, index, showing the full set of the collection, creating, adding something new to the collection. "people/1": operating on the single element: showing, updating, so and so forth.
The exceptions were representing with the semicolon to say, yes we really kind of still need to describe more than four functions, but at least let's distinguish the two and make sure the hierarchical part of it is just ...(?) of(?) application, and we'll use the semicolon to describe the exception behind it. So the default case for showing "people/1" will be showing the thing; if we need that alternate view of the same element, we'll do semicolon at it. This is still not important.
The important part comes in what it does to the way you're modeling your domain -- that's the real power of CRUD. And I'll have two examples to demostrate all of that works.
[showing PPT page 19]
So, a common domain is an idea of having groups, and having users, and having a many to many relationship between these groups and between these users. That's actually a little bit of a tricky thing because as soon as we start doing this, also its annoying decison start to emerge.
The GroupsController, for example, let's say we choose to have the group being the main form of interaction when you manipulate these relationship to users. So, the GroupsController will have methods like add_user() and remove_user().
Well, already here I'm getting flashbacks to PHP, and the flashback is that these method names -- they're trying to represent scopes. Why is it not just called "add" or "remove"? Well, because we're talking about something else within something else. That's why we start to have to disambiguate these things, and that's just not good. That already takes off my aesthetic radar that something is a little bit off. Even more so are the URLs for these things. If we follow just the same name and scheme as we were before, the way we describe, the way we will get to add users would be something like "/group/1", first grab the group we're working with, then try to add a user to that when we need to signify that it's the add_user action we want, then what the user_id is.
Errrrr... that's a little too much stuff going on here. ...(?) be making two concepts be mixed in. And it's just as bad with the remove_user(). And even worse so, there's just one way of doing. We could just have, well, done the other way around -- that we started with the users and users are things to join groups and leave the groups. Well, the reason we can feel this ambiguity is that we're missing something. And we can draw this missing thing out of the domain by saying, "this is not CRUD, this is more operations than just the base ones." What is missing? Why can't we describe this domain with just CRUD operations? Well, it's because we have REALLY considered the domain, because we're missing a piece, and the piece is "naming the link between groups and users". That link is called memberships.
[showing PPT page 20]
As soon as we force ourselves to think more about the domain, (and) new concept pops up. That concept that it's memberships, that the relationship between groups and users is not just a many-to-many unnamed magical relationship, it's actually a real construct of the domain, and we can choose to call that something. And as soon as we named that thing, we can start to reason about it.
Naming is one of those power techniques we have in object-orientation, that we can start putting something... we can start wrapping these constraints, these concerns we have in domains into logical small units. And when we add this memebership class, everything in the controller suddenly becomes clear. We can expose this domain -- it's just another CRUD operation.
[showing PPT page 21]
Creating many-to-many relationship between groups and users is just an act of creating memberships. And when we can create memberships, we can stop having that namespace thing going on. Our operations are now back to the default ones, we can have create, we can have destroy, we can even have a way of looking at these memberships individually, which we didn't have before -- since we didn't name the things we couldn't have a way of holding it, we didn't have a way of identifying them individually.
This is somewhat possible because the recently development in Rails has made it easier to start naming these relationships. Thanks to the ":through" operator, it's now just a whole lot less painful to inject a real model instead of just a many-to-many relationship.
And now the URLs for this, of course, gets nicer. If we wanted to destroy a membership, we just referencing that membership because the membership itself has a refering(reference?) point and you can remove it.