My last post generated a lot of great comments. I think it's important not to confuse your schema with your contract. A client and a service have to agree on all sorts of things, only some of which are captured in your WSDL/XSD(/Policy). My goal in proposing that almost everything in your XSD be optional is to find the sweet-spot between easy coding and flexibility for evolution.
In general, I want to provide an XSD so that consumers can build an object model and get intellisense if they want to. But once I commit something to XSD, changing it (as opposed to extending it) typically means changing the XSD namespace. Most OX mappers bake the target namespace into code. So if I change that, I'm forcing a lot of changes into clients. I'm also forcing my service to work with two essentially identical type models if I want to support multiple versions. That leads to loads of boiler-plate object-to-object mapping code. If a client is using the same types to talk to more than one service as well, changing schema namespace may introduce the same sort of mapping there as well. So my goal is to maximize support for evolution without changing target namespaces. This is the heart of my versioning model, which breaks the world into three sorts of changes: additions, extensions and changes. I can handle the first two without changing namespaces. I want to see what changes I can handle without changing namespaces. The most obvious (are they also the most common?) change is occurance requirements.
Consider a simple example. I have a system that receives Customer data. In V1, I define customer like this:
<complexType name=”CustomerType”>
<sequence>
<element name=”FirstName” type=”string” />
<element name=”LastName” type=”string” />
<element name=”Address” type=”tn:AddressType” minOccurs=”0” />
</sequence>
</complexType>
FirstName and LastName are required, Address is optional. Then, in V2, I decide that Address is actually required. I can implement this change two ways:
- Revise the XSD to capture this requirement by marking the Address element minOccurs=“1“, change the XSD target namespace because this is a breaking change, and then use schema validation or some other approach to enforce the requirement.
- Leave the XSD alone and modify my service logic to enforce the requirement using an internal XSD for schema validation or some other approach to enforce the requirement.
The advantage of (2) is that all systems that were already sending the optional Address data simply continue to work, and I don't have to write lots of object model to object model mapping code. It's only those that do not work that way which need to be modified (but if Address is a real requirement, they needed to be modified anyway). The benefit for those systems is that the modification does not require moving to a new schema definition, which means more work on their part (if they’re using the same types to talk to other systems that aren’t moving to the V2 namespace at the same time, this saves writing lots of boilerplate object-to-object mapping code).
You might argue that this approach makes it so the client developer doesn't or can't learn what the real requirements are for your service. I disagree. That information just has to be conveyed some other way. Further, this encourages the client developer to understand that your service will evolve and that they should expect that they may need to move to keep up.
It's worth noting that if you are designing an XSD for use by lots of different services, you probably don't know what occurance constraints they will require. Making content optional makes loads of sense in that case too.
Posted
Apr 24 2006, 03:04 PM
by
tim-ewald