In my discussions with JJ on REST, he's often made the observation that REST is nothing but Distributed Objects and is therefore a bad style. But is it really?
I have two different arguments why I believe it isn't.
1. Let me first talk about my experience as a migrant from India to Australia many years ago. Working in Indian companies had acclimatised me to a rather direct management style. If my manager ever wanted me to do something, he or she would say so in so many words, "Do this!"
When I arrived in Australia and began working, I was struck by the very different style of Australian managers. I would hear things like, "You may want to do this," or "You may like to do this." It took me a while to realise that they were essentially saying the same thing, only less directly. Let me coin a term for this style, because I'm going to use it to explain a concept with Distributed Objects. Let me call this a polite command.
Let's now turn to methods that set an object's attributes. We may see setter methods like these:
widget.setSomeAttribute( someValue );
widget.setAnotherAttribute( anotherValue );
Now consider another style of doing the same thing.
widget.updateSelf( widgetDTO );
where widgetDTO is a structure that holds the new values of someAttribute and anotherAttribute.
Let's call the direct setter methods commands. "Remoting" these commands leads to a tightly-coupled, RPC mechanism. This is the Distributed Objects style. I would be the first to agree with JJ that this is a bad approach.
But the second style is a polite command. It's requesting the object to update itself based on values held in a Data Transfer Object (i.e., a representation). Now this is a style that can be remoted without problems, because it's not really RPC.
The REST style of updating resources follows the latter model.
PUT /widgets/1234
<attributes>
<some-attribute>some value</some-attribute>
<another-attribute>another value</another-attribute>
</attributes>
In other words, this is a polite command. It can be safely remoted. It's not Distributed Objects.
2. JJ laughs at the approach of annotating object methods to turn them into REST resources, the way JAX-RS does. This is another reason why he considers REST to be Distributed Objects. The annotations seem to be doing nothing more than remoting object methods. Therefore, REST = Distributed Objects and consequently a horrible way to design systems.
Not so fast.
Let's not forget the concept of Service Objects, which are not really Domain Objects.
Let's look at a simplistic domain model for a banking system. The major Domain Object in this model is an Account. An Account object has the following methods:
class Account()
{
public double getBalance() {...};
public void credit( double amount ) {...};
public void debit( double amount ) {...};
}
The Domain Model is internally-focused. Nothing here understands the concept of a transfer. Indeed, a transfer cannot be elegantly modelled using domain objects.
That's because a transfer is an aspect of a Service. Service verbs are really free-standing verbs. They don't belong to classes the way domain methods do. The methods getBalance(), credit() and debit() don't make any sense by themselves. It always has to be account.getBalance(), account.credit() and account.debit().
In contrast, transfer() can be a free-standing verb. In fact, it seems downright clumsy to push transfer() into a class, because it really doesn't belong inside any class. It's just that languages like Java are unyieldingly object-oriented and don't tolerate free-standing verbs. So in practice, designers create an awkwardly-named class like AccountService and stick transfer() inside it, like this:
class AccountService()
{
public void transfer( Account fromAccount, Account toAccount, double amount )
throws InsufficientFundsException
{
if ( fromAccount.getBalance() >= amount )
{
fromAccount.debit( amount );
toAccount.credit( amount );
}
else
{
throw new InsufficientFundsException();
}
}
}
[If J2EE designers feel a sense of déjà vu on seeing this, it's the old Session Façade pattern all over again, with Stateless Session Beans acting as a service façade for domain objects represented by Entity Beans. Stateless Session Beans were not part of the Domain Model at all. They were an explicit service layer that lent itself to being remoted through (what else?) a Remote Interface.]
Now, if we tried to remote a method like credit() or debit(), it would be a classic case of RPC (RMI, strictly speaking) and therefore Distributed Objects hell.
But a "method" like transfer() readily lends itself to being remoted! That's because an instance of AccountService isn't a Domain Object but a Service Object.
If designers took care to annotate only the methods of Service Objects and avoided doing so with methods of Domain Objects, then they neatly avoid being trapped into the Distributed Objects paradigm.
All that leads to a certain insight. And that is that although REST is an architectural style, it isn't prescriptive enough. We need to tell designers what types of domain objects can be modelled as resources and what cannot.
With a nod to the term polite command, perhaps it's not enough for systems to be RESTful. They should also be RESPECTful :-).
I realise I have blogged extensively on this over 2 years ago, here and here.