RPC-style Web Services
Having finally found some time, this post continues my little mini-series on SOA styles. Once again a warning to the experts: expect and please accept some oversimplification and a whole lot of things that seem annoyingly obvious to you — but please do point out any mistakes you might find.
The most pervasive Web services usage pattern is to use them as an interoperable means of doing RPC (Remote Procedure Call) programming. I have a very strong personal opinion about the usefulness of this (read: I think it’s the wrong way to go); but before I point out why I think so, let’s take a look at what it actually is.
A Brief introduction to RPC
The goal of RPC in general is make distributed programming as easy as possible by creating the illusion that an exchange of data over the network that results in some processing (on another machine than the one the application is running on) is nothing more than a special kind of procedure call — one that has the special attribute of being “remote”. Stating the obvious, there is a clear separation of roles in this scenario: the application invoking the procedure (the caller) is called the client, the one executing the procedure is the server. (In more advanced applications, a single program may assume both roles during the course of its execution.) Unsurprisingly, RPC is the foundation of client/server computing [1]. While RPC started out as a way to provide a transparent programming experience for traditional, procedural models, it was quickly followed by technologies that aimed to do the same for object-oriented programming. Examples include DCOM, CORBA, and RMI (for which you basically have to replace procedure with method in the next few paragraphs).
All of these technologies basically work the same way:
- The interface (the collection of procedures used by the client and offered by the server) is specified, either in a language specifically designed for this purpose or directly in the programming language used to implement clients or servers (the latter being the case for Java and C#). 2. A compiler generates stubs and skeletons, i.e. code that represents the remote procedure interface for both client and server. 3. At runtime, the stub forwards requests to the remote location; the skeleton accepts network requests and dispatches them to the implementation. As there is a lot of functionality in place here that is independent from the remote interface, this is done with the help of a library that is linked into the client and server applications, respectively.
RPC-style Web Services
Treating all of the RPC and OO-RPC technologies as equivalent naturally does not do them justice; they differ in aspects such as programming language and operating system independence, the handling of (stateful) conversations, object identity (or lack thereof), data marshaling protocols, interface description language, industry support, performance, transport (in)dependence and many more. Still, I maintain that the philosophy is very similar.
So let’s (finally!) talk about RPC-style Web services [2]. It seems very natural to view Web services as simply the next in a line of ever-improving RPC technologies. In fact, Web services explicitly started out with this goal — one of the most obvious signs of this is the name of SOAP’s ancestor, XML-RPC [3]. Basically, the same development pattern is used, with two distinctions:
- The “IDL” used is the XML-based WSDL,
- the parameters of the remote call are marshalled as XML (and put into a SOAP envelope).
Usually, the protocol used for transporting the marshalled request from client to server (and the response back from server to client) is HTTP; this is less important though, since Web services are supposed to work with lots of different transports [4].
There’s some advantages this approach has over traditional RPC, CORBA, etc.; there’s an (at least) equal amount of disadvantages. I’m not alone in believing that the RPC-style Web services largely fail to exploit the possibilities the underlying technologies offer. But let’s take a look at the advantages first.
Advantage 1: Industry Support
No other RPC technology ever had the same amount of industry support. For years, there was a war between Microsoft’s DCOM and the rest of the world’s CORBA, leading to fragile bridging solutions and frustrated users. Web services and the associated standards — especially XML, SOAP, and WSDL — are almost universally supported. Almost every commercial software vendor has introduced or plans to introduce support for these technologies into their products and tools.
Advantage 2: Interop
While it was entirely possible to get a Microsoft and a Unix application to talk to each other using DCE-RPC or CORBA, today is the first time it’s possible to do so using the respective vendors own technology — with at least some level of interoperability. As long as quite a few rules regarding what data types and programming constructs may be used are followed, it’s possible to get a .NET consumer talk to a WebSphere or WebLogic provider or vice versa.
Advantage 3: Ease of use
RPC is a paradigm most developers are familiar with, and if they aren’t, they can pretty easily “get it” in a few hours. With decent IDE support, there’s no need for the developer to bother with any of the lower-level details such as the network protocols being used [5].
Advantage 4: Composability of add-ons for non-functional aspects
The coolest feature of SOAP — and thus one that is available for RPC-style Web services as well — is its support for extensibility by means of SOAP headers. In contrast to e.g. IIOP, there’s a clearly specified model for passing any sort of contextual information with your method invocations, and XML together with namespaces provides the necessary technology to compose one or more of the multitude of WS-* specifications that exist for many different purposes. Even RPC-centric programming models such as JAX-RPC [6] provide a way to get access to SOAP headers during message processing, and of course toolkits implement many existing specs such as WSS by default.
The Problem
So why do I think RPC-style Web services should not be the way to go? Doesn’t this all sound perfectly reasonable, with a long history of succcesful predecessors to show that this approach works?
In fact I think that in those cases where CORBA or DCOM might have worked just as well as RPC-style Web services, they should probably have been used in the first place. CORBA is a very good and proven technology for use in scenarios where client and server are tighly coupled to each other — usually scenarios where you control both sides. RPC-style Web services are just as tightly-coupled as DCOM or CORBA; they don’t make use of XML’s extensibility, or HTTP’s generic interface (more on that later). Let’s take a closer look.
Self-descriptiveness
One of the nice things about XML is that it carries not only data, but also descriptive information about that data. Consider the following piece of information:
4711 Joe Doe 3 36.5 2005-05-02
What can you do with this? You might take a guess, e.g. that there’s a name somewhere and a date, but this is not going to help you get very far. Clearly, though, you need some information about the structure up front to process this. So take a look at this:
4711 Joe Doe 3 36.5 2005-05-02
-order#-| -- name -------|amnt|-price-|deliverydate
So this might actually be a purchase order, containing an order number, a name of the buyer, an amount, a price, and a delivery date.
Who knows about this? In an RPC scenario, this information is part of the interface description. From this, the stubs and skeletons for client and server are generated. This way, both know what the data looks like, i.e. they expect an order number, than a name, amount, etc.
So what, you ask? The problem is two-fold:
It’s redundant. Here’s what a SOAP message encapsulating the information from above might look like:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <e:Envelope xmlns:d="http://www.w3.org/2001/XMLSchema" xmlns:e="http://schemas.xmlsoap.org/soap/envelope/" xmlns:i="http://www.w3.org/2001/XMLSchema-instance"> <e:Body> <sns:order i:type="sns:Order" xmlns:n0="http://example.org/somenamespace"> <sns:amount i:type="d:int">3</sns:amount> <sns:deliveryDate i:type="d:dateTime">2005-05-01T23:59:50.971+02:00</sns:deliveryDate> <sns:name i:type="d:string">Joe Doe</sns:name> <sns:ordernumber i:type="d:string">4711</sns:ordernumber> <sns:price i:type="d:double">36.5</sns:price> </sns:order> </e:Body> </e:Envelope>
What’s the point of transmitting all of the meta information, such as the names of the attributes here when client and server expect it anyway? Because changes are easier to handle? Wrong; see below.
It’s as tighly coupled as older RPC technologies. A change to the procedure signature will break a communication partner if it’s not updated to the newest interface immediately — which usually requires re-compilation and/or re-linking, the reason being that both sides depend on the complete interface because that’s what the proxies have been generated for.
Basically, there’s simply no point in using XML this way: you might just as well stick with CORBA or DCOM and save some bandwidth.
Conclusion
In the end, RPC-style Web services combine all of the disadvantages of traditional RPC-style solutions, such as tight coupling between client and server, with the performance and bandwidth disadvantages of XML and HTTP [7] without exploiting any of its benefits. Your use case may mean the the simple interoperability benefits alone justify their usage, but there’s no ground-breaking difference to earlier technologies. There’s much more you can do once you accept that there’s a difference to Distributed Objects - and I’ll explore that some more in the next part of this mini-series.
Footnotes
Thanks to Marcel for valuable feedback on an earlier draft.
[1] The first popular RPC solution was introduced by
Sun (Sun RPC, later called ONC RPC) together with NFS, the Network
File System. It featured all the important parts of more modern
incarnations: An interface description with an associated
stub/skeleton generator, marshaling, even a (albeit very simple)
registry (portmap(8)
). I just checked and was pleasantly surprised
that my 2005 Mac OS X Tiger installation still includes rpcgen(1)
,
which even supports transport independence (I don’t think the original
Sun RPC did). The other important RPC standard is DCE RPC, which is
also used as the foundation of Microsoft’s DCOM.
[2] Note that this has got (almost) nothing to do with the document/literal vs. rpc/encoded discussion of SOAP styles and encodings. While it’s hard to do anything but RPC with rpc/encoded, it’s entirely possible to do RPC with doc/lit, and simply switching from rpc/enc to doc/lit buys you exactly nothing in this respect.
[3] In my opinion, XML-RPC will always have an honored place as the worst protocol ever designed.
[4] This is (hopefully) the last time I’ll use “transport” to describe what HTTP is; it’s not a transport, but a transfer protocol. More on that later.
[5] I don’t believe this at all (see below), but it’s an advantage that is pointed out by proponents of this approach.
[6] Despite the name, JAX-RPC 2 (which is currently under development in the JCP as JSR 224) does in fact provide means to build message-style Web services as well. Any JAX-RPC 2 compliant implementation will have to provide the RPC-style programming model as well, though.
[7] In fact I don’t really believe that there’s a notable performance hit when using HTTP and XML in real-world applications, provided they are used the way they are supposed to (document/resource representation exchange). Most often gzip-compressed XML rendering of some object will take less space than a dumb binary representation such as the default Java serialization one.
I don’t agree.. From my point of view, there is one mayor reason why RPC web services are necessary: Microsoft is involved. CORBA is an excellent OO middleware, but without the support of Microft, and the counterpart for DCOM. So the only technology that really interoperates between the Microsoft world and the rest of the world is RPC Web Services.
I don’t agree.. From my point of view, there is one major reason why RPC web services are necessary: Microsoft is involved. CORBA is an excellent OO middleware, but without the support of Microft, and the counterpart for DCOM. So the only technology that really interoperates between the Microsoft world and the rest of the world is RPC Web Services.
I think many Webservice evangelist have failed in explaining when to use Webservices (and when not), and how to achieve loose coupling by SOA and document-oriented approaches.
I know of several projects where - thanks to all that hype around it - Webservices are completely misused, and serve as nothing else than just another intranet / single platform RPC protocol (where IIOP or DCOM would be much better suited).
Webservices are for integration, not for inter-tier distribution!
Arno, I agree - I have seen the occasional use of Web services as an intra-app middleware that made sense, but this is clearly not the scenario the WS-* stack has been built for.
Hi Stefan, I accept the oversimplifications and the annoyingly obvious things (cited 8-) ), but I think there’s one minor error: skeletons are not generated dispatchers (as you describe them), they are instead (at least in my limited experience) actual skeleton code that has to be filled in by the programmer of the service (object, procedure) in order to be sure the interface matches the dispatcher’s expectations based on its mapping rules and the IDL.
To react to comments, I think Enric has in his mind exactly the use case where the benefits of interop outweigh the benefits of using proven and performing older technologies.
“A change to the procedure signature will break a communication partner if it’s not updated to the newest interface immediately “
Thats not quite true. Most WebService implementations allow the server to add or remove parameters, without the client breaking, as long as the client does not need the parameter. Thats different in Corba for example
Best regards Jakob
What you describe is how it should be; sadly it does not reflect the way toolkits actually work. You can find out more here:
http://www.innoq.com/blog/dm/2006/03/changing_interf_1.html