Wednesday, April 18, 2007

Looking For A Good Argument Against REST

I know why I'm skeptical. Just because it's good in the right context doesn't mean every single thing on earth needs to support it. It's like putting mustard on ice cream just because it tasted good in a sandwich once. There's nobody out there saying "some things need REST, some things don't, and here's how you make the judgement call." There's just people saying "REST? What's that?" and people saying "REST! Hallelujah!"

It's just the typical frenzy. The religion of the hammer. Where everything looks like a nail, and everybody looks like either a believer or an infidel.

Let me correct my headline: looking for a good argument about REST. I would love to see an intelligent, rational blog post going over where REST is bad and where it's good. All praise the mighty hammer, sure, Amen, whatever, but what the grownups among us really need is a clear way to decide when to use it and when not to bother.

Obviously the whole value of REST is that it makes URLs into messages passed within an incredibly large virtual machine. Servers run on Unix but the Web itself looks more and more like Smalltalk every day that the REST frenzy grows. But the idea that every last thing in every last corner of the Web should in every single case be a URL-accessible resource is just insane. It's like, either you have resources calling URLs on each other (objects passing messages to each other), or you get infinitely fine-grained access. It's absolutely one or the other.

13 comments:

REST makes sense mostly for web sites where deep linking is a feature you want.

REST is absolutely horrible for web applications where you want to control the workflow of the application or protect your valuable data from being scraped. If you have valuable data, say hotel content for example, REST sucks and makes it easy for a competitor to steal your data, and believe me, they will.

Using a RESTful framework all the time makes you have to do stupid things like protect your controllers with guard clauses and security system that redirect when the user isn't authorized.

Seaside's a good example. By having urls be meaningless keys into the current session, a site is impossible to scrape with brute force hacking of the URL.

If a user gets to a particular point in an application, it's because I showed him a link that allowed him to go there. There no need to verify his presence is allowed with a security check. Using REST would actually require more code, not less.

REST makes sense sometimes, but not nearly as much as the Rails crowd seems to think lately, and certainly not all the time.

REST isn't "absolutely horrible" if you want to control the workflow of the application...okay, so maybe it is out of the box, but not if you think a little differently.

Now I admit that what I've done doesn't touch seaside, but I've only taken it as far as I need to. And I get to keep REST...sexy. The point is that with a sufficiently dynamic language and some creativity, you can get the best of all worlds.

Let me start with a quote from Roy Fielding's dissertation on REST (where the entire concept comes from). "communication must be stateless in nature, as in the client-stateless-server (CSS) style of Section 3.4.3 (Figure 5-3), such that each request from client to server must contain all of the information necessary to understand the request, and cannot take advantage of any stored context on the server."

So to be truly RESTful, you cannot store any session information whatsoever... and there are very few applications currently that do this. People use some of the components of REST and say that their site is RESTful... but (in the idiom of Rails), if you put session[anything goes here] = anything else anywhere in your application, you have just violated one of the absolute most basic principles of REST... the only more basic being that you must be using a client-server architecture.

My point is this: until people start developing sites that are _truly_ RESTful, I consider the entire conversation to be somewhat moot.

Were I not to feel that way, I suppose I would lean towards the 'best tool for the job' viewpoint: if you're spending more time hacking a way around using session than you are designing the website's solution to your problem domain, then you probably ought not to be using REST.

Now, this isn't to say there aren't concepts in REST that are useful beyond the scope of trying to comply word for word with Fielding's dissertation. Meaningful URLs, for instance: while I don't consider them to be necessary in every case, they are certainly handy in a lot of cases. I wouldn't want to try to develop a blog site where you could only enter at the front page, and navigate from there to whatever post you were looking for. On the other side of that, I wouldn't want to try to develop something like DabbleDB so that you could link into a custom view of a specific dataset with all your options already predefined via a "meaningful" URL, either.

The pain point for me is when a resource can be viewed and/or transitioned in more ways than are offered by the simple HTTP verbs. If you're trying to come up with some way to finagle custom views of resources into being resources in their own right, you're in for a long and punishing fight that you could have done with by simply admitting there are occasionally more operations you want to perform on a resource than GET, PUT, POST, and DELETE.

@ramon - the thing is, all that hotel stuff is usually better served by aggregators anyway. proprietary information-delivery sites are using the paradigm of the channel, the idea that you control the information from possessing it all the way out to when the users get it. I think that paradigm's outdated.

But you're right, Seaside is a good example, and technodolt's right that creating a DabbleDB which used meaningful URLs for every single thing would be a nightmare. I think the decision to make REST possible in Seaside, but not a priority, I think that was a good idea. Saying REST is an option but not the primary design concern at an architectural level, I think that's correct. I'm still just not sure entirely why.

@pat, have you ever noticed how certain actresses and models are gorgeous at 19 and unremarkable by the time they turn 24? And conversely Christie Brinkley's hot at 50? REST is sexy, sure, and sexy is all well and good, but there's sexy that lasts and sexy that doesn't.

The truth is the tech industry has "it girls" the same way Hollywood does - as consistently, and as uselessly. It happens because people get excited about new stuff, and people churn out new ideas as regularly as new teenage runaways arrive in Hollywood looking to become stars. But for every Scarlett Johanssen there's a hundred thousand brainless bikini chicks. REST is sexy, sure, great. But can she act?

If I were to say that REST was 1% good idea and 99% fad, how would you prove me wrong?

@technodolt - you're right about the impurity of Rails' RESTful implementation, but what's the business case for a pure one? Picture a strange, impossible beast: a manager who understands technology better than any geek, but only cares about the business case. Why would somebody like that care about REST one way or the other?

Assaf, rest isn't the best idea we've got, it's just one idea. It's also an idea that makes really big assumptions like "everything should be linkable", but that assumption isn't true.

REST is great when you're working in a context where you want things to be linkable, which is when you're building web sites, things like blogs and forums.

The web has grown beyond mere websites, applications are moving onto the web, and when working in the application context, you usually don't want things linkable. Dabble is a good example here. Applications in general don't like deep linking because they are more than mere content, they are process.

Even on the web, such things exist, I don't want someone deep linking into step 3 of my checkout process.

A good framework must provide both options, the ability to be RESTFUL when dealing with documents and content, and the ability to use meaningless urls that are only valid in a particular session for complex worflow scenarios.

I watched your screencast, and I'm curious, how does your approach work in the presence of validations? Won't a validation prevent you from saving an incomplete active record to the database between steps? Your approach would seem to require all fields allow nulls or empty strings, am I missing something?

REST is definitely a good idea, but I'm not sure about that best part. It depends what you're building stuff for. Take for example Gmail. It could make sense to have a REST API for Gmail, and certainly REST is great for Web service APIs, far better than the XML approaches, but saving drafts with REST would be ridiculous.

I think REST is a good idea, and it could be the best, or not, but it's definitely not necessary in every single case, and I think a little more calm, rational analysis and a little less breathless exhuberance might make a lot more sense. Like if you say REST is better than SOAP, well sure, absolutely it is. If you say baking REST into the framework is so handy that it's worthwhile, because it makes writing APIs much less work, I'm with you there as well. But the idea that REST should be an integral part of the framework because REST is in and of itself incredibly important, I think that's off. It sometimes seems like people think you should make stuff RESTful because then it'll be RESTful. It's not like that; something has to have a reason to happen if it's going to be a good idea.

Btw -- it's not Seaside vs. Rails -- you have to do stuff to make REST happen in Rails as well. I just think, a little less "everything should be like this!" and a little more "you should use this in X situation."

@Ramon: I wrote yet even more code to get around that :) So basically what you can do is clear out the validations for an instance at one step and give it whatever arbitrary validations you want.

It works great for our app. The only downside is that we have to include a status field, and queries in our app only look up records with a particular status. That's easily solved with with_scope filter in Rails.

I have a feeling that Seaside wouldn't need that hackery, because you wouldn't have to stick the record in the db until the very end. Is that accurate?

@Pat, ok, I see, though I see another down side. Your validations only exist in the model, meaning you'd have to leave the schema wide open with everything nullable. This isn't going to work in the face of unique constraints on fields, something only the database can support well.

You're right, Seaside wouldn't face this problem because you could carry the partial object through the workflow without ever hitting the database until the final commit. Though, this isn't unique to Seaside, it's just a matter of keeping temporary data in the session until it's ready to be committed. Rails could likely do the same thing, nothing says you have to save the active record at the end of every step.

The fact is, workflow requires state, but the database is more meant for permanent state, not transient session state. A domain object being carried through several steps of a workflow is really transient state until the final step. I think sessions are the right answer here.

@Ramon: I certainly agree with you. One problem with Rails is that it's simply not built to store tons of state in the session, whereas in Seaside that's obviously one of the key points. So in Rails, you have to do some fudging in places where sessions would be the most appropriate solution.

Fortunately for us, the workflow is only a small part of our app. And our workflow requirements are very, very simple. Rails is an excellent solution for the rest of the app, so it makes sense to work around it for the little part we need.

I definitely want to have a go with Seaside though, I have a feeling it'll either pull me in, or at least lead to some major changes in how I develop with Rails.

> Using a RESTful framework all the time makes you have to do stupid things like protect your controllers with guard clauses and security system that redirect when the user isn't authorized.

Holy crap, Ramon! You just mentioned the exact argument I am currently having with myself. I wrote up a post a few moments ago regarding my frustration with accepting the RESTforAll paradigm as the ultimate hammer.

REST is useful in a specific context. After that, who really gives a damn. No one bitches about the ugliness of Amazon.com or Expedia urls, do they?

I am onboard with Giles' thought process here. This has little to do with Rails or Smalltalk. The fact is that sometimes you have state that is part of a process and you start to do silly things when you feel the need to constantly hit the db to store that state in order not to use session. This is especially problematic when you have not collected all of the state that would constitute an atomic and relationally sensical unit for the business rule(s) you are encoding. Though I use Rails and am a long time Smalltalk user as well and really like both, I can say that most Rails apps that are "RESTful" that have more than the simplest of business cases almost always use session. Check out beast for example. Going totally sessionless would be a dream for all kinds of reasons, but so far I haven't been smart enough to see how that is possible for the ecommerce systems I build.