Friday, January 11, 2008

Resource-, Service- and Object-Orientation

I've had an epiphany. I can tell you the difference between systems that are Resource-Oriented (REST), Service-Oriented (REST and SOAP/WS-*) and Object-Oriented (Java, C#, etc.) And it's very simple, something that can be explained with basic English grammar.

No, I don't mean the old "noun-oriented" and "verb-oriented" classification. That's actually quite a meaningless classification. REST and Java are both noun-oriented, but they're opposites in a more important sense. REST and SOAP/WS-* seem to be opposites because one is noun-oriented and the other is verb-oriented, but they're both actually very similar.

No, the very term "noun-oriented" is meaningless because all these systems deal in verbs. The question is, what's the subject of the verb? In other words, who does the act represented by the verb?

If the "object" itself is the subject of the verb, i.e., it's an intransitive verb, then the system is Object-Oriented. If an external "service consumer" is the subject of the verb, then the system is Service-Oriented. In other words, Service-Oriented systems are Subject-Oriented as opposed to Object-Oriented.

Example: You start your car. The car starts.

It seems like the same verb in both sentences, but they're not actually the same. The verb "start" in the first sentence is transitive, i.e., it has an object. "You" are the subject and "your car" is the object. In the second sentence, "start" is an intransitive verb. "The car" is the subject and there is no object at all.

Service-Oriented (SOAP/WS-*):
verb/operation: start (specific verb)
parameter: car ID (i.e., which car to start)

Service-Oriented - Resource-Oriented subtype (REST):
verb: PUT (generic change of status)
resource: car URI (i.e., which car to start)
parameter: new status: "started"

Object-Oriented (Java):
car.start() (this is a different "start" from what the driver does to the car)

Note the difference between two "noun-oriented" systems here (REST and OO). An Object-Oriented system specifies what an Object can do (the car can start (itself)). A Resource-Oriented system specifies what can be done to a Resource by the service consumer (you can start it). So REST is Service-Oriented. The focus is on what the service consumer does to the resource (transitive verb), not what the resource does (intransitive verb). GET, PUT, POST and DELETE are all transitive verbs, and their object is always a URI.

If we want to take a less ambiguous verb than "start", how about beating a drum? A drum booms when it is beaten.

The Service-Oriented view of a drum is "You beat the drum". The Object-Oriented view is that "the drum booms". The concept of "beat" doesn't enter the Object-Oriented world unless you're modelling the drummer.

Service-Oriented (SOAP/WS-*):
verb/operation: beat (specific verb)
parameter: drumID (i.e., which drum to beat)

Service-Oriented - Resource-Oriented subtype (REST):
verb: PUT (generic change of status)
resource: drum URI (i.e., which drum to beat)
parameter: new status: "beaten"

Object-Oriented (Java):
drum.boom() (has nothing to do with "beating" because the viewpoint is different)

A few extra points:
SOAP/WS-* shares a trait with another much-maligned technology - EJB, specifically Session Beans. I've always felt that Session Beans were not true OO. What did they model? The answer now stares me in the face. Session Beans are Service-Oriented. They deal with what the service consumer can do, not what an (internal) object can do.

If you look at Session Beans from a purist OO perspective, you will see that the Session Bean's methods are the only important thing. The containing Session Bean class is only there because Java does not allow first-class verbs (freestanding methods). All methods must be wrapped inside classes. So the Session Bean class doesn't really model anything in the domain - it's not a Domain Object at all! It just satisfies a contractual requirement of the Java language to have classes wrapped around methods. That's why Session Beans tend to have such weak names as "Account Manager". They just act as catch-all containers for methods that seem to belong together. That's also why more than one Session Bean can often seem appropriate to house a certain method. Where does the changeAddress() method go? Is it CustomerManager.changeAddress( customerID, newAddress ) or AddressManager.changeAddress( customerID, newAddress )?

And why is SOAP/WS-* like Session Beans? What's a SOAP "service"? It's the SOAP "operation" that's important, - the verb. The SOAP service is a catch-all "noun" that holds a bunch of related operations together. In other words, SOAP (or WSDL to be precise) suffers from Object-Oriented thinking of the very kind that afflicts Session Beans. Why can't we have freestanding verbs in WSDL?

To round out the analogy, REST is like Entity Beans, but with one crucial difference. Both model resources. Both Entities and Resources have lifecycles. The methods on Entity Beans are lifecycle methods, not so much methods that make sense to the service consumer or which fit into the service consumer's "process". [This ties back to an earlier discussion on the difference between a process and a resource lifecycle. One deals with the viewpoint of the service consumer, the other deals with the viewpoint of the resource or object itself.] That's really why Entity Beans need Service façades (officially called Session façades in the literature), even though the immediate reason for Service façades is to avoid the performance overheads of remoting individual entities. I believe Service façades perform the important function of shifting the viewpoint of the system from Object to Subject and thereby make Object aggregation possible.

REST avoids the fine-grained remoting problem that plagues Entity Beans because it's Service-Oriented. The focus is always on what can be done to Resources. With Entity Beans, the focus is on what an Entity can do, and it requires a Session Bean to change the focus to what can be done with Entities. So it's easy to deal with a bunch of Resources in REST. Just adjust the URI and some parameters so that they refer to a set of Resources rather than just one. With Entity Beans, that is simply not possible. When the very paradigm focuses on an individual Entity, how does one deal with a set of them without enumerating them all? So the Session bean (Service façade) has to step in to do the expensive enumeration locally and provide a single remote interface that is less expensive.

So there you go. Object-Oriented systems tell you what Objects can do. The method verbs are largely intransitive, (although when an object's method takes another object as a parameter, it tends to be a transitive verb). Service-Oriented systems tell you what can be done, period. Resource-Oriented systems, which are a subset of Service-Oriented systems, tell you what can be done with Resources. The other Service-Oriented systems (the "rest", heh!) tell you what can be done in such specific terms that an object may not have to be specified, although it can. The object in such cases is the set of parameters to the verb, i.e., the XML input document defined for the SOAP operation.

No comments: