So far, we have explored the concept of service orientation, looked at the structure of service-oriented messages, examined the requirements for message addresses, and discussed the industry standard for message addressing. If you understand the motivation for a standard addressing structure in an SO message, then it is not much of a stretch to understand the principles of service orientation. Every service-oriented design adheres to the following four principles (often called the four tenets).
In service orientation, services can interact with each other by using messages. To put it another way, services can send messages across their service boundary to other services. Services can send and receive messages, and the shapes of the messages that can be sent or received define the service boundaries. These boundaries are well defined, clearly stated, and the only accessible point for the service’s functionality. More practically, if Service1 wants to interact with Service2, Service1 must send a message to Service2. In contrast, an object-oriented or component-oriented world would demand that Service1 should create an instance of Service2 (or a proxy referring to Service2). In this case, the boundary between these services is blurred, since Service1 is, for all intents and purposes, in control of Service2.
If Service1 sends a message to Service2, does it matter where Service2 is located? The answer is no, as long as Service1 is allowed to send the message to Service2. One must assume, however, that sending a message across a boundary comes with a cost. This cost must be taken into consideration when building services. Specifically, our services should cross service boundaries as few times as possible. The antithesis of an efficient service design is one that is “chatty.”
In my opinion, service-oriented systems should strive to be sort of autonomous, because pure autonomy is impossible. True service autonomy means that a service has no dependencies on anything outside itself. In the physical world, these types of entities are nonexistent, and I doubt we will see many pure autonomous services in the distributed computing world. A truly autonomous service is one that will dynamically build communication channels, dynamically negotiate security policy, dynamically interrogate message schemas, and dynamically exchange messages with other services. A purely autonomous service reeks of an overly late-bound architecture. We have all seen these sorts of systems, whether in the excessive use of IUnknown or the compulsive use of reflection. The bottom line is that developers and architects have proven time after time that these types of architectures just do not work (even though they look great on paper). I must temper these comments by admitting that movement in the area of service orientation is picking up at a blinding pace. Just five years ago, service-oriented applications were few and far between, and now they are commonplace. This momentum may take us to a place where purely autonomous services are the way to go, but for now, I think it is reasonable to settle for a diluted view of autonomy.
So what does autonomy mean in a practical sense? From a practical perspective, it means that no service has control of the lifetime, availability, or boundaries of another service. The opposite of this behavior is exhibited with the SQL 2000 database and agent services. Both of these services are hosted as separate Microsoft Windows services, but the agent service has a built-in dependency on the database service. Stopping the database service means that the agent service will be stopped as well. The tight coupling between these two services means that they can never be considered as separate, or versioned independently of each other. This tight coupling reduces the flexibility of each service, and thereby their use in the enterprise.
Since service orientation focuses on the messages that are passed between participants, there must be a way to describe those messages and what is required for a successful message exchange. In a broad sense, these descriptions are called contracts. Contracts are not a new programming paradigm. On the Windows platform, contracts came into their own with COM and DCOM. A COM component can be accessed only through a published and shared contract. Physically, a COM contract is an interface, expressed in Interface Definition Language (IDL). This contract shields the consumer from knowing implementation details. As long as the contract doesn’t break, the consumer can theoretically tolerate COM component software upgrades and updates.
Service-oriented systems conceptually extend the notion of COM IDL contracts. Service-oriented systems express contracts in the widely understood languages of XSD and WSDL. More specifically, schemas are used to describe message structures, and WSDL is used to describe message endpoints. Together, these XML-based contracts express the shape of the messages that can be sent and received, endpoint addresses, network protocols, security requirements, and so on. The universal nature of XML allows senders and ultimate recipients to run on any platform more easily than with a technology like COM. Among other things, a sender must know the message structure and format of the receiving application, and this is answered by the contract. In essence, a message sender requires a dependency on the contract, rather than the service itself.
Services must be able to describe the circumstances under which other services can interact with it. For example, some services might require that any initial sender possess a valid Active Directory directory service account or an X509 certificate. In this case, the service should express these requirements in an XML-based policy. At the time of this writing, WS-Policy is the standard grammar for expressing these types of requirements. In a fanatically devoted service-oriented world, message senders would interrogate this metadata prior to sending a message, further decoupling a message sender from a message receiver. For the same reasons stated earlier, it is more probable that service policy will be interrogated at design time more than at run time.