In Craig McMurty’s blog entry that stirred up discussion of Indigo and Jini, he mentions a piece by Don Box, in which “the four fundamental tenets” of service-oriented development are laid down. Craig further asserted that ‘The “services” that one can construct with Jini do not conform to any of those four tenets’. Really? Well, given how badly Craig seems to have misunderstood Jini, I decided to go back to the source and see what the good Mr. Box has to say for himself.
So what exactly are Don’s four fundamental tenets?
Boundaries are explicit
Services are autonomous
Services share schema and contract, not class
Service compatibility is determined based on policy
Plausible? Well, the first two are unexceptional, and describe Jini services quite nicely. I suspect the devil may be in the details. The third seems unduly coupled to a particular technology and language; if we replace “schema” with “interface” and “class” with “implementation”, it feels OK – and describes Jini very well. And the fourth? I have no idea what it means, but on the surface it seems to conflict with the second (autonomy) and to overlap with the third. Perhaps we can resolve these conflicts later on. Let’s dig into each of these ideas.
Boundaries are explicit: Back in the early days of distributed computing, it was considered a good idea to hide the boundaries, to make remote resources look just like local ones. This is what gave us remote file systems and early RPC schemes; in extremis it gave us things like Locus. Over time the wisdom of folks like Peter Deutch and Jim Waldo cured us of this. These days we all believe in explicit boundaries.
Box, however, introduces what seems to me like a non-sequitur: “Because each cross-boundary communication is potentially costly, service-orientation is based on a model of explicit message passing rather than implicit method invocation.” Now this is bizarre. He’s saying that because an interaction may be expensive, we have to describe it explicitly at the lowest level. Even if one is performing a higher-level pattern, such as a method invocation, one is required to unpack it by describing the individual message patterns and how they are correlated. While sometimes this may be appropriate, it hardly seems fundamental. For a start, it conflicts with the notion of autonomy. Why should a client and service, mutually consenting adults, be required to describe their interaction in such detail in advance? Why could they not negotiate a mechanism on the fly, using available resources?
Box goes on to say, “the fact that a given interaction may be implemented as a method call is a private implementation detail that is not visible outside the service boundary”. But this is disingenuous. How detailed, how explicit is the message description? Either we give up on type (or schema) based notions of compatibility, or every interface requires a detailed description of request and response messages which will make the “private implementation detail” instantly public (and will significantly constrains the ways client and service can interact).
A final thought on boundaries: while they may be explicit, they are not necessarily static. Refactoring is a fact of life. In practice this means that software components will be constructed in such a way that potential boundaries are declared as such (using, for instance, the remote interface in Java), and services will be assembled and composed in terms of such interfaces. Describing a service in terms of a low-level message exchange pattern then becomes one technique among many for defining service boundaries, and one that is generally effected by a design tool of some kind. It’s an implementation artefact, not a design principle.
Services are autonomous: Box’s account of service autonomy is excellent. He discusses version skew, the dynamic nature of the aggregations that comprise a system, the effects of unintended usage, partial failure, and security. (He could also have said something about dynamic discovery, self-healing, the use of patterns such as broker and facade, and the use of techniques such as introspection to perform dynamic adaptation.) There is nothing here that a Jini enthusiast would disagree with.
Services share schema and contract, not class: Earlier I wondered if this referred simply to a separation between interface and implementation. This understates Box’s position. He writes, “services interact based solely on schemas (for structures) and contracts (for behaviors). Every service advertises a contract that describes the structure of messages it can send and/or receive as well as some degree of ordering constraints over those messages.” And he also says that “the contract and schema used in service-oriented designs tend to have more flexibility than traditional object-oriented interfaces. It is common for services to use features such as XML element wildcards (like xsd:any) and optional SOAP header blocks to evolve a service in ways that do not break already deployed code”. So what we are dealing with here are relatively simple interfaces, evolving slowly, with weak consistency and ad hoc extensions.
Now there are plenty of situations where this kind of approach is just fine. As Box notes earlier, it’s the kind of thing that made Amazon.com’s services the success that they are today. But for other applications, this kind of thing is hopelessly inefficient or inflexible. For the vast majority of intranet services, for instance, the most common way to invoke a service isn’t going to be by parsing its description and constructing a new client stub ab initio: it’s going to be by invoking a copy of the stub code generated when the service was created. And if you’re going to do that, why not take advantage of it – not just at compile time, but dynamically, so that the interactions with the service can reflect the characteristics of the deployed service? As for the suggestion that one needs more flexibility than “traditional object-oriented interfaces”, mechanisms like introspection allow for powerful and robust run-time flexibility, without sacrificing type safety.
It seems to me that the fundamental principle involved here is the one I alluded to earlier: establishing a clear separation between interface and implementation. How we do that seems to depend on the application and context; there is no reason to believe that one size fits all.
Service compatibility is determined based on policy: It turns out that what Box is talking about here is the distinction between structural compatibility and semantic compatibility. The latter is familiar and unremarkable: XML schemas, class signatures, on-the-wire encodings, that kind of thing. But what Box is interested in is “[s]emantic compatibility… based on explicit statements of capabilities and requirements in the form of policy”. He gives a few hints about what he’s thinking of, but at this stage I think it’s safe to say that he raises more questions than answers. Suffice it to say that this whole area is in its infancy, and it’s not an immediately important issue. By the time we figure out exactly how to express
such things (OWL-S?), how and when services get to ” apply simple propositional logic to determine service compatibility”, and exactly what customers want to use this for, our initial expectations are likely to change significantly. There’s certainly nothing here that is incompatible with Jini.
So what’s the verdict? Was Craig correct to claim that Jini doesn’t conform to Box’s “tenets”? Unambiguously not: Jini absolutely conforms to every aspect of Box’s “autonomy” tenet. How about the others? Well, it all depends on whether you read the interface or the implementation: whether you concentrate on the broad principle, or how Box chooses to implement it. Jini is entirely compatible with the broad principles, but not surprisingly it’s not going to conform to Box’s Procrustean Bed of message-based service patterns. But why should it? Box gives us no reason to believe that this technology is the only way to realize the principles. It’s just the way Microsoft chose.
I’ve already discussed why Microsoft took this path, but it’s important to recognize that it’s not the only – or even the best – approach. There are more powerful, elegant, and efficient models for realizing the principles of service-oriented distributed computing, and Java and Jini represent such a model. For Box and McMurty to argue that only one technology fulfills these principles is self-serving, not to mention ahistorical. The wide range of problems to be solved, the variety of contexts in which the solutions must operate, and the kinds of constraints and requirements that must be met, are such that multiple technologies will clearly be needed. As Jim Waldo pointed out, the “Highlander Principle” (“there can be ‘only one'”) is a fallacy.