Monday, April 6, 2009

Versioning of Web Services

I was asked an interesting question the other day: how do I handle the versioning of web services? It was a hard question to answer (the person who asked me is a delivery manager of a large bank, and openly admitted that he has no real strategy as of yet either).

Incidentally, I also had struggled with another question a year or two ago, which was simply how do I handle versioning of assemblies in .Net. That gets tricky too. And as for handling of different jar versions in the Java world, well that's just a nightmare. Use Ivy I guess!

Web Services 101

This isn't a web service primer, but in simple terms, the steps consist of:
  • Whack up a wsdl (or generate one from existing classes)
  • Implement the service based on the wsdl interface
  • Publish the service in some way (UDDI, tell your friends, use twitter.com....)
  • Clients subscribe to the service via the wsdl
  • Clients produce their own client side proxies
  • Clients call web methods, and the server returns the results
To me, when you use web services in their full glory, you effectively have just another API, albeit a facade for a remote server somewhere. So, all the challenges of versioning come into play.

And Then a Change is Made

So what happens when a client wants a new feature, a different result to be returned, etc. Well, the web service implementation is updated, and perhaps so too is the wsdl (particularly if this is a breaking change).

But, what happens when the implementation of the service changes in a non-breaking way? Do we still tell the world that a new version of the web service exists? Or do we keep this secret?

When a new version of a web service is produced (for whatever reason), there are two sides to consider: client side and server sided. Yes, we need to implement the actual implementation of the new version, but the clients will require updating too.

Changing one web service client application is not too hard. But what happens when you have 100 different clients all calling the same application, and only some of them want the change?

Luckily, in the .Net world, when a web service is changed, as long as the changes do not break the contract, then clients do not require updating.

In the Java world, I have been told that the client side app will have to be recompiled based on the new wsdl (I guess Java web service implementations do a full regeneration of the wsdl, and clients always do an xsd validation against the wsdl).

An example of a breaking change is this:

Old interface:

MethodA(string arg1, string arg2, string arg3);


New interface:

MethodA(List args);

An example of a non-breaking change (in the .Net world) is:

Old interface:

BankAccount GetAccount(string id);


class BankAccount {

decimal Amount;
}

New interface:

BankAccount GetAccount(string id);

class BankAccount {

decimal Amount;
date ModifiedUTC;
}

If the client has the new version of the Bank Account class, then the date modified field will simply be null. If the server has the new version of the Bank Account class, then the date modified field will be sent across the wire to the client, but the client proxy will simply ignore the additional data within the SOAP packet.

Supporting Side-by-Side Implemetations

The good news regarding versioning is that a server can side by side support two versions of web services. However this can get messy.

I guess the golden rule here is to take a leaf out of the book of domain driven design.

Design your services as what they are... plain old objects that really don't care who or what calls them (because you might need to support many different types of interfaces, such as web services, RMI, WCF, WEP, MSMQs, you name it. You might also need to support subtly different interfaces as well, such as CorporateBankManagerService and PersonalBankManagerService (both which call the same bank manager libraries, but have slightly different workflows, API design, etc). So, if the domain is designed correctly, multiple services can be exposed (just as a thin wrapper), and also, running side by side versions isn't a nightmare either.

On the other hand, if your web service *is* your underlying service, well, doing the server side support of multiple versions is just going to get nasty. Perhaps an approach here is to actually have two separate code bases with different namespaces, etc, running side by side on the same box?

On the client side, as long as the new version of the service is there, then porting to it should not normally pose too much of an issue. The catch is that some clients may want a staggered upgrade, where some of the old is called along with some of the new... particularly when there is a chance that a rollback might be required due to an unacceptable bug, design fault, etc discovered in the live new version.

Hosting Multiple Versions of Services

So, how do we support multiple versions of a web service? I like the idea of having web services just as a thin wrapper over the real service... hopefully the underling domain model can support both the old and the new interfaces (with a bit of shoe-horning). Over time, the old version of the web service (well, interface) can be decommissioned, and an even later version can then come into the design/delivery phase.

Other options (in production today) include UDDI facilities for resolving a web service request to a particular running box - the box that serves the correct version of the web service as requested by the client. In a way this is nice... you can technically have exactly the same interfaces between the old and the new version, and the middleware running on the router/instrumentation server will proxy the request to the correct box, based on the IP address of the requesting service (for example). This could also be done through per application/machine configuration too at a guess.

And Now For Something Completely Different...

One other thought that occurred to me was to use web services just as transport mechanism. So, the only thing they publish is the fact that they have a method called "Invoke", along with maybe a parameter list which is a collection of serialised arguments, and the invoke method returns a serialised object which is unmarshalled back into an object at the client side (this is kind of how early versions of RMI worked from memory). This has advantages and disadvantages: on the good side everything is very loosely coupled. There is no concept of interfaces really, you just name a method to be invoked, perhaps a version number, and you get back some data. On the down side, you bypass all type support, schema support, discovery support, security support, etc.

For me, the idea is worth it, as I have never really found all the framework stuff related to web services of any use.

For others, maybe they do, and the idea of reducing web services to a transport mechanism just plain stupid.

No comments:

Post a Comment