12:03 PM, Thursday, December 20, 2007

REST and Loose Coupling

It happens again. Over at ebpml.org, JJ Dubray has a couple of related posts about the dark side of REST, and a proof that REST creates strong-coupling. I am not sure what to make of his style of writing, but like good citizen, let me try to make some sense here.

Let me start with his first point about the dark side of REST. A good chunk of his discussion is around SimpleDB, and how the REST community reacted. To quote him,

That was enough to wake up the inquisition lead by the grand priests of REST who were absolutely outraged at Amazon's latest heresy. Bill de Hora, Stefan Tilkov, Assaf Arkin, Subbu ... were all ready to burn the heretic who had committed one of the worst crime in REST history. Funny, how mechanical their reaction is: never discuss the questions always point at what not to do and occasionally what to do. There is never a single inconsistency in a religion -by definition.

Quite the contrary. The discussions were about correctly designing a REST interface. Why care about correctly designing it? So that an interface designed for consumption over HTTP can really take advantage of HTTP. Period.

It does not stop here. To quote Dubray again,

Unfortunately, he wanted you to come to the conclusion (insidiously) that "all action interfaces" are bad (Nice try Subbu).

I think he makes this statement in response to my post Why Bad REST is Easy?. He completely missed the point. Action interfaces are not bad! Having worked with a number of REST-wannabe applications, the common pattern I notice is that developers tend to translate their action-oriented interfaces into REST, which leads to poor REST APIs that fail to take advantage of what HTTP has to offer. Each problem domain requires a different approach towards solutions.

He then goes on to prove that REST does not care about versioning.

It has been notorious that REST is really bad at versioning (I am preparing an article on this topic that will be published early January). Of course the RESTifarian say that there is absolutely no need for versioning since there is only ONE interface (GET, PUT, POST, DELETE) and actions don't exist.

I think his comments are based on the belief that XSD and WSDL provide a versionable contract, and since RESTful applications do not require neither XSD nor a WSDL-equivalent, REST applications do not care for versioning. This kind of FUD is quite unfortunate.

No matter how an interface is described, remote interfaces ought to worry about forwards and backwards compatibility. Versionable XSD and WSDLs are one way to describe compatibility, but versioning an interface does not provide for backwards and forwards compatibility automatically. It is the responsibility of the producer of the application to accommodate for compatibility independent of XSD and WSDL, i.e., you have to code for compatibility. In fact, some of the best compatible systems don't have formal descriptions.

That brings me to the need for descriptions. Remote interfaces need to have descriptions so that we can understand the syntax and semantics, and can develop client applications that work. While SOAP world chose XSD and WSDL for descriptions of their interfaces, in the REST world, the descriptions are URIs, HTTP verbs, and request/response encodings. For instance, take a look at Amazon's description of a GET request to get a list of all the buckets from S3. To make such a description compatible, all it takes is to follow some simple guidelines, such as (a) keep minor additions into inputs optional, (b) never remove required parts of data from responses, and (c) follow the must ignore rule. See also Extending and Versioning Languages: Strategies for more discussion along similar lines. These rules apply independently of whether you are describing your data as XML, or JSON, or some other format. These rules seem hard when you try the first time, but over time, they become natural design principles.

Upon showing the dark sides of REST as above, Dubray moves on to prove that REST introduces strong coupling between producers and consumers. The proof is long in English, but I think his proof is based on the belief that RESTful applications don't have descriptions, which is quite appalling. As I just showed the Amazon S3 example, RESTful applications do have descriptions. Even this blog has a description - the description is hyperlinks and HTTP verbs, which my user-agent and my web server understand and support.

Comments

Subbu:

you misread my post, I talked about Internal interfaces and external interfaces in the context of loose-coupling. I would encourage you to read it again.

An "internal" is the interface modeling the interaction with an other component from the component's implementation point of view. When you are not sure to which consumer, a provider is going to be connected, you have to create a model for it.

You keep playing with the fact that REST does not need actions and yes actions are everywhere. Could you please clarify what you mean by:

>> Set of URIs for the verbs that they can respond to (I don't understand the use of 'for')

What verbs are you talking about? the one from the uniform interface or the actions?

Could you please clarify whether the internal interface must be described in terms of actions?

If yes, now, let's assume you have two components that each have been implemented based on their internal interface Pi and Ci, how do you wire them together with REST (knowing that the only plug you have is Ce=Pe=(GET, PUT, DELETE, POST)? I know that you marshal actions with links, perfectly ok, but the question is how do these links get wired to Ci or to Pi? How's the code look like? Could that code be the wild-wild-west you were talking about?

thanks,

JJ-

>> An "internal" is the interface modeling the interaction with an other component from the component's
>> implementation point of view. When you are not sure to which consumer, a provider is going to be
>> connected, you have to create a model for it.

I now understand what you mean by "internal" interface. IMO, these internal interfaces on either end are due to version changes. At time t=0, let's say, both the producer and consumer speak v1.0 of the interface. Over time, some producers may be upgraded to v1.1, while the consumers may still be viewing the producers as conforming to v.1.0. This combination leads to some very interesting problems, as I blogged about in Web Services Versioning - Part 1 and Web Services Versioning - Part 2 a couple of years ago. In the case of Web Services, we ended up relying on XSD namespaces, which turned out be nice at the interface level, but hard at the code level. Hard because, XSD driven code generation is tied to namespaces, and one ends up duplicating code or building additional layers.

Coming back to the case of REST, there are two approaches that people tend to take for versioning interfaces:

a. Provide a different set of URIs for each version for major (I mean really MAJOR) changes that are incompatible with the current version
b. Change encoding formats (xml, json, query params etc.) such that they are forwards/backwards compatible.

These solutions do work in practice, and that is why I do not agree that REST does not address versioning. To me, versioning takes some skill and experience no matter what interface description technology one is using.

>> What verbs are you talking about? the one from the uniform interface or the actions?

I meant HTTP methods such as GET, PUT etc. Those are also the actions in "action-oriented" speak.

>> If yes, now, let's assume you have two components that each have been implemented based on
>> their internal interface Pi and Ci, how do you wire them together with REST (knowing that the
>> only plug you have is Ce=Pe=(GET, PUT, DELETE, POST)? I know that you marshal actions with
>> links, perfectly ok, but the question is how do these links get wired to Ci or to Pi? How's the code
>> look like? Could that code be the wild-wild-west you were talking about?

In the model I described, the internal interface is merely "a" version of the interface, and so, there is no internal vs external question. So, the wireup is more natural, since the consumer knows only one version of the interface. As long as the producer is maintaining compatibility, things work. No wild-west here.

Subbu:

thanks for these precisions. I read your posts on web service versioning and it looks like we are pretty much in line with the approach there.

I am a bit skeptical about what you say about REST:

>> b. Change encoding formats (xml, json, query params etc.) such that they are forwards/backwards compatible.
No problem here since it is the same recommendation as WS

>> a. Provide a different set of URIs for each version for major (I mean really MAJOR) changes that are incompatible with the current version

Now, you are showing another strong coupling that works well on the Web and does not work at all in the "information system's world". Since REST couples application state with Resource (representations) and Identity with Location (access), what happens in the event that I am a consumer of a resource and you change the version on me? There is only one resource right? As a consumer I hold a URI to this resource to be able to do something with it at a later time. What happens to the resource after the version upgrade? I can't access it any longer? how do I get the new URI?

See the business logic changes constantly, at least its lifecycle is in general shorter than the one of the resources it manages. So coupling the "interface" to the "resource" is a bad, very bad idea. Again, it works well when a user is in the loop because the user never keeps application state, when you navigate away from the resource representation there is no "real" application state left on your browser. In information systems architecture this assumption simply does not hold. When a resource interacts with another resource they keep a knowledge of their respective states (could just be implicit) and this is necessary to understand what inter-action comes next. You can never push all the state of the inter-action to a common location. You can have a shared state, for sure, though it is not required, but you can never pushed the application state outside the resource itself, because resources have an intrinsic state machine on which the unit of work (the application) they are currently involved in relies upon. Most often (99% of the time) you never want to share all your state as part of the interactions.

What you are telling us is that a different URI will point to a different code base? how can you be sure you are talking about the same resource. Identity is now mixed with Version of the action interface to the resource (not the resource itself). That does not sound like a good design if you ask me.

At the end of the day, the RESTifarians come in as if Information Systems are a brand new thing and we are still discovering some of their core features. In case you have not noticed, information systems were invented 8000 years ago, yes, 8000 years ago, in the middle-east. They brought us civilization, writing, with writing, knowledge, education (word of mouth does not scale), science, philosophy... The characteristics of information systems are independent of "computing". The killer app for computers in the 50s was "data processing", it is only in the 70s with "permanent storage" and "online" access were invented that information systems started to be hosted entirely within a computer and computers did not just "compute" anymore.

Unfortunately, most people don't realize that computing is different from managing information. They mix up pretty much everything: data, middleware, algorithms, programming languages, query languages... recently there was even a guy who commented on SimpleDB and started to argue that Data was not "relational". Guys, I have news for you. The principles of information systems have not changed for pretty much 8000 years: things like identity, content, states, representations, actions, inter-actions, trans-actions, privacy, signature, "relationality" of data, indexes... are still the same. The technology has changed but not the principles.

JJ-

Hi JJ - very interesting discussion :)

"Now, you are showing another strong coupling that works well on the Web and does not work at all in the "information system's world". Since REST couples application state with Resource (representations) and Identity with Location (access), what happens in the event that I am a consumer of a resource and you change the version on me? There is only one resource right? As a consumer I hold a URI to this resource to be able to do something with it at a later time. What happens to the resource after the version upgrade? I can't access it any longer? how do I get the new URI?"

I don't think there is a magic solution to this problem with any kind of networked architecture. Think of a WSDL changing the interface. For compat sake, the WSDL may include both the old and new versions, but that does not do any good to the machine client. The machine client will continue to use the version that it understands. The same is the case with REST. A machine client will continue to ignore the new URI. This is not coupling.

Leave a comment