Consumer-driven contracts
The use of Schematron in the above example leads to some interesting observations about contracts between providers and consumers, with implications beyond document validation. In this section we draw out and generalise some of these insights and express them in terms of a pattern we call Consumer-Driven Contract.
The first thing to note is that document schemas are only a portion of what a service provider has to offer consumers to enable them to exploit its functionality. We call the sum total of these externalized exploitation points the provider contract.
Provider contracts
A provider contract expresses a service provider’s business function capabilities in terms of the set of exportable elements necessary to support that functionality. From a service evolution point of view, a contract is a container for a set of exportable business function elements. A non-normative list of these elements includes:
• Document schemas: We’ve already discussed document schemas in some detail. Next to interfaces, document schemas are the parts of a provider contract most likely to change as the service evolves; but perhaps because of this, they’re also the parts we have most experience of imbuing with service evolution strategies such as extension points and document tree path assertions.
• Interfaces: In their simplest form, service provider interfaces comprise the set of exportable operation signatures a consumer can exploit to drive the behaviour of a provider. Message-oriented systems typically export relatively simple operation signatures and push the business intelligence into the messages they exchange. In a message-oriented system, received messages drive endpoint behaviour according to semantics encoded in the message header or payload. RPC-like services, on the other hand, encode more of their business semantics in their operation signatures. Either way, consumers depend on some portion of a provider’s interface to realise business value, and in consequence we must account for interface consumption when evolving our service landscape.
• Conversations: Service providers and consumers exchange messages in conversations that compose one or more message exchange patterns such as request-response and fire-and-forget. Over the course of a conversation a consumer may expect the provider to externalise some state particular to the interaction in the messages that it sends and receives. For example, a hotel reservation service might offer consumers the ability to reserve a room at the outset of a conversation and to confirm the booking and make a deposit in subsequent message exchanges. The consumer here might reasonably expect the service to “remember” the details of the reservation when engaging in these follow-on exchanges, rather than demand the parties repeat the entire conversation at each step in the process. As a service evolves, the set of conversational gambits available to provider and consumer might change. Conversations are thus candidates for being considered part of a provider contract.
• Policy: Besides exporting document schemas, interfaces and conversations, service providers may declare and enforce specific usage requirements that govern how the other elements of the contract can be realised. Most commonly, these requirements relate to the security and transactional contexts in which a consumer can exploit a provider’s functionality. The web services stack typically expresses this policy framework using the WS-Policy generic model plus additional domain-specific policy languages such as WS-SecurityPolicy, but in the context of our considering policies as candidates for being included in a provider contract, our definition of policy is specification and implementation agnostic.
• Quality of service characteristics: The business value potential that service providers and consumers exploit is often evaluated in the context of specific quality of service characteristics such as availability, latency and throughput. We should consider these characteristics as likely constituents of a provider contract and account for them in our service evolution strategies.
• The definition of contract here is a little broader than the one we might usually offer when talking about services, but from a service evolution perspective it usefully abstracts the significant forces that impact our problem domain. That said, the definition is not meant to be exhaustive in terms of the kinds of elements a provider contract might contain: it refers simply to a logical set of exportable business function elements that are candidates for including in a service evolution strategy.
• From a logical point of view, this set of candidate elements is open, but in practice internal or external factors, such as interoperability requirements or platform limitations, may constrain the type of elements a contract can contain. For example, a contract belonging to a service that conforms to the WS-Basic profile will likely not contain policy elements.
• Notwithstanding any such constraints, the scope of a contract is determined simply by the cohesion of its member elements. A contract can contain many elements and be broad in scope, or focus narrowly on only a few, just so long as it expresses some business function capability.
How do we decide whether to include a candidate contractual element in our provider contract? We do so by asking ourselves whether any of our consumers might reasonably express one or more expectations that the business function capability encapsulated by the element continue to be satisfied throughout the service’s lifetime. We’ve already seen how consumers of our example service can express an interest in parts of the document schema exported by the service, and how they might assert that their expectations regarding this contractual element continue to be met. Thus, our document schema is part of our provider contract.
