How to Think Loosely Coupled
Now that Service-Oriented Architectures (SOAs) have found their way into the hype machines of end-users, vendors, and press alike, it’s worthwhile to examine whether or not corporate developers and enterprise architects are really getting and implementing the core concepts of SOA, or are simply “putting lipstick on the pig” — adding talk of SOA to their discussions without really understanding it While it is certainly the case that a number of notable companies are implementing truly loosely coupled, coarse-grained Services that solve the integration and reusability problems of yesteryear, it is also the case that many vendors and developers have simply not learned how different SOAs are from other traditional forms of distributed computing. In particular, it seems that despite the capabilities of Web Services-based SOAs, many developers have yet to figure out how to achieve loose coupling. In this ZapFlash, we’ll point out a couple of common misunderstandings developers, architects, and vendors alike face when trying to think in terms of loosely-coupled Services.
Getting away from the One Component / One WSDL Mentality
One of the wonderful things about SOAs is that they have contracted interfaces. A software contract is a document that specifies what a particular application or functional component expects of consumers and what those consuming applications can expect of it. In Web Services-based SOAs, the contract is defined by a WSDL document, which stipulates, in XML format, how Service consumers can bind to a Service producer. The key here is that the Web Services-based contract is defined in a machine and platform-independent way, giving us a stepping stone towards standards-based interoperability, and potentially, but not necessarily, loose coupling.
When developers are first presented with the idea of a WSDL document, the first thing they do is create a single WSDL file that maps to a specific component they have created. Of course, these developers quickly realize that they have not in fact solved any of their loose coupling issues because changes to the component require changes to the WSDL file and vice-versa.
The cardinal sin induced in this case is the notion that each component must have only one WSDL description, or that a WSDL file can only map to a single component. In a truly loosely coupled SOA, the opposite is far more desirable. In such an SOA, a single piece of application functionality can map to many different WSDL documents — each specifying how a particular group of consumers can access that functionality. Conversely, a single WSDL document can map to a whole set of components, shielding the Service consumer from knowing how the contract is being implemented. By applying a “many-to-many” philosophy around WSDL document creation, loose coupling can in fact not only be enabled, but enforced through the contract abstraction.
Stop Static Binding!
SOAs are often visually described as a three-legged triangle in which there are three participants: the Service producer, the Service consumer, and the Service registry. Yet, early adopters often make the mistake of forgetting about the third corner of the SOA triangle: namely the dynamic binding aspect.
For those that are most familiar with Remote Procedure Call (RPC) style distributed computing, Web Services are simply a better way for Service consumers to talk to Service producers. However, this standards-based RPC-style invocation of Web Services is nothing like the loosely-coupled style required of SOAs. In an SOA, a Service consumer should never be coded to speak directly to a particular Service producer. For one thing, any change to the Service producer would require commensurate changes to all consumers if they communicated in such a direct fashion, making them tightly coupled.
More importantly, however, the RPC-style approach loses the real Service-oriented nature of a Service. A Service is meant to be an independent entity that users can compose into business processes as they desire. In an SOA, it’s the Service consumer, rather than the Service producer, that defines how an application behaves. Yet, loose coupling mandates that Service consumers and Service producers be independently created and controlled. In addition, we mentioned above that any given Service might have multiple contracts that define how a consumer can bind to it to gain required functionality. Finally, policies are increasingly controlling Services, where those policies define specific security, process, semantic, and governance constraints by which consumers can bind to specific Service producers.
Given the highly variable nature of the Services being exposed, Service consumers depend on registries in order to find and bind to the appropriate policy-controlled Service, and to insure that the composed application continues to operate in the face of continuous Service change. Dynamic discovery and the associated routing enables the association of Service requests with the appropriate Services at runtime — regardless of any API-specific characteristics of the underlying components. As a result, it is clear to see that in a truly loosely-coupled SOA world, it is as impossible to operate without a registry as it is to operate in a global Internet without a DNS.
The ZapThink Take
For those developers or former developers reading this article, remember the first time you learned object-oriented programming? Maybe your first exposure to a programming language was Basic or COBOL, or maybe even assembly language or LISP. Whatever the language was, if you were only familiar with procedural languages, your first object-oriented language experience was fraught with many a headache. The problem wasn’t learning the programming language. Rather, the problem was learning how to think object-oriented. While it might have taken you only a few months to learn the vagaries of C++, Smalltalk, or Java, it took years for you to finally learn how to build an object that was truly modular, inheritable, and exhibited the rest of the positive traits that many gurus spent years admonishing you to include in your code.
In much the same way, thinking in a loosely-coupled, Service-oriented way will take a reorganization of brain cells and a change in the thought process. Sure, learning SOAP and WSDL or implementing libraries to expose application functionality as Services is fairly simple — if not trivial. However, it’s figuring out which Services to expose at what level of granularity and how to make it all work in a truly loosely-coupled fashion that will take years to master.
There are a few more points to consider. First, ZapThink wouldn’t go so far as to say that the Services in an SOA “must” be coarse grained, loosely coupled, and asynchronous. That’s not a universal rule — there must be an allowance for a range of exceptions. For example, synchronous behavior can be thought of as a special case of asynchronous, and no one would say that synchronous behavior shouldn’t be supported.
However, in order to really achieve the desired effects of an SOA — namely IT capabilities that are capable of meeting the needs of continuously evolving business requirements, and achieve the constantly sought-after goal of reuse, developers must build, and businesses must consume, Services that are truly loosely-coupled, coarse-grained, and often, asynchronous.