Contract-First or Code-First Design - Part 5
(Editor’s note: This is the fifth 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. The conversation has just moved to Adrian’s fourth-of-four reasons for preferring contract-first and WSDL.)
Adrian: Last reason: Code-first doesn’t work in a multi-lingual development organization.
Ted: What, you mean not everybody uses Java? Hush, or Sun will hear you!
Adrian: I think it’s fair to state that it’s the exception, rather than the rule, for an organization to use just one language, right? Far more often, many organizations will require a blend a number of different languages, for a lot of different and valid reasons. Some languages (e.g. C#, Java) provide good support for code-first approaches; while others (e.g. C++) do not. It seems inappropriate to place interface specification (and consequently, implementation) in the hands of just one part of the organization (those that use a preferred language). Also, it impairs your ability to redeploy new implementations of services in different languages later on: the new language may generate a different interface contract.
Ted: Well, I could take that argument and run with it further, suggesting that it’s unfair to place interface specification in the hands of somebody speaking a language (e.g. XML) that doesn’t cleanly map to any of the implementation languages, and that you’re basically just exacerbating the problem further, not simplifying anything. And while I might challenge the idea that C++ isn’t a good language for doing code-first approaches, I won’t, since that’s not something I have particular facts on at the moment.
Adrian: You’re willing to accept my contention that there aren’t?
Ted: Nope, because Microsoft’s C++/CLI implementation in Visual Studio 2005, or maybe even an earlier version of ATL Server, may have this covered. I don’t know, I haven’t looked in a while. I am willing to accept that the idea of code-first through C++ isn’t as well-explored as C# or Java, certainly.
Adrian: What about Ruby?
Ted: I think applying the traditional C#/Java approach to Web services to Ruby is missing a large point of Ruby’s mojo, but that’s starting to get off the point entirely. Can I punt on that one for now?
Ted: So that’s your final word on the subject?
Adrian: No, if I had to sum it all up, I’d say it this way: there are some things you want from your service contracts. You want to be able to define a service-wide data model, reusing types across services. You want to be able to organise WSDL and XSD artifacts in separate files to increase reuse. You want to be able to apply appropriate versioning schemes to these contracts and type definitions. You want your services to separate interface from implementation, so that changes in the back-end do not render existing service consumers obsolete overnight. If you’re serious about service oriented architecture in the enterprise, then you want all of these things, and code-first approaches to contract generation just don’t deliver.
Ted: And now the prosecution rests?
Adrian: I thought I was the defense!
Ted: Here’s the thing: I don’t think anybody who’s ever had to use a service defined entirely code-first is going to buy the purist code-first argument. The idea of “just flip a switch and suddenly all your POJOs become Web services” I think is finally dying, and I, for one, suggest that we all just let it rot in the grave for all eternity. But I’m suggesting instead that we can define services using code-first approaches that define a contract, ultimately expressed in WSDL for lack of anything better in that realm, that’s far easier for developers to work with and develop against. This means that developers have to be aware of how the code constructs they’re using and what consuming those code constructs looks like on “the other side”, whether we’re talking about IDL or WSDL. That’s what I mean by “code-first/contract-aware”.
Adrian: What about the rest?
Ted: Well, I hate to say this, but I think you’re wrong on a couple of points: I don’t want to focus on reuse across service definitions, because I don’t want my services tightly coupled to one another for fear of the ripple effect when I have to change something in those reused definitions. I don’t want to reuse types across services for the same reason. That’s appropriate for within a single programming language, but even there we as an industry haven’t exactly had a stellar record about achieving reuse successfully within a single language, much less across them. Versioning is another issue that deserves its own debate, but frankly I’m skeptical of the versioning schemes we’ve tried in prior technologies like CORBA and COM/DCOM, and would prefer just taking a more “open” and loosely- coupled approach, such as using open content model schemas or forgoing the idea of a single schema at all.
Frankly, I think if you’re serious about trying to separate implementation from interface, then you have to consider the idea that XML is just a data representation, and not a type system of its own, and that therefore you cannot try to force XML into a “type system” through XSD. And I think the argument about interface and implementation being separated from one another is a red herring–I’ve rarely run into situations where we wanted to have distinctly different implementations to the same interface in a distributed scenario. When dealing with CORBA and RMI and .NET Remoting, that was necessary to facilitate the compiler’s type-checking of the arguments passed in to the remote call, but now we’re in a different space, where we don’t want the tight coupling that the old CORBA/DCOM/RMI-based approaches brought us. If we’re serious about trying to build services that will stand the test of time, we need to take a step away from the old model of object RPC, and go back to the world’s original loosely-coupled technology, that of message-passing.