Sunday, February 01, 2009

Service Compatibility - A Primer

In a comment on the InfoQ article Contract Versioning, Compatibility and Composability about my definition of service forwards and backwards compatibility, the problem of talking about compatibility of services compared to the definition of schema compatibility is acknowledged.

The "problem" is that a service version that is compatible with the specifications of older versions of the service, can be achieved using both backwards and forwards compatible schemas. That is correct, but doesn't preclude having a definition of forwards and backwards compatibility for service providers, a.k.a "services". Service compatibility is based on ability to validate a message, it is not based on using wildcards in the schema definition.
For a definition of the three types of forward compatibility, see my post on schema, service and routing compatibility.

Seen only from the service provider perspective, how it handles incoming messages is what defines if a service is forwards or backwards compatible (or both). How consumers handle messages sent by the service is really not of any concern for the provider - wait, read on.

Thinking about this within SOAP 1.x constraints, where a WSDL operation has a request message and a response message with fixed schema definitions/version (unilateral contracts), will lead to the conclusion that operations cannot be classified as forwards or backwards compatible, only the message schemas. This is a limitation of SOAP, but not of messaging in general.

In the following examples, the v1.2 service provider is backwards compatible and interacts with a v1.1 consumer. However, the schemas are not designed to be forwards compatible - they do not support XML extensibility (schema wildcards). In this scenario, the consumer can do either XSD validation of response messages against the v1.1 schema, or do 'validation by projection' of response messages - i.e. do "ignore unkown" validation. Doing 'validation by projection' is a recommended practice for compatibility and really simplifies building SOA solutions - this is also how WCF validates messages. So how to handle consumers that only do XSD validation, without relying on schema wildcards?

In REST, the consumer can put an "accept formats" header in the v1.1 request message, and the service provider can then respond with a v1.1 schema even if the service version is v1.2. The service provider adheres to it's obligations by being backwards compatible, and the consumer is allowed to express it's version expectation - the service has bilateral contracts.

Service Virtualization is a mechanism that can help with service versioning. The task of such an abstract endpoint intermediary is to handle versioning through both service compatibility and schema compatibility. A virtual service supports multiple versions of the service on the same endpoint, and must be capable of processing older requests. The virtual endpoint must have a mechanism that allows for the latest major v1.2 provider to handle v1.1 consumers. The intermediary mediates between the schema versions by transforming or projecting/enriching the messages as needed.

Back to the example, the service provider v1.2 response message can be stripped down to a v1.1 message by the intermediary as it is sent back to the consumer. The net effect is that the service has virtual bilateral contracts.

In messaging in general, by definition there are no duplex channels, only one-way channels (see
Enterprise Integration Patterns by Hohpe/Woolf). On top of this, you can have a logical two-way channel for message exchange patterns such as request-response, specified using a "reply-to" address and a "reply-format" (bilateral contracts). The message compatibility is defined by the schema constructs, but just as in REST, the version of the incoming message does not dictate the version of the response message. It is the implementation of the endpoint that processes the messages that defines the compatibility policy of the endpoint, not the schemas.

So, service compatibility do not require using forwards compatible schemas in addition to backwards compatible schemas. The message validation policy is what defines service compatibility.

It is of course much simpler to just have a service compatibility policy based on that the schemas used in the services must be both forwards and backwards compatible - as shown in the "SOAP-style unilateral contracts" service compatibility figures.

Click figures to enlarge.

This way, the service provider or consumer platform need not handle "request-format" and "reply-format" that have different versions. In such a unilateral schema compatibility policy world, services are just intrinsically compatible through schema compatibility.


Integral ):( Reporting said...

>> In REST, the consumer can put an "accept formats"
>> header in the v1.1 request message, and the
>> service provider can then respond with a v1.1
>> schema even if the service version is v1.2

In REST versioning problems are a bit more subtle due to the coupling between the resource access and URIs.

First, the "accepts format" was not intended to be used for versioning but rather for different "data formats" such as HTML, XML, PDF... so this means you have to weave the versioning scheme on top of the "accept format" semantics.

Second, there is no "interface" or artifact to version. So you have no way to say that now I want to work with v1.2 of all the business logic associated to this resource. You better be lucky that you did not forget to update an accept format in your consumer code.

But last, when you have a major version of the business logic associated to a resource, you can't move your resource to a different endpoint. If you do then the question becomes is /customers/v1.1/123 the same as /customers/v1.2/123. REST mixes up "identity" and "access" and that's not very helpful for versioning.

Now, of course if you are using REST, just as a "protocol" and not a "resource oriented application protocol" you can encode any (proprietary) semantics in it.

Kjell-Sverre Jerijærvi said...

Yes, REST has a (long) way to go regarding versioning. The thinking I've seen is about using the format both for specifying the resource type + version + format, and not using the URI for versioning.

And as you say, the URI is used for several things, such as links, identity and, in combination with the uniform interface, actions. So I think keeping version expectations as a header is better than overloading the URI with even more semantics.

As an interesting side note, I watched Stefan Tilkov's REST & SOA presentation and the Web2.0 cross-site scripting (XSS) attacks today on InfoQ; and think of the implications of bad browsers and XSS in combination with every enterprise resource available through URIs. Better get a good access management story around this.