Understanding the Relationships among Services, Contracts, and Policies
If you’ve been programming computers as long as we have, you probably remember the first time you tried to write an object-oriented program, maybe in C++ or Java. The tendency was to put all the code into a single object. It took a while to finally get our heads around the new approach to software that objects represented. After all, learning how to code in C++ or Java was easy, but learning how to build an “object” was really hard. At some point, however, there was that “aha” moment, and from then on, you always wondered why you had ever programmed any other way.
Moving to Service-oriented development requires the same sort of mind shift. Developers tend to build Services as though they were simply APIs to existing functionality. Sure, Web Services enable standards-based interfaces, but what’s the big deal with that? Just as putting all the code into a single object reflected a lack of understanding of the new approach, the “one interface per Service” mindset is also due for that critical aha moment. To get this insight with Services, you must understand the relationship among Services, contracts, and policies in SOA.
Can a Service Have More than One Contract?
One of the main goals of Service Orientation is to separate the interface of the Service (represented by the contract and associated metadata) from the implementation of that Service (represented by the underlying code that the interface abstracts). As we defined in the What Belongs in a Contract ZapFlash, a Service contract defines the relationship between a Service provider and a Service consumer, and the requirements for engaging in an exchange of information. To recap, a Service Contract contains two key parts: the functional requirements of what’s expected of the Service consumer and provider, and the non-functional requirements that govern and restrict the interaction of the two parties. While this definition is fairly clear on its face, it’s important to understand that any particular Service implementation can have more than one contract associated with it.
In fact, it is a best practice for Services to have more than one contract. The best way to explain how this works is through example. In this example, suppose that a Service developer at a particular company wishes to develop a loosely-coupled Service that exposes customer information to authorized requesters. In one instance, the company wishes to expose only non-private data to any requester that queries the Service. In another instance, the company wishes to expose all customer data including private information to requesters as long as they provide an authorized digital certificate. To further add to the value of this example, let us also suppose that we wish for the same quality of service policies (such as expected response time) to apply to both of these Service usages. An illustration of this situation is in Figure 1 below:
Figure 1: Multiple policies per contract, multiple contracts per Service
In this example, a Service consumer has a choice of binding to one of two Service contracts: one in which they can provide no security information and therefore only get general, public customer data as long as they provide valid information in the <customerID> element, and another in which they supply an authorized digital certificate and get all data in the <customerData> XML document, including data supplied in the optional <private> element. The key is that we only need one Service implementation here. The developer, using contract-first development, would have realized that two contracts specified very similar requirements, and that all the developer would need to do is to check whether or not a valid digital certificate was present, and return the appropriate information — both responses of which would have complied with the <customerData> XML schema.
One interesting thing to note about this example is that the two contracts look very similar to each other, with one notable distinction. In the one case, Policy #1 applies to the first contract, which implies no security requirements, while in the other case, Policy #2 applies to the second contract, which requires stricter security. Another interesting thing about this example is that there is a third policy that applies to both Service contracts requiring that in any case, the Service must not wait more than 30 seconds to provide a response. Thus, we have three policies, two contracts, and just one Service implementation.
Figure 2: Many-to-many relationship between policies and contracts
To make this example even more interesting, we can add a third Service contract that responds with a completely different response, providing only the <customerName> field when prompted with <customerID> input, as shown in Figure 2 above. Of course, there’s no reason to require another Service implementation, and therefore, we can have at the very least three Service contracts for this one Service, and countless more as long as the Service implementation is appropriate for all such Service contracts. The key to making this example work is that the Service consumer is responsible for choosing the appropriate contract to bind to — knowing full well what the policy requirements are and therefore what to expect from the response.
Can More than One Service Implement a Single Contract?
Another take on the contracts vs. Service implementations question is how a single Service contract can abstract multiple Service implementations. Let us extend the above example by adding another Service that can respond to the Service contract that provided only the <customerName> data, as shown in Figure 3 below. In this case, this implementation uses a local cache to deliver much faster results to the Service consumer than the more general-purpose customerData Service implementation.
Figure 3: Multiple Services per contract
Now, the first question you might ask is why would we use two Services to implement a single contract? The reason might be that the infrastructure that implements the Service might decide to utilize the more optimal customerName Service when the customerData Service is overloaded, or vice-versa, only use the customerData Service when implementing Service Contract #1, or perhaps use either on a round-robin basis whenever calling Service Contract #3. Regardless of the implementation mechanism, it’s clear that either of the two Service implementations in the above diagram can adequately respond to any Service consumer that binds to the appropriate contract.
The ZapThink Take
To make loose-coupling work, and to truly separate interface from implementation, we need to allow a many-to-many relationship among Service contracts, implementations, and policies that apply to any number of Services. This pattern is quite different from the traditional one-API-per-object interface pattern from the object-oriented world. In a sense, we’re extending the principle of polymorphism that applies to methods in OOAD, and extending it to contracts in Service-oriented development. However you look at it, the many-to-many relationships among policies, contracts, and Services represent a fundamental aha moment for Service developers.
Even when developers understand this fundamental aspect of Service-oriented development, however, they still face the problem that there’s insufficient tooling for creating Service contracts and policies available on the market today. In fact, while many of the companies with products for Service contract development, policy management, and policy enforcement have their own mechanisms for enabling users to create policies, there’s no single tool that a company can use to manage their contracts and policies across all their Service implementations.
In addition, one of the biggest issues still remaining with regards to Service contracts and policies is the vocabulary required to adequately describe all the needed aspects of Service contract and policy. It is clear from the above examples that WSDL by itself is not sufficient to describe all the functional and non-functional requirements of Services. And for those that have thought that WS-Policy might shed some light here, the awful truth of this spec is that it only provides an interoperable container for exchanging policy information, but doesn’t go about telling you exactly how to specify that policy behavior. Much work remains to be done here, and we hope that ZapFlash readers like yourselves can help to contribute to the solution to this problem by sharing with us your experience, metadata, or other things you use to put the meat behind the Service contract and policy bones. So, if you have found a good solution to the metadata problem, or have even come up with a good Microsoft Word or other text template to define Service metadata, let us know about it — we’re all ears!
These areas are clearly the state-of-the-art for SOA. We’re hoping that as 2006 proves to be the year that SOA takes hold in the enterprise, we mature not only our understanding of what SOA is and why we do it, but how deal with Services, contracts, and policies correctly so that we can realize the promise of IT systems responding in an agile, flexible, and loosely-coupled fashion to the changing requirements of business.