Why REST is Better – Part 3 – Think Globally, Act Locally

Share the article!

Jonathan Schwartz (President, COO of Sun) writes in his blog:

Web services may collapse under its own weight -
No one at the conference said this. Those are my words. I’m beginning to feel that all the disparate web service specs and fragmented standards activities are way out of control. Want proof? Ask one of your IT folks to define web services. Ask two others. They won’t match. We asked folks around the room – it was pretty grim. It’s either got to be simplified, or radically rethought.

No new revelation here other than the fact that a C-level executive from a influential technology company seeing the writing in the wall. Most people who control budgets listen to these folks rather than the more technical adept ones. Unfortunately for the SOAP comunity, this innocent blog entry adds an added dose of fear.

Let’s of course move on to a more technical discussion. In my previous article in this series I further examined how Decorator like structures make dynamic composition of components easier, and how non-uniform interfaces make it more difficult. I also showed how a small set of interfaces do not prevent one from modeling complex interactions. That is, REST verbs fit the theory of speech acts like a glove.

An asynchronous API looks something like this:

ConversationId id = ...
Request req = ...
protocol.invoke(id, req);
// do other stuff
// some later time or in another thread
Response resp = protocol.get( id );

The ConversationId is a Asychronous Completion Token as described by Douglas Schmidt. Back in 2002, I wrote about why Asynchronous services where better than RPC based mechanisms:

The problem with the RPC style messaging is that it couples in time the parties involved. In otherwords, the parties have to be both present and active to get the communication across. It’s okay for realtime processes, unfortunately most processes don’t happen in realtime.

Since then the SOAP community has realized the temporal coupling problem and has adopted support for asynchronous services. However, there are still two ways to do asynchronous messaging one more interoperable than the other. You can either push messages (i.e. initiated by the producer) or you can pull a message (i.e. initiated by the consumer). A push based API looks like this:

// implementing a handler must use a common interface
class MyHandler implements EventHandler
    void onEvent( Event evt )
// Sending an event
EventHandler handler = new MyHandler();
Event e = ...
handler.onEvent( e );

Push based messaging is more tightly coupled because it is the responsibility of the producer to know how to push messages to its consumers. This puts the onus on a single producer supporting the requirements of all its consumers, a highly impractical proposition. The standard solution is to standardize the push infrastructure (see SMTP) placing stringent requirements on all consumers to comply with that infrastructure. Consumers are required to be constantly available and continually upgradeable to function properly in a push network. Sean McGrath has a paper that highlights the pros and cons in more significant detail.

For example, let us add an entirely new event, the code will look like this:

NewEvent event = new NewEvent();
handler.onEvent( event );  //valid? 

The only case where the code would be valid is if NewEvent extends from the original event. This restriction however usually doesn’t hold true. The initiator is responsible for selecting a compatible access path, here the producer should fallback to the original working code.

In the REST model the conversation id is equivalent to the resource URI. The REST model of asynchronous communication would therefore conform to a shared space model (see Tuple Space). The Tuple Space model has been shown to be beneficial for distributed process coordination. In fact as a historical note, the original JINI core specification did not include JavaSpaces. The expctation that an RPC mechanism (i.e. RMI) was adequate for the distributed objects, however over time the JavaSpace route became the preferred mechanism for process coordination.

A pull based API invocation looks like this:

URL location = ...;
Response resp = protocol.get( location );

// when server add a new kind of response, the location should also be different (URI uniqueness).

try {
    URL newlocation = ...;
    Response resp = protocol.get( newlocation ); // also fails!
catch( Exception ex )
    URL oldlocation = ...;
    Response resp = protocol.get( location ); // however, succeeds if server maintains old linkage

The push and pull methods both fail if the consumer isn’t informed of a change in the producer. The difference however is this, which party holds the responsibility for ensuring compatibility? In general the initiating party holds responsibility. That is the initiating party makes the decision as to what is the most compatible access path. Also, in general there are more client implementations than server implementations, therefore it is less demanding a task for a client implementation to upgrade than a server. From a global perspective the amount of effort is identical, however at the local level (where it really counts) the effort differs significantly. Therefore a pull based implementation has a greater chance of ensuring compatibility.

An example of asychronous publish and subscribe implemented in RESTful fashion is the ad-hoc RSS network. Let’s compare RSS a polled1 pull asynchronous model versus SMTP a pushed asynchronous model. The common explanation why email spam is difficult to fix because the SMTP has no mechanism to authenticate the source of the email message. However, the problem lies deeper than that, because SMTP is a push network, for it to function correctly, all the nodes of the network need to be upgraded in unison. Furthermore, message propagation are initiated by the source and not by the consumer it becomes more difficult to avoid spoofing.

RSS by contrast has less difficulty upgrading its infrastructure, in fact today despite having multiple incompatible variants, the RSS newtork keeps on ticking. Spoofing is much more difficult since transfers are initiated by the consumer. One would have to hack in the access path in each and every consumer to pretend to be someone else. The network can be incrementally upgraded because a change in the producers format doesn’t break consumers, it’s simply ignored. Consumers choose the access path and therefore can choose the path that is most compatible. For example if I have a news aggregator that doesn’t understand ATOM, I can always select a path (i.e. FeedBurner) that translats the ATOM feed to an older format.

Yet again we see a pattern recurring, that is the consumer has the right to ignore certain features. It’s easy to be reminded of Postel’s Law, that is “Be liberal in what you accept, and conservative in what you send”.

But before we leave this topic of asynchronous messaging let’s look a little bit deeper into that “Conversation Id” (a.k.a. Asynchronous Completion Token). The absence of such an identifier makes asynchronous messaging impossible for all but the simple cases, since there would be no way of correlating messages. This fact gives us a glimpse of the importance of URI aspect of REST. One could simply dismiss URIs as a way of supporting browser hyperlinking, however its more than just that. It is the feature that enable REST to support complex interactions.

In fact, if we dug in to some theory about concurrent distributed processes, we find something called the Pi-Calculus. Robert Milner proposed in his paper “Turing, Computing and Communication” that there are two elementary particles for the new computing model:

Synchronized action

Channel or Vocative name

These two fit together perfectly; indeed, like quarks, they hardly exist apart. Synchronization is between an action – the vocative use of a name – by one agent, and a reaction by another. At this level, names and channels are the same thing; in fact, they are the essence of several superficially different things, which computer scientists have called links, pointers, references, identifiers, addresses, …, and so on.

In otherwords, the URI is not just an REST idiosyncrasy that can be ignored as the SOAP proponents have done. It is in fact the basis of all interaction. It’s conspicuous absence in SOAP is a clear indication of not just a problem but the a flaw that’s fundamental. It’s like trying create the sound of one hand clapping, something only a Zen master can truly grok.

Folks, I’ve run out of time today, my 5 year old is calling and I need to play with Buzz Lightyear. Next time I’ll discuss the message layering problem, read this piece for a preview.

1. Because HTTP does not have a built-in asynchronous delivery mechanism (see Rohit’s Dissertation), polling is used.

Share the article!

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>