A few weeks ago, Ron Jacobs stopped by the Austin Microsoft Technology Center to talk about the CAB and SOA. Ron gave the best explaination of SOA that I’ve heard so far, and none of it was at any extreme. He covered the four “requirements” of SOA:
- Boundaries are explicit
- Services are autonomous.
- Schema and contract are shared, not class
- Compatibility is determined by policy.
My favorite line from the talk was that SOA simply seeks to make integration a forethought when building an application instead of an afterthought like it is today (many companies have existing applications that they are now trying to integrate or share).
Some boundaries are like International boundaries. You have to go slow. You may be stopped and searched. When you need to cross this boundary, you plan for it. Other boundaries are like interstate boundaries. You control both sides, and you can typically fly across the border at 70 mph. The relationship to SOA is that service boundaries are explicit like International boundaries. You need to slow down and plan for crossing. Component boundaries are like interstate boundaries, and you can fly across those using any fast communication mean you want because you control both sides.
A service is sovereign over its space. Service can be composed of other services. Autonomy is not black and white. There is a specrum, and you want services to be more toward the autonomous side. If a service delegates to a dependency, the failure of that dependency should not automatically halt the service.
Schema and Contract:
The schema is the format of the message that will be passed. The contract is the action that the service can be trusted to commit with the message. This is tightly coupled with policy.
Policy determines compatibility:
Many services today use MSMQ, or MQ Series products. This is not to say that services have to be asyncronous, but to say that SOA isn’t just about web services. If the policy states that the schema must be compatible with a bunch of systems, then the schema will have to be a text schema, and Xml is great for that. If the policy states that only a few clients are supported, then a faster, more efficient schema can be used, perhaps binary, as long as the few clients can understand the message. Services can use any communication mechanism, not just SOAP, to communicate, but this decision is set by the Policy in place.
Ron also went over an anti pattern, the CRUDy interface. This is a service interface that behaves much like an OO component. This makes for a chatty interface of creates, reads, updates and deletes. This puts the clients in the wrong frame of mind, and it encourages an RPC style of development. This requires clients to know too much about the internal implementation of the OO system behind the service interface.
Examples of this are
- Enumerated interfaces (a MoveNext endpoing).
- Abstract types (xs:any). This weakens the interface. Keep to explicit types.
- Leaving data in an inconsistent state (if the client failed to make another call, would the service be in a “dirty” state).
- Operations that require multiple messages are dangerous because the service sacrifices some autonomy to the client.
Another anti pattern: loosey-goosey (or exteeennnsible).
This happens when a contract may need to be used for a long time. If a contract is extensible, then it is vague. Services that have a “QueryDatabase” command are a good example. A client should be able to ask “What can I send”, and the contract should explicitly answer the question. The client developer shouldn’t have to experiment with the service to find acceptable input.
Each endpoint should do distinct things. A loosey-goosey service has to be learned by experimentation. People then tend to depend on implicity behavior instead of the explicit contract.