It may come as a surprise to our long-term readers that even after seven years of talking about Web Services and Service-Oriented Architecture (SOA), ZapThink still has something novel and interesting to say about what a Service truly is. But in fact, although we define the term repeatedly for business, technical, and mixed audiences, there are still some subtleties to the definition that underscore the fundamental nature of the Service abstraction, and they also underscore the connection between that abstraction and some of the infrastructure choices Service-oriented architects must make. So, without fear of tripping up on the oxymoron of a concrete abstraction, let’s delve into what ZapThink really means by a Service.
Implementations, Interfaces, and Abstractions
As we discussed in our Subtleties of Service Convergence ZapFlash, the term “Service” is overloaded even within the IT context. But while that ZapFlash differentiated between the Services we speak about in the context of SOA from other IT services, this ZapFlash focuses only on the subtleties of the definition within the SOA context entirely. Even within this relatively narrow context, however, people still often get confused about the level of abstraction of a Service. Basically, there are three levels of abstraction we work on in the context of SOA:
- Service implementation — at this level of abstraction we’re talking about software. A Service implementation is made up of running code. This is where the Service Component Architecture (SCA) lives, as it deals with Service components, which are implementations can consume or provide Services (in the sense of #2 below).
- Service interface — Web Services live at this level, as a Web Services Description Language (WSDL) file provides a contract for the interface, but says nothing about the underlying implementation. Web Services, however, are not the only kind of Service interface, because Service contracts are not always WSDL files. Sometimes Service interfaces are loosely coupled, but many times they’re not.
- Abstracted Service — A representation of a business capability or data that the organization can compose with other such Services to implement business processes. An abstracted Service is typically a business Service, but not necessarily, as there is a role for abstracted IT Services as well. However, all business Services should be abstracted Services. Such business Services are the sorts of Services ZapThink focuses on, as they are the core abstraction that underlies SOA. Abstracted Services should always be loosely coupled, although the specific coupling requirements can vary. Building loosely coupled abstracted Services thus becomes the core technical challenge of implementing SOA.
So far so good — but the real question here is how we make an abstracted Service actually work, when the tools at our disposal are the Service implementations and interfaces and all the infrastructure that goes along with them. It’s one thing to talk about “representations of business capabilities,” and quite another to string your ones and zeroes together into something that actually runs.
Service Contracts, SOA Infrastructure, and Loose Coupling
The first critical point to understanding abstracted Services is to understand that there is typically a many-to-many relationship between Services and Service contracts, as ZapThink explained in our Understanding the Relationships among Services, Contracts, and Policies ZapFlash. Clearly, a Service implementation may support multiple contracts, each of which could correspond to a particular Service interface, for, say, a particular type of consumer. Similarly, there might be several implementations that support a single contract, and hence a single Service interface, for the purposes of scalability or fault tolerance, for instance.
With abstracted Services, however, the relationship becomes what we might call “many-to-many-to-many”: a particular abstracted Service might have several contracts that represent relationships with various consumers, while also representing multiple Service interfaces that themselves might each have one or more Service implementations. This approach might sound overly complex, but it’s the key to loosely coupling the abstracted Service. To illustrate this point, let’s work though an example.
Let’s say we have a Customer Information Service that different lines of business in a large enterprise can consume and compose to provide or update any information about their customers that the lines of business might need. From the business perspective, this is a single business Service that any line of business can use as per the policies set out for that Service. From the IT perspective, however, it makes sense to implement the Customer Information Service as a set of Service interfaces with different Service contracts in order to support the somewhat different needs for customer information that the various lines of business might have. Furthermore, each Service interface may represent several Service implementations that the SOA management infrastructure can leverage as necessary to meet the service levels set out in the contracts for both the abstracted Service as well as the Service interfaces, in addition to the policies that may apply to these Services as well as other Services in production.
In this example, the complexity beneath the Service abstraction is necessary to support the loose coupling of the abstracted Service. For example, the line of business consumers may need different formats for the customer information, or may require different data as part of the response from the Service. To loosely couple such consumers, an intermediary (or set of intermediaries) may perform a transformation that can take the output from any of the Service interfaces and put it into the format the particular consumer requires, as per the contract in place that governs the relationship between that particular consumer and the abstracted Service. Then, either the management infrastructure (or possibly the integration infrastructure) may offer content-based routing of the requests from particular Service interfaces to the underlying implementations, based upon runtime policies in effect at the time.
Furthermore, a Service interface may support several contracts, for example, when one Service interface has multiple bindings. In the case of a Web Service, each WSDL file specifies a binding, so to support more than one, there should be multiple Service contracts for the Service interface. Each binding may then correspond to its own Service implementation, or in the more general case, multiple implementations may support each binding, or one implementation may support multiple bindings.
In any case, loose coupling means more than being able to support different consumers with different needs. It also means building for change. Because we have a governance and management infrastructure in place that enables this many-to-many-to-many relationship among abstracted Services, Service interfaces, and Service implementations, we are able to respond to those changes in a loosely coupled manner as requirements evolve — in other words, without breaking anything.
For example, if one consumer changed its required data format, we could introduce a new contract which might require a new transformation on the intermediary between the Service interface and the abstracted Service, but wouldn’t impact the Service interface directly or any of the Service implementations. Another example might be the need to upgrade or add a new data source to support the Service. Such a change might require a new implementation of one or more Service interfaces. But if the contracts for those interfaces don’t change, then the abstracted Service is unaffected, and neither are the consumers. A third example would be a policy update that would change the content-based routing behavior between the Service interfaces and their implementations. In fact, we see this application of content-based routing as more of a management challenge than an integration task because of this need to support runtime policy changes.
The ZapThink Take
There’s an interesting side-effect of taking this Service-oriented approach to implementing abstracted Services: it becomes difficult to count how many Services you have. Sure, in this example, you have one Customer Information Service from the business perspective, but it actually might have several Service contracts, each of which have several interfaces — and those interfaces may change in number over time. How you count your Services may impact your SOA maturity model, for example, or even your software licensing costs, so this question may be more important than it seems.
But in the final analysis, the most important thing to remember is that the Customer Information abstracted Service is but a single example. In the general case, the architect must select from a variety of SOA infrastructure patterns depending on the specifics of the problem at hand, as we explained in our recent SOA Infrastructure Patterns and the Intermediary Approach ZapFlash. The bottom line is that loose coupling presents architectural challenges that are at the heart of planning and implementing the SOA infrastructure. Building the Service abstraction presents a simplified representation to the business but requires additional efforts under the covers to make that abstraction a concrete reality. This is the work of SOA: implementing and maintaining loosely coupled business Services that are at the core of any successful SOA implementation.