This final aritcle in a three part series on understading service-orientation concludes with a discussion of the fundamental elements and design patterns of service-orientation.
Service-oriented architecture (SOA) is an architectural model that aims to meet the goals of service-orientation. This model revolves around a service-orientation design paradigm and can consist of a combination of technologies, products, APIs, supporting infrastructure extensions and various other parts. SOA is defined in terms of principles rather than formal constraints. This means that often there is a trade off when choosing and applying the principles of service-orientation. The principles are not designed to permit formal reasoning about the properties of the architecture.
The main elements of a service-oriented technology architecture are its services, contracts, compositions, and service inventories. Collections of services that are governed under the same processes are brought together into the same service inventory. Services have underlying capabilities that they express through their contracts, and may in turn implement those capabilities by invoking other services in compositions of varying complexity. A composition may be led either by an application-specific composition controller services, or directly by a service consumer to implement the specific business requirements of individual applications.
Services exist as physically independent software programs. Each service is assigned its own functional context and is comprised of a set of capabilities related to this context and its underlying service logic. The set of capabilities are expressed via one or more published technical service contracts.
Most services are created with contexts that are agnostic with respect to any particular business process (Figure 1). These services are capable of being reused by integrating them into multiple service compositions. Some services may be specifically modeled to implement the disposable portion of businesses applications. These application-specific services form compositions with services that implement the reusable portion of their solution logic.
Figure 1 - A service for managing invoices.
Service capabilities are invoked by sending requests to a service endpoint that conform to a supported contract. Several contracts may be supported simultaneously by a service in order to manage contract changes over time or to support different kinds of consumers (Figure 2). A contract may be shared between several services but is generally expected to be unique to a particular service in expressing available capabilities, SLAs, and policy constraints.
Figure 2 - A service contract exposes abstract service capabilities.
A service composition is a coordinated aggregate of services (Figure 3). A composition of services is comparable to a traditional application in that its functional scope is usually associated with the automation of a business process. A composition may be executed or orchestrated either by an application-specific composition controller service, or directly by a service consumer. Reusable logic may, itself, be implemented in the form of a service composition – further eliminating waste and improving business performance.
Figure 3 - Applications and services can be built as compositions in order
to reuse service capabilities.
A service inventory is an independently standardized and governed collection of services within a boundary that represents an enterprise or a meaningful segment of the enterprise (Figure 4).
Figure 4 - Governance is applied at a service inventory level.
SOA Design Patterns
One of the goals of SOA architects is to build up a library of patterns that can be easily applied to solve emerging problems as they arise. Some of the core patterns in support of SOA design principles include:
- Contract Centralization
- Contract Denormalization
- Logic Centralization
- Domain Inventory
- Schema Centralization
- Service Façade
- Service Normalization
- Validation Abstraction
- Three-layer Inventory
The final section in this article series highlights these patterns, which are part of a greater master patterns catalog [REF-1] comprised of 85 patterns that is soon to be expanded with the release of 14 new REST-inspired patterns [REF-2].
The Contract Centralization pattern seeks to reduce coupling between a service consumer implementation and its service provider implementation by requiring a service to be accessed only via its published contract. Consumers that access service capabilities through back-door mechanisms such as shared databases or private APIs introduce implicit coupling that is difficult to manage and control, and that can quickly become unsustainable. Limiting and “centralizing” all access to the service contract avoids implementation coupling, but it can potentially reduce performance. Therefore, an ongoing standardization effort is required to define and evolve related contracts.
Contract Denormalization encourages service designers to expose capabilities at multiple levels of granularity for use by different consumers. One service consumer may want a whole invoice or a list of invoices. Another service consumer may only want to access the customer details of a given invoice. By providing capabilities at multiple levels of granularity, a service contract can reduce the processing and network performance overhead associated with invoking a capability. The cost of denormalization is a larger contract and a greater governance burden in maintaining the service.
Logic Centralization attempts to avoid many of the pitfalls associated with redundant logic implemented across several applications by normalizing the logic in the form of a single normalized service. Redundant logic can lead to increased maintenance overhead on both an ongoing basis and when business requirements change. It can lead to governance and configuration management issues, especially where the redundant logic is “owned” by different groups within an organization.
Eliminating redundancy, by centralizing the logic in a specific service, leads to the improved performance of the organization. Pitfalls can be found initially both when forcing compliance with the principle in an organization that is not aligned to service-orientation, and later if changing business requirements subsequently reveal problems with the original analysis and design of the centralized service.
Domain Inventory is a popular fallback pattern used when the services of an enterprise cannot be successfully incorporated into a single centrally governed service inventory. This pattern suggests that while not ideal, it is OK and in many cases inevitable that different domains, or more precisely, different groups or organizations manage their service inventories separately. Service compositions that cross over multiple service inventories may require a specific integration exercise to resolve any differences between the contract design standards used in each inventor – such as the use of different media types to convey the same kind of information.
By maintaining an explicit inventory of these domains, responsibility for governance can be effectively allocated. The clear existence of multiple service inventories encourages the cooperation and the exchange of ideas between governance boards. Harmony between contract design standards will minimize the integration effort required for cross-inventory compositions, therefore owners of the different design standards should seek to meet regularly to move incrementally towards common standards.
Individual service contracts with express capabilities to process similar documents or types of data can each define their own schema, resulting in mismatched encodings or even mismatched data models for effectively the same information. Schema Centralization suggests the extraction of this type of information into a separate schema inventory that can be centrally controlled, evolved, and managed. The advantages lie in removing the transformation overhead as documents are passed from service to service, and in promoting the end-to-end integrity of the information held within these documents. The overall governance effort associated with the management of the total set of document types is reduced because redundancy is decreased. However, the governance of individual schemas becomes increasingly important as multiple services form dependencies on the same schema definitions.
This pattern is important for harmonization between REST and SOA because it introduces the missing media type architectural element into the service-oriented architectural model. When dealing solely with XML, schema and media type are equivalent concepts. However, the media type term is not limited to XML and can support other data representation and exchange formats.
Services that directly link their contract and message passing logic to core implementation logic can be significantly impacted when their contract is required to change or their implementation evolves. The Service Facade pattern suggests including a software module as part of the implementation of a service that can decouple the core logic from both future contract changes and from multiple simultaneous contract definitions over time.
Service Normalization is related to the Logic Centralization pattern, but views the design of services from a service inventory perspective. A normalized service inventory is designed with a clear blueprint and with careful attention given to service boundaries. Boundaries are defined on a functional basis. New logic that needs to be incorporated into a service inventory is first analyzed for its coherency with the boundaries of existing services. Care is taken to avoid overloading services with unrelated logic, just as care is taken to ensure logic is only expressed once. Normalizing a service inventory maximizes the efficiency of the enterprise, but requires up-front analysis, established governance practices, and a whole-of-inventory perspective to be applied. Normalization makes it easier for consumers to find and correctly use the functionality they need in a consistent, logically partitioned space of services, as well as to ensure that different services are not unnecessarily duplicating functionality.
Initially, it seems useful when defining contracts to impose a range of automatic validity checks on requests to be embedded in the contract as they pass through a service's message processing logic. However, excessive validation constraints can harm the reuse of a service contract over time and may require that new contracts or contract revisions be devised and published more often.
The Validation Abstraction pattern suggests that validation logic be carefully abstracted to avoid including constraints that are likely to change in the future. Applied to the media types within a schema inventory, this pattern takes on special significance. The Validation Abstraction pattern may have to take into consideration the contract evolution requirements of several services and their capabilities. This approach reduces contract churn in an evolving service inventory, but it may result in validity checks becoming more dispersed throughout the service logic, which make it more difficult to maintain and govern.
One approach to ensure reusability of services is codified as the Three-Layer Inventory composite pattern. This common pattern breaks down services into task, entity, and utility layers. Services within these layers conform to the Process Abstraction, Entity Abstraction, and Utility Abstraction patterns, respectively. Task services automate business processes. Entity services manage the bulk of enterprise information in a role similar to traditional database systems. Utility services transform information or perform specific low-level reusable functions.
Task services are likely to be composition controllers for business processes with relatively little reuse potential outside of the context of larger business processes. Entity services and supporting utility services have high reuse potential because the key capabilities expressed in their service contract are application-agnostic information storage, manipulation and management. Separating task services from entity services is one proven technique.
Understanding service-orientation requires an understanding of the target state that we endeavor to achieve when genuinely adopting SOA for the strategic benefit of the business. Service-orientation gives us a solid, field-proven method for achieving this target state, and is supported by a paradigm comprised of industry design principles and further supported by a comprehensive library of design patterns.
[REF-1] SOAPatterns.org website, www.soapatterns.org
[REF-2] “SOA with REST: Principles, Patterns, and Constraints”, Prentice Hall, www.soabooks.com/rest