BT

Facilitating the Spread of Knowledge and Innovation in Professional Software Development

Write for InfoQ

Topics

Choose your language

InfoQ Homepage Articles Contract Versioning, Compatibility and Composability

Contract Versioning, Compatibility and Composability

This item in japanese

In the recent weeks, many industry analysts have been prompt to point out fears, uncertainties and doubts about SOA. Gartner, for instance, claims that companies with plans to start SOA initiatives are falling, while companies which plan no SOA initiatives have increased from 6 to 16% in the last 12 months. These notes and articles often sound as if companies no longer believe in building reusable IT assets which can be composed in different solutions.

We believe that the explanation for this lower level of interest in SOA is quite different: one of the key failure of SOA initiatives has been precisely the inability to produce reusable and composable assets. It seems as if that every new consumer brings enough fresh requirements to mandate a service different from existing services. Since services are more expensive to design, build and operate when compared to more traditional solution architectures, SOA cannot realize a large part of its business case when these services can’t be reused.  To our experience, few companies have been able to move beyond primitive reuse of services to achieve the promised effects of SOA.

If you ever hope to reuse a service, it is imperative to have clear design guidelines for contracts that express what this service provides and how it can be consumed. You may be able start your SOA initiative without much SOA Governance, but it would be a mistake not to have contract design guidelines. Overtime, these design guidelines will of course become a central part of your SOA Governance design compliance policies. It seems, however, that the industry as a whole has put a heavy emphasis on SOA Governance processes as a way to successfully build reusable assets, often dismissing the “Just a Bunch of Web Services” (JaBoWS) approach, but this strategy has yet to prove that it is enough to accomplish this particular goal.

We argue that SOA Governance is necessary but cannot generally deliver Service Specifications that are at the level required for reusing assets over long periods of time. SOA Governance is important, and as much governance as practical should be practiced when identifying, specifying and designing a service. However, because of limited resources, time and the inability to predict the future well beyond a 3-6 month horizon, Governance alone cannot create reusable assets. Inevitably, new and unforeseen service consumers will come with new requirements that will mandate an evolution of existing services. Without a proper versioning strategy, new versions of a service will result in a new service altogether, creating the need for similar, yet separate registry entries, code bases and lifecycles. Organizations without a proper versioning strategy often deploy, operate and maintain several “versions” of the same service in production drastically limiting SOA’s benefits and Return-On-Investment fueling comments from some analysts who have been prompt to claim that “reuse” should not be expected as part of a SOA initiative.

In this article, we provide a series of recommended practices for establishing a Service Contract Versioning strategy geared towards service reuse, composability and compatibility with prior consumers (or providers). We claim that such versioning strategy is essential to achieve satisfactory levels of service reuse and in turn generate higher (and expected) ROI from SOA initiatives.

Elements of a contract

“A contract is the most important metadata in SOA”, says Ron Schmelzer, analyst at ZapThink. There are many parts to a contract between a service provider and a service consumer. Some of these elements can be made machine readable, and even for some enforceable at runtime, using technologies such as XML Schema, WSDL and WS-Policy specifications for instance, while other elements will remain mostly for human consumption only.

The goal of this paper is not necessarily to look at every possible elements of a contract from the format and sequence of the bits that travel on the wire, to service level agreements or legal statements (about privacy for instance). Rather, we would like to focus on one simple problem: defining a strategy that supports the evolution of a service provider or consumer while remaining compatible with existing consumers or provider, respectively. We believe that this strategy is core to delivering the benefits of SOA and can greatly reduce both the initial cost of building a service (because it reduces the need for governance) as well as the ongoing service maintenance and operations costs.

The proposed versioning strategy is twofold:

  1. Create machine readable contract elements that express all rules enforced at run-time by both the service consumer and provider
  2. Create or leverage a set of compatibility rules between the versions of the contract elements agreed upon service consumers and providers

Machine readable contract elements are the foundation of versioning because this metadata can and must be used by both the service consumer and provider to decide whether the current message sent to and received at an endpoint will and can legitimately be processed. These elements define the lowest bar for a potentially successful processing of a given message. Of course, business rules in the service implementation can potentially return a contract exception.

One strategy could be to define no machine readable contract element and keep exchanging exceptions each time the consumer or provider cannot process a message, until either the consumer or the provider fixes the problem. For instance, members of the REST community have advocated the adoption of a “uniform contract” dismissing the need for further machine readable elements which could have otherwise provided unambiguous semantics while assisting in the implementation, validation or configuration of a service. Yet, the REST community does not provide evidence that RESTful Web Services can be evolved in a compatible way.

The problem is less about which contract elements one needs, but how to facilitate the expression of compatibility between two versions of a service provider (or consumer). In other words if a consumer interacts with a new version of service provider, are we expecting a behavior equivalent to the prior version or not? Adopting a “uniform contract” such as agreeing simply on sending and receiving messages at a particular location is not going to help answer the compatibility question.

In this article we will focus on the metadata necessary to validate whether an incoming SOAP message is legitimate or not. So we will focus on the contract elements defined in a WSDL document. Since the usage of WSDL 2.0 is not yet widespread, we will be using WSDL 1.1. We do not believe that there would be any significant changes when applying this strategy to WSDL 2.0. The elements of WSDL 1.1 include:

  • Service definition target namespace
  • Message types
  • Message definitions
  • Faults
  • Port types
  • Bindings
  • Service definitions
  • Optional policies expressed using WS-Policies

 

Fig 1. Elements of a WSDL 1.1. Contract

Versioning guidelines

Service and Schema Versioning can lead to these types of compatibility scenarios (Fig 2):

  • No compatibility
  • Forwards Compatible
  • Backwards Compatible

A new version of a contract that continues to support consumers designed to work with the old version of the contract is considered to be Backwards Compatible.

A contract that is designed to support unknown future consumers is considered to be Forwards Compatible.  Such a contract anticipates that consumers will evolve over time by supporting extensibility through XML Schema wildcards. This type of compatibility is often found in B2B scenarios where a consumer works with multiple service providers which may evolve at a slower pace. In the enterprise, the most common scenario is backwards compatibility.

Backwards compatibility is what is typically meant by “compatible” and is possible when non-breaking changes are made to a contract. Making breaking changes to a contract will always lead to no compatibility. These scenarios have been extensively described in the literature by John Evdemon or Dave Orchard for instance.

Note that contracts can be both backwards and forwards compatible (more on this later).

Fig 2. Service Operations Compatibility Scenarios

The degree of support of Web Services technologies for both forwards and backwards scenarios is unmatched in the distributed computing technologies world. Neither RPC, CORBA, DCOM or JEE have been able to support these scenarios out of the box, simply by applying specific design constrains. As a matter of fact the ability to support these scenarios is a key to achieving loose-coupling and reuse.

When a service is evolved in a backwards compatible manner, it can be reused by more consumers, without requiring existing consumers’ implementation or configuration to change. When Governance has failed to predict the needs of future consumers or when the budget prevented to get all the features needed in V+0, compatible service versioning is what enables updates without impacting existing consumers’ operations. In particular, this is how “JaBoWS” can slowly but surely evolve into Enterprise Class services, serving a wide range of consumers.

Compatibility is defined by a stated versioning scheme:

  • Major versions: incompatible (breaking change)
  • Minor versions: compatible (non-breaking change)

Breaking changes are modifications, for instance, to existing schema types that will cause processing of incoming messages to fail, such as changing an existing optional element to be mandatory or adding new required elements. Non-breaking changes are e.g. adding a new optional element. Non-breaking changes to schemas or services are registered as minor versions, while breaking will always be registered as a new major version.

All the versionable artifacts of a service will be affected by changes, and these changes will ripple through the artifacts from bottom to top, and eventually the ripple effect will impact your consumers. This ripple effect is detailed in table 1 and illustrated in figure 3. While versioning lets you control the effects of changes, compatibility helps you alleviate some of the negative effects of versioning.

Fig 3. The ripple effect of changes

In the following, we will state that a service version is incompatible using a major version and a compatible version (forwards or backwards) using a minor version. Point version should be used to denote versions that did not involve contract changes and were limited to implementation, deployment or configuration changes (for instance a bug correction, a new service container release, etc). Point versions are always compatible by definition (again this is a statement not a guaranty).

 

Artifact Change Major Minor Point
Service Breaking X    
Service Non-Breaking   X  
Composite Service Incompatible Schema Service X    
Composite Service Compatible Service   X  
Service Incompatible Schema X    
Service Compatible Schema   X  
Schema Breaking X    
Schema Non-breaking   X  
Schema Aggregate Incompatible Schema X    
Schema Aggregate Compatible Schema   X  
Code Bug fix / maintenance     X
Code Safe modifications   X  
Code Semantic / Unsafe modifications X    
Other service artifacts Any     X

Table 1. The versioning ripple effect of changes to code, schemas and services

Two message types can be stated to be compatible using these simple rules when designing Message Type Schemas:

  • XML Namespace values must be constant for a given message type and a given major version
  • Message type schemas must include mandatory minor and point version custom attribute on the message type root element, using for instance a type xsd:int.
  • Whether XML validation is used or not, each message consumer must verify that the major version of an incoming message is matching its own implementation version. An exception should be returned when the major versions of the message sender and receiver do not match.

In the .Net world, Message Type artifacts are also known as data contracts.

Web Services Extensibility Guidelines

The principles of backwards compatibility have been well documented (see also this reference), yet they are rarely applied. For the sake of clarity we are detailing them here.

Service definition target namespace

WSDL target namespace can be different from Message types XML Schema namespaces. WSDL target namespace must be different each time the service contract or implementation is modified, be it for a point, minor or major version

This namespace is not used at runtime, provided that SOAP actions are defined manually instead of automatically by the runtime. Therefore, all WSDL definitions MUST include manually defined SOAP actions[1]

Message types

Message type schemas must be designed with the utilization of XML Schema extensibility mechanisms (we provide a detailed discussion of these mechanisms below)

Message type namespaces must only refer to a major version of the service contract, indicating an incompatible service version. Minor version may be specified as an attribute to the root element

Message definitions

Parts can potentially be added to message definitions, we however recommend to use a single part which contains a message envelope in which content can be extended using XML Schema’s extensibility rules

Faults

Faults cannot be added to an existing operation, unless they pertain to message type extensions associated to a new minor version

Port types Port types can be extended with new operations

No changes can be made to the operation’s signature nor the order in which the operations are called (which is not specified in WSDL)

Bindings

New bindings can be defined, however, existing bindings cannot be modified, including the endpoint of the service

Service definitions

Services definitions can only be extended with new ports, existing ports cannot be altered

Optional policies expressed using WS-Policies

There are no general framework available to assess compatibility scenarios for policies

Table 2. Service Definition Compatibility Design Rules

The design of Message Types using XML Schema must be carefully planned to achieve backwards compatibility, also known as XSD extensibility.

John Evdemon explains:

The XML Schema standard introduces as a wildcarding element. enables schemas to be extended in a well-defined manner. includes a namespace attribute that either constrains or extends the range of elements that might appear within the wildcard. The namespace attribute can be set to any of the following:

  • ##any enables the use of elements from any Namespace to extend the schema.
  • ##targetnamespace restricts wildcards to the elements that appear within the targetNamespace.
  • ##other makes it illegal to extend the schema using elements from the targetNamespace.

The processContents attribute dictates how schema extensions should be validated by the parser:

  • strict requires the parser to validate all schema extensions.
  • skip turns off validation for schema extensions.
  • lax validates elements from supported namespaces and ignores unknown or unexpected elements (most Web services specifications use lax).

 

Regarding XSD extensibility, there is a snag in the XML Schema’s  1.0 specification. Because of the unique particle attribution (UPA) rule there is an ambiguity during the validation of XML Schema types that have an optional or unbounded number of elements as their last element in the type definition. For that reason, when the last element of the type has a variable cardinality, we have to add a specific element with a cardinality of exactly one, before using the element.

For instance, you may want to choose an element such as this one:

<eovmxmy> where x and y are the major, minor version numbers  (eov stands for end-of-version)

In XML Schema 1.1 this ambiguity will be removed and this additional element will not be needed.

Using XML Schema extensibility features is one thing, but we still need to define and agree on a set of rules when an older version of a message consumer encounters a newer version of a message. It is likely that this new message will have elements that fall in the some of the extensibility sections of the original message schema. The question becomes then, what should we do with these elements?  We recommend applying the following rules which result in Backwards Compatibility requiring no consumer side changes:

  • The behavior of a service when it encounters an unknown element must be clearly defined by an extensibility handling rule as part of the contract
  • New elements added to a new version of a message type designed to be backwards compatible must not invalidate the prior version of the message type
  • Consumers of a message must accept and remove from processing any element that they do not recognize
  • Responses generated from a request that contains the same types as their corresponding request must add the corresponding elements they removed prior to processing the request

These rules ensure that every consumer is in the position to use XML schema validation for the elements that it is bound to process in its implementation. In no way, we recommend using XML and XML schema extensibility in a sloppy way and forego validation (Figure 4). Contrary to a widespread belief in the industry, XML and XML Schema extensibility is essential to a compatibility-based versioning strategy, and hence essential to achieve reuse. In a bizarre fate, this key technological advance has been all too often discounted by industry experts and analysts.

Consumers and providers’ implementations are asymmetric when it comes to their implementations:

  • If the consumer validates the incoming messages sent by the provider, they will pass validation (because of the implementation rules defined)
  • However, -and of course- the service provider implementation must in general keep track of the schemas for all the minor versions for incoming messages and validate each incoming message based on its minor version number for a given major version, even possibly route the call to variants of the implementation

The reason for that is because an upper minor version schema cannot validate a lower version schema (in general). The upper minor version will most likely have required elements in the same target namespace that cannot be validated with a lower minor version schema.

Consumer Variations

There is also a need for “extension areas” in an XML Schema that are different from versioning (Figure 4). For instance, extensions are common when consumer specific variations are needed, i.e. when specialized relationships between consumers and providers (independently of other consumers) are necessary. These extensions can be viewed as a private contract between a particular consumer and the service provider, embedded in the contract common to all consumers. Again, having a strategy to enable these extensions is essential to achieve a good level of reuse of services.

  • Extensions must be treated separately from the general versioning patterns. We recommend implementing extensions using a single element under the root element of the message type.
  • Extensions must not be processed by the message consumer, unless they are explicitly defined in its message type or unless specified with a mustUnderstand=’true’  attribute. The message consumer’s implementation must generate an exception when it cannot process the required elements.
  • It is advised that extensions belong to a different namespace from the root of the message type.

Fig 4. Versioning and User Extension Compatibility

With Web Services technologies, the fact that one may use different endpoints to access the same information via different versions of the business logic simplifies greatly the maintenance and operations of the corresponding services. Overall, Web Services technologies, XML and XML Schema offer unprecedented opportunities to support compatibility scenarios unlike distributed computing technologies before them, including REST which cannot rely on a stable contract to specify a versioning strategy. In REST, the fact that each resource (instance) exposes an endpoint is creating a strong coupling between the endpoint and the resource (instance) which makes it difficult to operationally manage multiple major versions of the implementation of the business logic as REST offers no room to introduce a layer of indirection between the two. This coupling between resource and endpoint makes it difficult to assign a version to a resource type since in REST, resource types do not exist and each resource (instance) can potentially implement its own version of the business logic associated to a particular version of HTTP verb and arbitrary noun.

Compatibility & Composability

The compatibility scenarios defined earlier can be combined into these strategies as defined in the latest Thomas Erl series book Web Service Contract Design and Versioning for SOA:

  • Strict: Any change is considered unsafe and must cause a new version. Non-breaking changes cause a new minor version. Breaking changes will require a new major version. Both backwards and forwards compatibility is intentionally disregarded.
  • Flexible:  Non-breaking changes will only result in a new point version. Breaking changes will of course require a new major version. This strategy uses backwards compatible contracts, but not forwards compatible contracts.
  • Loose: Use both backwards and forwards compatible contracts. Breaking changes will of course require a new major version.

“Strict” is a very common approach to handling schema versioning. It is a safe approach that will give you no surprises when changing contracts. In fact, the schema artifact versioning table shown above is based on the “Strict” strategy. However, it will lead to an explosion of contract versions as your services evolve, and this will hurt discoverability and especially governance not to mention reuse. In addition, operations will need to keep your multitude of service versions up and running. Changes to schemas that are used in aggregate schemas (schema compositions) will ripple through all involved aggregates and cause a domino effect of new schema versions. And of course, when a schema used in a service gets a new version, the service must also get a new version. Composite services that involve these services will then also be affected and must also get a new version.  Thus, the ripple effect is much bigger than you think.

This versioning domino effect soon has caused a little change to ripple through all versionable artifacts in your system. And it doesn’t stop there; in the end it will affect your consumers.

Composability will suffer when you have poor service discoverability and a proliferation of service versions. Which services should an unfortunate consumer use and which services will work together as composite services? Having standardized service contracts including a common information model for your domain might not be enough when there are thousands of versions of the standardized services and schemas.

“Flexible” tries to alleviate the version explosion effect of Strict, by treating all non-breaking changes as safe and backwards compatible. As backwards compatible contract changes by design continues to support consumers designed to work with the old version of the contract, a new version is not needed – i.e. it is just a point version. Services can easily be composed together as all the contracts within a major version are backwards compatible and only one minor service version – the latest – needs to be considered for every major version. Add “Loose” to get forwards compatible contracts, and all your compatibility & composability issues are history.

In theory this seems to be the perfect solution, only breaking changes will require a new version and hence ripple through all versionable artifacts. In theory - had it not been for possible side-effects of “safe” changes, both functional and non-functional. As Nicolai M. Josuttis shows in the book SOA in Practice even adding a new optional XML element can have non-functional side-effects such as increasing the response time of a service, breaking the SLA of the service. It would be safer to provide a new service version with the new schema, as if there is a problem, only the upgraded consumers that required the change will be affected. Keep in mind though, that in our proposed recommendations, the compatibility is stated, not implied, so if the SLA was changed by a single element, this would mandate the definition of a new major version (and XML namespace), even though from an XML extensibility perspective, this change is perfectly compatible.

A certain combination of these will work better to our experience:

  • Flexible/Strict: Use “Flexible” for all safe schema changes, while “Strict” must be used for any unsafe modification to schemas. Breaking changes will require a new major version. This approach supports backwards compatibility.

The “Flexible/Strict” strategy combines the best from the three original strategies. It grades changes into safe and unsafe even if they are theoretically backwards compatible (i.e. non-breaking). Safe changes cause point versions, while unsafe changes cause at least a minor version. There are no absolute classification schemes of which changes are safe and which are unsafe, but we suggest that adding to schemas are considered safe while modifying existing schema components are considered unsafe. Always judge if even a “safe” change may cause negative side-effects, remember to consider non-functional aspects.

Strategy Change Major Minor Point FW
Strict Breaking X      
Strict Non-Breaking   X    
Flexible Breaking X      
Flexible Non-Breaking     X  
Loose Breaking X     X
Loose Non-Breaking      X X
Flexible/Strict Breaking X     +
Flexible/Strict Non-Breaking, Safe     X +
Flexible/Strict Non-Breaking, Unsafe   X   +

Table 3. Compatible changes classified as safe or unsafe

Using “Flexible/Strict” will impact the schema artifact versioning table as all changes that in the “Strict” sense must be a new minor version now can become just a point version for safe changes. Unsafe non-breaking changes must still be a new minor version. Note that even if you judge a code change to be safe, we still recommend this to be a new minor version.

Schemas are validated and routed based on their major and minor versions, thus aiming for point version compatibility will also reduce the need for intricate versioning mechanisms in your services.

We recommend using the “Flexible/Strict” strategy for your published services, and also use forwards compatibility in the form of planned extensibility. Avoid just throwing in schema wildcards everywhere as this will lead to vague contracts, countering discoverability. John Evdemon advises that “schemas should be designed for extensibility, not to avoid versioning”. Judicious use of unambiguous wildcards can help minimize service versioning. We strongly recommend following these guidelines.

Use a combination of compatible contracts and multiple active service versions to ensure that you’re system is flexible enough to accommodate the inevitable changes that will happen over time. Keep things simple. Whatever you do, do not try to implement some implicit automagical handling of versioning inside your services; instead expose your services at abstract endpoints and apply intelligent routing to achieve service virtualization and apply schema duck-typing outside your services.

You should use the flexible strategy during development of the services due to the agility needed in that phase. Wait until the services have been published (are in production) to apply strict versioning aspects, otherwise you will just end up with a very frustrated bunch of consumer and provider developers.

Note that how platforms support backwards compatibility differs. Some require the use of schema wildcards while others like WCF have implicit support for forwards compatibility. Always test that your involved platforms work with your backwards compatible schemas. Don’t rely on this just working, interoperability is important for composability.

Data Model and Message Type DSLs

One of the core problems of distributed computing technologies is the combined handling of both information and business logic. Some approaches are good at managing distributed information (REST / HTTP) and some technologies are good at invoking business logic (Web Services). Technologies that have tried to address both using a combination of remoting technologies and naming & identity services have generally failed at delivering an environment where both information access and business logic invocation coexist harmoniously. Most often, a pattern, such as the Data Transfer Object pattern, has become the prevalent mode of interaction and information representations are simply conveyed back and forth between endpoints representing services, i.e. business logic.

One of the fundamental reasons for the lack of solution for this difficult problem is the fact that Enterprise Data is “relational” and utilizes most often bidirectional associations. By contrast, the Web is built on a “navigational” data model and unidirectional links. In both cases (navigational and relational), there is always the need to fetch data in a denormalized way via the same endpoint. This means that when fetching a purchase order, one might also return some customer specific information (name, address, telephone…) as well as shipping information. Whether you use a RESTful approach or a Web Services approach, the problem is exactly the same. REST is of course slightly better equipped to provide a normalized solution to this problem since a link to the customer can be embedded within a purchase order representation, but this is generally not practical as representations often need to embed related data, to enhance user experience, limit navigations and network roundtrips.

The goal of this paper is not to solve this distributed information integration problem. We are going to assume that somehow people can only deal with it behind endpoints in both REST and Web Services world (this is the state of where we are today until more progress is made in distributed computing technologies). In this environment, the problem people have to deal with is how to manage denormalized message types, especially in the context of versioning, i.e. when the enterprise data model needs a revision (Fig 5.). 

Fig 5.  How do we keep the enterprise data model and message types synchronized?

 Up until this point, the industry has kept Enterprise Data Models, XML Schemas and Message types relatively separate. At most, people defined an ontology with links to both. 

In this article we argue that (Fig 6.)

  • XML Schema should not be used for creating and managing enterprise data models.
  •  Enterprise Data Models should be created and managed based on a DSL (EDM-DSL)
  •  Message types should be created and managed based on a DSL and using the Enterprise Data Model elements as building blocks (MT-DSL)
  •  XML Schemas should be generated from the Message Type DSL (itself referencing elements of the Enterprise Data Model).

Fig. 6. Enterprise Data Model and Message Type DSLs

Let’s explore these points one by one. XML Schema should not be used for creating and managing Enterprise Data Model because XML Schema was never designed for that. XML Schema cannot describe efficiently the relational nature of enterprise data models. XML Schema is hierarchical in nature and cannot model well bidirectional relationships between information entities. XML Schema is a technology that is well suited to describe and validate the structure of self-standing “documents” be it message types, web pages, office documents…

Enterprise Data Models should be created and Managed based on a DSL because no current modeling technology, be it UML or Entity-Relationship diagrams (ERD) have the appropriate semantics to describe Enterprise Data Models. The core semantic that is missing, and that makes it a non starter for any existing technology, is paradoxically having the ability to describe a hierarchical structure of related elements. In other words be it in UML or ERD, we do not have the semantic to define the boundary of a purchase order or a customer. We can define classes or entities, but in reality a purchase order or a customer is effectively “composed” of several classes. We need to be able to define a boundary to these objects and no “standard” modeling language support this semantic because they themselves are too close to the physical implementation model (Object Orientation in the case of UML and RDBMS in the case of ERD). In the case of UML, we would have to define a UML profile to extend it with these semantics. We recommend however to create a dedicated Data Model DSL instead of using a UML profile because transformations are a lot easier, uncluttered by the UML metamodel.

Message types should be defined based on a dedicated message type DSL which references elements of the Enterprise Data Model because, in essence, this is really how Message Types are constructed (or at least should be constructed). When you create a service interface, be it RESTful or Web Services based, you really want to create a message type (or resource representation) that reflects the enterprise data model both semantically and structurally, instead of reflecting the particularities of a given back end system. This is in line with loose coupling practices which recommend to minimize the “contract-to-implementation” coupling. An approach based on the semantics of an Enterprise Data Model is expected to reduce the need for both Governance (or at least reuse Data Governance efforts) and create service interfaces or resource representations that will be most likely reusable and composable.

Finally, flat XML Schemas should be generated from these Message Types definitions (based themselves on the Enterprise Data Model). Flat schemas improve interoperability between Web Service stack as some stack have difficulties to deal with complex nested schema files. XML Schema is a great technology to validate the structure and (some of) the content of “documents”. It should remain the primary choice for describing the structure and validating the content of incoming messages.

Active Service Versions

It is important to implement service lifecycle management policies and procedures to help with governing service versions. We recommended creating an “Active Service Versions” policy to keep the number of service versions that you have to govern to a minimum. Alas, our experience shows that in practice this will be hard to adhere to, thus implement the policy as a guideline rather than a law.

Such a policy typically states that there should be maximum three active versions of a service available for consumers, plus a hidden active minor version of the latest major. The hidden minor version gives current consumers a transition period for reverting to a compatible version, just in case the compatibility statement made for the latest minor version was erroneous. In that case, the consumer will manually point to the previous minor version endpoint.

Fig. 7. Service version classification

You will typically end up with some services that require 5-6 major active service versions, especially for popular services that are used by multiple consumers. There will always be some consumers that are laggards in upgrading to newer service versions, and you might not be able to cut them off. However, the approach that we are recommending ensure that for every major version available, we only need to expose the respective latest minor version.

Ensure that new consumers always by default discover the published version of your services (i.e. the latest major/minor version). The published version is what developers will get using the classic http://url?WSDL “discovery” of the service. In addition, we recommend that three major versions of a service can be discovered in your service registry. These must be the latest minor version of each.

Finally, you must monitor the usage of the services to know which are used and by whom. The service lifecycle stewards must notify all consumers of deprecated versions and gently force them to upgrade to an active service version. When no one (important) is using a deprecated version, you can decommission it. This ends the lifecycle management of that service version. You can easily imagine how much harder the steward’s job would be if he or she had to do the same thing for both the major and multiple minor versions as well.

The active service versions should be accessible through a single virtual endpoint that the consumers use to invoke the service. This will lessen the impact that versioning the service will have on its consumers, as the virtual endpoint stays the same and handles the routing to the correct active service version. Compatibility reduces the need for virtualization as the same endpoint can service several generations of compatible consumers. Services are routed based on their major and minor versions, thus aiming for point version compatibility will also reduce the need for complex virtual endpoint mechanisms.

Service Virtualization is achieved by combining several ESB patterns such as abstract endpoints, intelligent routing and schema transformations. Using service virtualization isolates the consumers from the providers and it processes messages “in-flight” to route and mediate between the providers and versions that make up a composite service that a consumer invokes or triggers through an event.

Using virtualization is not only for composite services, in fact all your published services at any classification level would benefit from this seen from a governance perspective.

Interoperability

The economy is getting more and more globalized and outsourcing seems to be the standard these days. The business processes of a company more often than not involve partners and suppliers mashed together into what is called the extended enterprise

The constituents of an extended enterprise will have heterogeneous systems, just as the different business units of a company most likely will have heterogeneous systems (figure 8). There is no end to the diversity of legacy systems in use in companies today. A recent Gartner study shows that the diversity of platforms used to deliver SOA is growing, even mainframe COBOL have had a surge the last year.

Composability across these heterogeneous service providers in the extended enterprise will require interoperability. This affects how you design your services and schemas, including which of the WS* standards you choose to entail in your services. Our interoperability experience is summarized in the below table.

Artifact Interoperability
SOAP Adhere to WS-I Basic Profile 1.1
SOAP 1.2 Most legacy platforms and tools require SOAP 1.1
WSDL style Prefer “Document/Literal Wrapped” (D/L-W)
WSDL design Avoid wsdl:import and xsd:import as many tools require a single flat WSDL. An example is Flex.
Messages Use message exchange patters (MEP) e.g. as defined in WSDL 2.0
Message design Single part element for both request and response
Schema style Prefer “Venetian Blind” (complex types)
Schema style Do not use anonymous types (“Russian Doll”)
Schema design Support XSD extensibility, use marker element before schema wildcard; always test support for schema wildcards across involved platforms
Schema design D/L-W schema components:  allows only elements,  prohibits use of attributes
Schema design Use of attributes for data or to annotate data elements might not be supported by all platforms
Schema arrays Use wrapped arrays/collections
XSD types Not all XSD data types are supported by all platforms (e.g. xs:date, xs:positiveInteger)
XSD nillable Some nillable schema components might not be supported by a platform, while other components might be required to be nillable
WS* standards The support varies wildly between platforms, always test and verify chosen standard for interoperability
WS-Security Make sure to agree on version, token type, message or transport security, order and level of encryption and signing, and establishment of secure conversations (security sessions)
WS-Policy, WS-SecurityPolicy Some platforms and tools do not support these standard, thus policy metadata have to be communicated out-of-band. An example is Java Spring-WS.

Table 4. Contract design guidelines

 

Fig. 8. Growing diversity in SOA platforms

The figure “Trends in Use of Development Languages are Related to SOA Adoption” is from the Gartner report “2008 SOA User Survey: Adoption Trends and Characteristics” by Daniel Scholler.

Conclusion

In this article we have defined a versioning strategy which focuses on reuse by enabling services to evolve to meet new consumer requirements without breaking existing consumers of the service. This approach adds a new dimension to the reuse of service: in a way it introduces a “forward” reuse strategy, as the “new version” of a service is reused by the older consumers instead of the other way around, while people traditionally think of reuse when a new consumer reuses a service designed for an existing service consumer.

From our experience, we feel that compatible, versioned data models, messages and services have not been a primary concern of SOA initiatives. In addition, of those that defined a versioning strategy, very few have used XML and XML Schema extensibility. It is our strong belief that a compatibility-based versioning strategy can increase service discoverability, composability and true reuse. It can also reduce, albeit not eliminate, the need for service governance. Overall, it is expected that the cost of construction, operation and maintenance of a service will greatly be reduced by such versioning strategy. It is time to move beyond primitive reuse to reap the benefits of your service inventory.

[1] Harmut Wilms, InnoQ, Private Communication

Rate this Article

Adoption
Style

BT