Contract-First or Code-First Design - Part 3

(Editor’s note: This is the third of a multi-part series of transcriptions of a conversation between Adrian Trenaman and Ted Neward on Web services in general and code-first/contract-first practices in particular, secretly recorded by an undercover agent of TheServerSide. Readers are reminded that before the discussion was sidetracked by rants against “clueless idiot programmers”, Adrian was still iterating his four reasons for using WSDL.)

Adrian: Fair enough. OK, second reason: Implementation code typically changes at a faster rate than the interface. As all agile developers know, service implementation code can change frequently through continuous refactoring, improvements and general maintenance. The beauty of a service-oriented approach is the ability to separate concerns: the user of the service should not be affected by downstream changes of implementation. Now, code is much more malleable than a formal contract specified in WSDL/XSD: its highly likely that in the course of general maintenance, the Java service interface may change, leading to an implicit change in WSDL contract and consequent on-the-wire interoperability issues with existing clients. Remember: it’s not just changes in the service endpoint interface that can lead to a compatibility issue: a change in any class or interface used by the service interface may lead to an incompatibility issue.

To demonstrate, consider the following service interface for an address book. Clearly, if we change the AddressBook interface (by changing an operation signature, or changing the class name) then a freshly generated contract will be incompatible with existing clients.

(Editor’s note: Our agent fortunately was also equipped with a digital camera, and at great risk to self–disguised as a ceiling fan–managed to capture the following code sample scribbled on a cocktail napkin.)

class AddressBook {

void addContact(Contact c) {

}

};

What’s not so obvious is what happens when we modify a class elsewhere in the system called Address, replacing an array of strings for the address line information with two strings, AddressLine1 and AddressLine1. Did I tell you that the Contact class contains an Address? It’s not obvious from the above class information, but that simple change will completely change the types used in the auto generated contract, and thus create an on-the-wire collision. By adopting a WSDL first approach, you can define all interfaces (like AddressBook) and data classes (like Contact and Address) with appropriate version information in a controlled way. That way, you’re guaranteed that clients and services using the same version of the interface will always interoperate.

Ted: Sure, but again, you’re arguing over something that’s not an issue of technology, but of discipline and design. Refactoring and services are an area that still have yet to be seriously explored in any depth, but frankly, based on experience with CORBA, COM/DCOM, RMI, EJB, and .NET Remoting, any attempts to refactor across a remoting boundary is a dangerous thing because of the tightly- coupled nature of a WSDL-based contract. It’s the Myth of the Single Source of Truth, and it’s a dangerous thing in an environment or technology that’s intended to bridge two independent systems together, like Web services are supposed to do. On top of which, you’re also letting your CORBA biases shine through here, based on your belief in the One True Schema.

Adrian: The what?

Ted: The Single Source of Truth and the One True Schema are correlated ideas, but basically they both stem from the desire of developers to try and create a single definition of the types that will be used by both sides in a connected system, and that’s a really hard thing to come up with.

Adrian: How hard can it be? You just sit down together, and–

Ted: Exactly! You have to get both sides together, sit down around a table, and argue out exactly the interface used. That might be possible for the first release, but from now on, both sides are tightly coupled to one another forevermore. Neither side can change the definition of Contract, AddressBook, Address, or any other entity defined in your WSDL (or your code-first interface, for that matter) without requiring every consumer of that interface to change as well, and all on the same schedule. That of course presumes that all of the clients using your service all agree on the definition of what a “Contact” or “Address” is, too, which is a problem anyone who’s ever tried to do one of those “database consolidation” projects knows pretty well. After all, in a successful Web service implementation you’re not going to have just one client of your service, which means the more people using your service, the more you have to politically navigate the very real world of “my notion of a Contact is different from your notion of a Contact”, which by the way is also not limited to discussions across companies, but across departments inside the same company, too.

This kind of tight coupling burns you in other ways, like when the service finally is revised, everybody who uses it needs to immediately drop everything and adjust to the change or face being broken when that revised service goes live in production. Look at it this way: if you’re a developer working for a large (or small) firm, and you’re told right in the middle of your project (one which is unrelated to the Web services project you did last month) that you need to drop everything and regenerate proxies, re-test the code using those proxies and maybe even have to rewrite code using those proxies that won’t compile anymore, how happy are you going to be? At the end of the day, any tightly-coupled relationship between systems is going to act as a barrier to refactoring, whether it’s described in WSDL or in code, either way.

Adrian: But you just keep the old service running, and let clients who want the new service contact the new one on a separate URL.

Ted: And you’re going to keep the redundant code between the two services where? Look, for a small number of clients and a small number of services, you can make your approach work, but that’s not going to scale up over time. This was basically the same approach that Microsoft took with COM, and that’s why COM now has such interfaces as IPersist, IPersist2, IPersistEx, IPersist3, IPersistEx2, IPersistExEx, and so on. I keep waiting for IPersistExExEx to come out, so I know which interface to use to store my porn, but for some reason they haven’t released that one yet.

(Editor’s note: There was a slight pause as the London Morality Police descended on the bar and tried to arrest Ted for his use of the word “porn” in a public location. Only timely intervention of our agent–cleverly disguised as an American CIA agent–kept the conversation going.)

Read Part 2 — Read Part 4