Friday, June 11, 2010

Is REST Another Variant of Distributed Objects?


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.

4 comments:

Integral ):( Reporting said...

Ganesh,

thank you for this discussion. It is refreshing to be able to exchange arguments at that level.

First, let me say that you have a very classical view of programming. OO, DTOs, Single-Operation services or so. I would actually argue that all these technologies and approaches are the core of IT's failure to build sustainable information systems.

OO is interesting, it can do lots of things, but unfortunately, it is inadequate for building information systems. We have been at it for 25+ years, banged our heads on ORM. In the end, OO does not work because:
a) it cannot model information entity associations properly
b) it cannot factor the business logic if information entities properly

In OO, an association is unidirectional. No matter how hard you try when you have a class Bar with a property foo of class Foo, well foo has no way to know anything about its parent class. In REST it is exactly the same way. A Web page may have a link to another Web page, but the target Web page knows nothing about the source Web page. Because of this poor implementation association, no one can really create arbitrary projections of the information model to bind to a message or a UI. All this is painfully hand coded over and over and over.

Second, and just as bad, OO cannot factor the business logic of Information Entity Lifecycles. Every Freaking Information Entity has a lifecycle, even a Web page. Commands, polite or not, are for the most part event handlers. If you need any correlation across events and you are on your own. BPEL or any orchestration language are much better suited to implement the business logic of entity lifecycles. If you read my introduction on WSPER, you will see that I explain that unlike an object a service implementation can tie together multiple operations. In OO you have:
public poke(P peek)
{
a bunch of code
}

in SO (and most people do not take advantage of this, granted, each operation can aim at the same implementation (a BPEL implementation). There lies the fundamental difference between OO and SO. I can now assemble my services in ways that Spring can only dream about. This is a major, major contribution of SCA.

In REST, of course, all you can do is encode commands with PUT or POST (http://www.ebpml.org/blog/213.htm), just like in OO.

I challenge you to give me a real business process (not just a made up one). Let me decompose it in Resource Lifecycles and you will never talk about REST again. Even Jim Webber finally understood that concept after I explained it to Ian Robinson, who brought it back to thoughtworks.

So in the end, SO is very different than OO. It introduces concepts never see before such as Resource Lifecycles, Bi-directional interfaces, Assemblies,... These concepts create a formidable programming model for building sustainable information systems. Just give me one business process and you will be convinced for the rest of your life.

So yes REST is the perfect distributed object technology:
a) it has a global naming service (DNS)
b) a perfectly interoperable ORB (HTTP)
c) an unbreakable interface with no IDL (GET,PUT,POST,DELETE)
d) caching and scalability

Basically everything that was wrong in CORBA, REST fixed it.

Yeap, I can call foo.doThis(with that) world wide.

Now, I am happy that we met last summer/winter and I have a very high respect for you. But, please, do not send commands with a PUT. You don't CRUD a command. This is the worst thing you can do, politely or not.

Integral ):( Reporting said...

Secondly, please, please, SO is not static methods in a class. You have to unlearn OO. You have to understand what a resource lifecycle is, where orchestration, bi-directional interfaces and assemblies play in the programming model, then only then you will be able to claim you know OO. Then only then you will have understood the true meaning of resource. Could you realize that you cannot express SO in OO syntax?

Please, read my paper on WSPER. Read my article on the 7 fallacies of business process execution. Please undertand how Resources (lifecycles), BPM and Service Orientation fit together. Please give me a process and let me show you how to decompose it in a service oriented way, on the foundation of resource lifecycles. I challenge actually anyone. Just give me your most complex process, and I'll show you how.
REST propagates antiquated ideas about information system construction. It keeps alive the flawed ideas of the Steve Vinoskis, Stefan Tilkovs or Bill Burkes of this world. It enslave anyone and everyone to CRUD (even politely) for the REST of their lives. This is the WOrst Atrocity that was ever pushed to IT.

There is only one flaw in everything you say, but it is essential, it is a flaw that transformed OO into a house of cards on which all our information systems are built. That flaw is the lack of concept of resource lifecycle. Please, just please, try to think each time you have a resource, what is its lifecycle, what is the interface of a resource lifecycle? (hint it is generally bi-directional). Then think how resource lifecycles interact with each other. Assemble 2, then 3, then 4 or 5 and then you will understand everything that is wrong with OO/DO and by extension with the current form of REST.

JJ-

prasadgc said...

JJ,

We seem to live on different planets. Of course, I will make the effort to understand the concepts you're talking about by reading your paper. Your frustration at not being understood by other practitioners comes across, and for that reason alone, I would like to try and understand what you're saying.

In the meantime, I cannot help thinking you're overimagining the limitations of existing technologies and confusing them with bad application designs that use those technologies. I'm sure someone can take your WSPER architecture and design a system badly, but that should not be taken as a reflection on WSPER.

Some quick points:

> Could you realize that you cannot express SO in OO syntax?

Yes, these are simplistic examples meant to illustrate some points I'm making. I have argued in past posts that SO is emphatically _not_ OO. So don't worry, I'm not confused.

> In OO, an association is unidirectional. No matter how hard you try when you have a class Bar with a property foo of class Foo, well foo has no way to know anything about its parent class.

Two issues with this:

1. I hope you're using the term "parent class" loosely. Unless Foo extends (inherits from) Bar, Bar cannot be the parent class of Foo. What you've described is a mere object reference.

2. Bidirectional associations need not exist by default. That's a good thing! It avoids tight coupling and helps reusability. Other classes can also have Foo as a property. Forcing bidirectionality will require Foo to be able to hold references to any arbitrary class that references it. That's tight coupling.

If you do need a bidirectional reference in a particular situation, you can of course model it, so OO is not an inflexible paradigm.

> In REST it is exactly the same way. A Web page may have a link to another Web page, but the target Web page knows nothing about the source Web page.

Huh? What does HTTP Referer do, then? Of course, if you're talking statically and not at run-time, then this ignorance is a good thing! If you've ever tried to design reusable portlets, this is one of the highest design virtues (not being aware of context).

> OO is interesting, it can do lots of things, but unfortunately, it is inadequate for building information systems. We have been at it for 25+ years, banged our heads on ORM.

I don't see what ORM has to do with this discussion. ORM is a level deeper inside a domain, about how to persist domain objects. We've been discussing inter-domain communication (services), how to expose domain business functionality. Why is ORM even relevant here?

(Cont'd because Blogspot doesn't take more than 4096 characters in one comment)

Regards,
Ganesh

prasadgc said...

(Cont'd from previous comment)

> If you need any correlation across events and you are on your own. BPEL or any orchestration language are much better suited to implement the business logic of entity lifecycles.

Why is there a contradiction between OO and event correlation? One is on the inside, the other is on the outside. Even REST doesn't say you don't need it. That's treated as part of the client application logic. You can build a process orchestration engine that interacts with systems using REST verbs and creates a business process. Why, BPEL 2 tries to do this (I'm not sure whether this is a genius of an idea or a monster, though!)

> I can now assemble my services in ways that Spring can only dream about.

I don't get the reference to Spring. It's a completely different technology, meant for a completely different purpose. If you're talking about Spring Integration, this is about bringing smarts to the endpoints. You'd still need an application to coordinate distributed functionality, whether it's BPEL or something else. Another non sequitur.

> So yes REST is the perfect distributed object technology

I have stated before that REST is not Distributed Objects, and you have not countered my arguments. These are not remote method invocations on domain objects. They could be remote method invocations on _Service Objects_, but that is not "Distributed Objects", because Service Objects are explicitly meant to encapsulate Domain Objects and to provide a service interface.

Can you please answer this point? Repeated assertions of "REST is Distributed Objects" without a convincing refutation of my counterargument will not convince me, I'm afraid.

JJ, when I read what you write, I sometimes get the feeling that you're writing something profound and I'm missing something hugely important, especially when you say things with so much conviction. On the other hand, you say many things which don't make sense to my mind at all, such as the points above. I actually disagree quite strongly on these points :-/.

I'll go halfway and read your writings more carefully to try and understand you, but you may also need to communicate more clearly, using simple examples and building up from very basic concepts. All the sarcasm and emotion are just getting in the way of someone trying to understand your points.

And finally,

> [...] let me say that you have a very classical view of programming.

Thank you, I take that as a compliment. I have never seen a case where fundamental IT principles have had to be discarded.

Regards,
Ganesh