Solving the Service Granularity Challenge
For us analysts that have been covering the markets around XML, Web Services, and Service Orientation it certainly is heartening to see that our audience of end users, vendors, and consulting firms are now asking some of the more complex and deeper questions around how to do architecture right. It seems that we’ve finally crossed the chasm and architects in particular now have a pretty good idea what SOA is and why they need it. Rather than trying to redefine what SOA is and what is means to the business, people are focusing on the more important issue of how to do SOA right. In that vein, some of our most recent conversations have centered on how to go about building the “right” Services. A key part of answering this question is making sure that we build Services at the right level of granularity.
Granularity is a relative measure of how broad a required piece of functionality must be in order to address the need at hand. Fine-grained Services address small units of functionality or exchange small amounts of data. Consequently, to build complex business processes, companies would have to orchestrate large numbers of such Services to effectively automate the process — a difficult, often Herculean task. Coarse-grained Services, however, encapsulate larger chunks of capability within a single abstracted interface, reducing the number of Service requests necessary to accomplish a task, but on the downside, they might return excessive quantities of data, or it might be difficult to change them to meet new requirements. As a result, an architect must craft the right balance of fine-grained and coarse-grained Services to meet the ongoing needs of the business. This balance, of course, is part of the art of Service-Oriented Architecture.
What Constitutes a Well-Defined Service?
The first topic to consider when trying to understand how to craft Services of the right granularity is to understand how well-defined a Service interface must be. Some might think that all you need are the right standards and voila, you’ll have well-defined Service interfaces. In essence, one can say that a well-defined interface is something that a computer can understand. However, it doesn’t matter which specific standards you use to define a Service interface, as long as it provides enough information for a loosely-coupled exchange. In an SOA, we do prefer standards-based exchanges over non-standard ones, and it seems that a good part of the WS-* stack (in particular, WSDL, XML Schema, WS-Security, WS-Policy, and possibly BPEL or WS-CDL) is well on its way to becoming widely accepted. While it is good to have as much contract metadata in machine-processable standards, simply having the specifications available for the user does not give any clues on how to define the Service interfaces and address the granularity challenge at hand. Sure, it is important for a computer to be able to understand a given Service, but that doesn’t make that Service valuable. Indeed, other forms of architecture have also depended on standards-based interfaces and have not produced the sort of loosely-coupled Services we so desire. At this point, we must take off our developer hats and put our architect one on.
In our recent ZapFlash entitled What Belongs in a Service Contract, we discussed the fact that a Service is not a Service unless it is defined using a metadata-encoded contract. The contract must contain two key elements: functional and non-functional information that specify the expectations of both the Service consumer and provider. In that case, at the very least, a Service contract must provide unambiguous information about what the Service does. In other words, a Service should clearly say what it means and mean what it says. Users shouldn’t be left scratching their heads as to what will happen when they provide the required input. So, a better argument for the well-defined Service question is that a Service is well-defined not only if a computer can understand it, but also if it is unambiguous as to what the Service will provide. Basically, a human can also understand the Service contract without having to consult additional resources or information.
Now, this requirement for unambiguousness is somewhat opposed to the desire for loose-coupling. By somewhat, we mean that an architect can take this desire for clarity to the extreme and expose the inner workings of the Service, or perhaps provide the exact details of how a business process is composed. However, for loose coupling to work, we’d like to know as little as possible about how the Service works or about the process composition in order to achieve the task. Even then, we may have what we might call operational loose coupling in conjunction with semantic tight coupling. In other words, we need knowledge both of what the Service will do as well as how it will communicate to make it useful. Thus, one of the first real challenges is to build Service contract metadata that specifies enough, but not too much.
Focusing on Reuse
We still have not answered the question as to how to determine the level of Service granularity, since after all, we can build fine-grained, well-defined Services and coarse-grained, well-defined Services. It’s vital to understand whether or not a particular Service is single-use or multiple-use. You could say that the best Services are the most reusable ones, which is true, up to a point. After all, having several redundant, fine-grained Services leads to tremendous overhead and inefficiency. Clearly having a small collection of coarser-grained Services that are usable in multiple scenarios is a better option. However, developers could theoretically take this principle to an extreme and try to build a single Service called, say, “DoSomething” that can meet every single need. DoSomething would have a simple interface that would support some arbitrary Service function requirement, and it would produce a corresponding Service result.
The problem with this DoSomething Service is quite obvious to anybody who has ever tried to implement such a thing. In essence, DoSomething is no longer a usable Service at all, since we’ve basically just passed the buck. Instead of the Service itself determining its own semantics, we’ve just shuffled that determination to some lower-level piece of code. In essence, we’ve treated SOA as just some sort of routing protocol or messaging system with no inherent functional capabilities. Such Services, however, are clearly unable to satisfy the requirements of SOA.
So, if general-purpose Services are a red herring, what about single-purpose Services? The answer to this question is a bit of a draw. Some single-purpose Services, even though they might be very fine-grained and accomplish only one particular task, might be exceptionally reusable. That is to say, architects might be able to compose such Services into many different process scenarios. In contrast, domain-specific Services might only be applicable in certain scenarios, but the fact that they are specific to a particular problem or set of problems is what makes them useful to the business. And that is where we get our first clue for trying to solve the Service granularity issue: focus not on an individual Service, but rather on overall business processes and how Services might meet the needs of multiple processes in the business. The more a company can leverage a Service for multiple processes, the more useful it is. Correspondingly, if it’s impossible to leverage a Service within several different processes, then you should wonder whether or not it is at the proper level of granularity.
The Role of Process Decomposition
A Service is not really a technology concept. It is merely an abstract representation of value the business wants to extract from its technology. As such, we should focus on defining Services from the business point of view — that is to say, the business process point of view, since business processes fundamentally define the business.
One approach to specifying the right Services is to start with some business process and decompose it into increasingly smaller subprocesses until you can go no further. The resulting subprocesses then become candidate Services for implementation. The more processes that a company decomposes in this way, the more they can see commonality across their subprocesses and thus have a chance at building an appropriate set of reusable Services.
However, this top-down process decomposition approach has a critical flaw in that we might end up defining Services that are impossible or impractical to implement. Therefore, it’s important to simultaneously go through an exercise of taking existing business logic, albeit ingrained in code rather than metadata, and exposing it as Services which themselves become candidate Services that specify not the overall business process, but rather the mechanism for implementing the process. This exercise should yield two categories of Services: business functionality Services that are reusable across multiple processes, and fine-grained utility Services that can provide value to various Services across the organization.
The ZapThink Take
Companies going through this Service definition exercise should make sure not to fall into the common, yet fatal trap of thinking that once they’ve defined their Services, they are done. SOA, by its nature, demands constant evolution. Even if the Services a company develops are perfect for the business at one time, the business will continue to undergo constant change, requiring new Services as well as new compositions of Services. What might have been the right level of granularity for a Service on day one might be inappropriate just a few weeks later.
As a result, it makes no sense to try to cast the level of granularity for a Service in concrete. Companies must approach Service design iteratively, building well-defined Service interfaces at a range of granularities and then establishing and using those Services that are appropriate at the time. Service-oriented architects will spend a good amount of their time tweaking Service interfaces such that they realize the optimal combination of fine vs. coarse-grained and single-purpose vs. multiple-use given the amount of knowledge they have about the business at that point in time.
As a result, developers and architects should resist the urge to “get the right Services.” Indeed, getting it right doesn’t even matter, since what’s right today will surely be wrong tomorrow. After all, building Services is not the goal of SOA — it’s building an architecture that allows businesses to continuously evolve their set of useful Services that the business wants and can leverage despite ongoing change. Building such useful Services is all about striking the balance between general-purpose and domain-specific Services as well as between overly-defined and overly-ambiguous Service interfaces. There’s no cut and dried answer to what those Services should be for any particular company, but there certainly are good approaches to making those Services a reality. Spurring and encouraging this ongoing debate in the industry will only serve to make SOA more useful to the business, and thus worth continuing to write and speak about.