I have read and re-read and re-re-read Jeff Schneider's post on Microsoft's Ron Jacob's webcast on Service Oriented Architecture. [whew]. While I tend to agree that only having four tenets at first glance sounds a little suspect, REST, the description of the architecture underlying the web, is composed of six constraints (which, if you squint your eyes, are tenets):
- Client-Server
- Stateless
- Cache
- Uniform Interface
- Layered System
- Code-on-demand
But then Jeff goes through the tenets one by one, challenging their meaning and offering an alternative tenet, and this is where the [re-]re-reading comes in. Let's dissect each in turn. Jeff says:
Boundaries are explicit - yep, hard to argue. But what does this actually say? How about this instead: "All exchanges of data, metadata, logic or other binary asset MUST BE exchanged through a contract. Runtime changes to code dependencies are NOT allowed."
Uh. No. That isn't it. Thanks for playing, though. Go back and read the source. "Boundaries are explicit" is about the fact that you can't see what kind of underpants I am wearing. If you want to know, you have to ask nicely by sending me a message. The contract stuff is in that other tenet. I have absolutely no idea what "Runtime changes to code dependencies are NOT allowed" has to do with explicitness of boundaries. In my estimation, nothing. I can think of a number of ways that runtime code dependencies could change in the context of a service oriented system, and everything would be just fine.
Services are autonomous - Most people know that I firmly believe that "services are not autonomous", they are synergistic. Services work together in a 'service ecosystem'. Services will influence each others metadata. In no way are services autonomous.
I don't agree. I believe that services *should* be autonomous, that their implementation dependency on other services is an implementation detail (because boundaries are explicit), and part of the responsibility of an autonomous service is to gracefully degrade service when its dependencies have availability or other issues. I do *not* go as far as Clemens Vasters does in talking about services waking up and touching, er, I mean, invoking themselves. While I do think that agent-based computing has its place, and I do buy into the notion he sells that services/message passing are a great way for agents to communicate, I don't buy into the notion that services are agents. I think it is important to make a distinction between services and agents, and that level of autonomy and self-directedness is one of the key distinctions I would try to make.
Interestingly, I think Jeff provides some much needed guidance on what would help scope an autonomous service in a different post on Design by Contract vs. Contract First, specifically, the bits about pre- and post-conditions, which are sorely missing from the WS-MESS.
My take: A service should be scoped to the level of assumed impact. If I can send a message to an endpoint and then safely assume something about the result of another message send, then those two message sends are coupled and most definitely not autonomous *without each other* and probably should correspondingly live together, i.e. be operations on the same service.
Consider the following: If I ask Fedex to send a package to my parents overnight and they agree, then I could verify the results one of two ways: call my parents, or check with Fedex. However, Fedex does nothing to guarantee that my parents will respond honestly. That isn't in the contract. They will, however, know whether or not they delivered it on time, what time they delivered it, whether or not someone was there to receive it, and if so, what the signature read. This is the essence of autonomy to me. Verifying package delivery isn't my parent's business, it's Fedex's business.
Jeff's next comment also seems to miss the mark for me:
Services share schema and contract, not class - I believe the point is that you want to share data using self describing, self validating, extensible schema systems that are ubiquitously deployed. That's cool - use an abstract typing system.
I think that this tenet is explicitly included for all of the rpc/distributed object guys, and I think that it can be loosely translated "Don't share dlls, don't share jars. It will hurt." Again I refer back to this great exchange. Network apis, *not* library apis.
I agree that it is impossible to completely avoid CRUD in many cases, but I have seen systems where every entity had a service crud interface, and that *is* a service smell/anti-pattern. The point is that the service interfaces should be coarser-grained and business-oriented. The difficulty is that one man's operation is another man's entity (think "Order" vs. "Order"). REST normalizes this by forcing you to view everything as a resource, i.e. a noun, and then restricting what you can do with that noun to a small set of verbs + post, the latter of which, loosely translated, becomes "do whatever the hell you want [in the scope of this resource]." Services looks at everthing as a operation, i.e. a verb.
I do like his questions about open-ended interfaces.
FWIW, I know that Jeff is a bright guy. Its apparent from his blog. And I like the fact that he's doing things like ServiceOriented and ProcessDriven, and OpenStorm is at a minimum a cool brand name, and it appears to be a lot more, though I haven't used it. And I trust he can explain what he means in a way that someone as simple as me can understand. I hope he does, because I don't get it.
Comments