Within the world of SOA, services are the building blocks and at the lowest level of the stack. They are the functional primitives of SOA. However, most enterprises are so focused on the architecture that the underlying services get very little attention. In order to create and maintain a healthy SOA, the process of designing, building, and testing services needs to improve. So, what are the best practices for services?
What's core to the problem is that we have a tendency to consider services as simple building blocks, something that will always be there, always using a good design, relevant patterns, and always in good operational condition. That's just not always the case. Indeed, services are the building blocks of SOA, and like building blocks of a house or a building, the quality will define the value of the finished product, in this case, the SOA implementation itself. Thus, spending time on what services do, how to define them, how to design them, and how to build them is a good investment in time, and something that's missing within many architectures.
Clarify these services issues at the outset of a SOA project to build better blocks:
First, services don't need to be Web services. ZapThink has been very clear about this point. However, this is a confusing statement for those of you who have been absorbing the hype. The fact is, you can build a SOA without Web services, opting for more traditional approaches such as transactions, distributed objects, or custom software systems. Indeed, when considering "special needs architectures," such as those requiring high performance, the use of Web services are clearly contraindicated.
Keep in mind as well that the service contract language is more than just WSDL. So such services (or more precisely, service interfaces) are similar to Web services, but have more information in their contracts than WSDL can provide.
Second, services produce behavior and data, not just data. Most people who design, create, and/or expose services think of them as data providers, and indeed they are in most instances. You invoke the service, and it produces data in the context of a structure, and consumed into another system. However, while many services are very data-oriented, services are able to provide behavior as well, or, the ability to do something around the containment of the data, or perhaps provide behavior without data at all.
Third, services are not applications, and you shouldn't design them like applications. As you'll see below, services have their own specific design orientation. The way you define and design a service is very different than what many consider traditional application design. You're building a much smaller system that exists within many systems, and thus you must pay special attention to interoperability, granularity, core purpose, and testing approaches.
Services are not complete applications or systems. They are a small part of an application. Nor are they subsystems; they are small parts of subsystems as well. Indeed, services are more analogous to traditional application functions in terms of design and how you leverage them to form solutions, fine- or course-grained. Knowing that, we have a better basis of understanding when approaching the service design problem.
Finally, each service has a specific purpose, and they are not complex or naturally dependent upon other services. Thus, they are easily abstracted into composite applications, in essence, leveraging these services as if they are functions local to the composite. This is where exposed services have a tendency to fall down. Since they were not designed, but abstracted, they typically have far too many dependencies to be as useful as services that were designed correctly from scratch. That's the tradeoff. Services should exist with a high degree of autonomy. They should execute without dependencies, if at all possible. This allows you to leverage the service by itself, and design the service with this in mind no matter how course- or fine-grained the service is.
It's in the design
So, how do you design a service? It's important to follow a few basic principles. While following these principles does not insure success, it will clearly send you down the right path. First and foremost, you should often design services for reuse. Services become a part of any number of other applications, and thus must be designed to provide behavior and information, but not be application specific. This approach is difficult for many developers since custom one-off software is what they've been doing for most of their careers. Thus, the patterns must be applicable to more than a single problem domain or application, meaning you must have use for your reusable service. Else, the exercise is in vain. However, not all service can or should be reusable, thus the criteria of reuse should be selective.
In addition, services have to be designed for heterogeneity. Build services so that there are no calls to native interfaces or platforms. Remember that a service, say, one built on Linux, may be leveraged by applications on Windows, Macs, and even mainframes. Those who leverage your service should do so without regard for how it was created, and should be completely platform independent.
Among other benefits, abstraction allows access to services from multiple, simultaneous consumers; hiding technology details from the service developer. The use of abstraction is required to get around the many protocols, data access layers, and even security mechanisms that may be in place, thus hiding these very different technologies behind a layer that can emulate a single layer of abstraction. Also, when we build or design services we need to account for aggregation. Many services will become parts of other services. Thus they become composite services that are leveraged by an application, and you must consider that in their design. For instance, a customer validation service may be part of a customer processing service, which is part of the inventory control systems. Aggregations are clusters of services bound together to create a solution.
Services are not applications and should have limited scope, as we discussed above. In other words, they do simple things such as check inventory or calculate reorder points. If your needs are more complex, you simply write more services and not overload a single service with too much functionality. Services with too much functionality are considered heavy, and are difficult to reuse since you may deploy a service where you're only leveraging ten percent or less of its functions.
So, now that we understand the common design patterns we must follow, the question is: How do you design a service? Also, what tools are available? There are certain steps architects and developers can follow. Here are some suggestions, assuming new service design.
- You need to define the purpose of the service. What will the service do, and who are the intended user; human, application, and / or other services?
- You need to determine the information to be bound to the service, including schemas and other metadata. You must understand how the service leverages information, and what functions require what data.
- You need to determine the functions (methods) encapsulated inside the service; in other words, the behaviors you would like to expose. It's also at this step where we define each function, including how the function breaks down using a traditional functional decomposition chart.
- You need to define any interfaces into the service, both machine and human. This means we need to determine how the service will interact with the calling applications, and through what mechanisms.
- You need to define how to test the service, using the suggestions above. Testing is an important but often neglected step where you define how those who leverage the service will test the service within the context of their usage pattern. You need to define test information, service invocation, and validity of results.
What's core to the success of SOA is a clear approach to service design, development, and testing. At the end of the day, it's good old-fashioned discipline that comes into play here, more so than new technology, tools, and programming tricks. That's not what people want to hear in the context of the deafening hype, but that's the reality.
The ZapThink take
The truth of the matter is that services are a new challenge for developers, and they bring their own sets of requirements. In many ways it's as much of a shift in thinking as was the movement from structured analysis, design, and development to object-oriented analysis, design, and development. We all know how long that took, and in many respects it's still going on today.
What we'll see in the short term is what you expect to see with any new approach -- poorly designed, developed, and tested services that bring high cost and lost productivity. Thus, the failures will lead to rethinking, relearning, and retooling to get service design right. Count on large expenditures on training, tools, and testing infrastructure over the next 3 to 6 years. Also, count on some pushback on the whole SOA concept as people understand that they are dependent on the underlying services, and thus the architecture will suffer as well as developers move along this learning curve.
You must also pay attention to the process of exposing existing legacy systems as collections of services. While it appears that you'll have to take the interfaces as they are deployed, now exposed as services, there is actually a lot the developers can do to design abstracted services that better serve the architecture. While many people believe that tools and technologies that turn APIs or transactions directly into services are the way to go, most will find that services built using those principles provide very little value in the long run.
SOA is indeed architecture, but it's based on the proper design, development, and testing of services. These services provide what's core to SOA, and the discipline and process that software engineers put around this effort should be significant. Changes to SOA services design, development and testing need to be made and understood right now.