This article is a modest collection of excerpts from three books [REF-1, 2, 3] in the Prentice Hall Service-Oriented Computing Series, combined to provide a concise overview of what lies at the very core of the service-orientation paradigm and the service-oriented architectural model: the identification and aggregation of agnostic logic into reusable and composable units. These units represent the foundational moving parts that collectively define and enable service-oriented solutions. Understanding how they are realized and then subsequently (and repeatedly) utilized is the most essential requirement to successfully benefiting from anything that SOA has to offer. The upcoming sections explore this topic area by focusing on the Service Reusability and Service Composability principles, as they are applied to the early stages of service modeling and design, and how they are further supported by key design patterns.
Breaking Down the Problem: Service Reusability and the Separation of Concerns
The SOA design patterns catalog establishes a set of foundational service patterns responsible for identifying and defining the scope of functional service contexts and boundaries, as well as service capabilities. As shown in Figure 1, the majority of these patterns pertain and lead to the definition of agnostic logic suitable for reuse and therefore subject to the Service Reusability principle.
Figure 1 – These foundational service patterns can be combined to establish a primitive service modeling process that results in the definition of service candidates and service capability candidates.
As explained in the upcoming sections, the combined application of these patterns essentially carries out the separation of concerns in support of the service-orientation paradigm.
The separation of concerns theory is based on an established software engineering principle that promotes the decomposition of a larger problem into smaller problems (called concerns) for which corresponding units of solution logic can be built. The rationale is that a larger problem (the execution of a business process, for example) can be more easily and effectively solved when separated into smaller parts. Each unit of solution logic that is built exists as a separate body of logic responsible for solving one or more of the identified, smaller concerns (Figure 2). This design approach forms the basis for distributed computing and is essentially embodied by the Functional Decomposition pattern.
Figure 2 – On its own, Functional Decomposition results in the decomposition of the larger problem into smaller problems. The actual definition of solution logic units occurs through the application of subsequent patterns.
When assessing the individual units of solution logic that are required to solve a larger problem (carry out a business process), we may realize that only a subset of the logic is suitable for encapsulation within services. This identification of service logic is accomplished via the application of the Service Encapsulation pattern (Figure 3).
Figure 3 – Some of the decomposed solution logic is identified as being not suitable for service encapsulation. The highlighted blocks represent logic to which this pattern was successfully applied.
After the initial decomposition of solution logic we will typically end up with a series of solution logic units that correspond to specific concerns. Some of this logic may be capable of solving other concerns, but by grouping single-purpose and multi-purpose logic together, we are unable to realize any potential reuse. By identifying what parts of this logic are not specific to known concerns, we are able to separate and reorganize the appropriate logic into a set of agnostic contexts (Figure 4).
Figure 4 – Decomposed units of solution logic will naturally be designed to solve concerns specific to a single, larger problem. Units 1, 3, and 6 represent logic that contains multi-purpose functionality trapped within a single-purpose (single concern) context. The application of this pattern results in a subset of the solution logic being further decomposed and then distributed into services with specific agnostic contexts.
Within each agnostic service context, the logic is further organized into a set of agnostic service capabilities. It is, in fact, the service capabilities that address individual concerns. Because they are agnostic, the capabilities shaped by this pattern are multi-purpose and can be reused to solve multiple concerns (Figure 5).
Figure 5 – A set of agnostic service capabilities is defined, each capable of
solving a common concern.
The application of the Utility Abstraction pattern results in the separation of common cross-cutting functionality that is neither specific to a business process nor a business entity. This establishes a specialized agnostic functional context limited to utility logic. The resulting type of service is referred to as a utility service and the repeated application of this pattern within a service inventory results in the creation of a logical utility layer (Figure 6).
Figure 6 – The application of Utility Abstraction restricts the agnostic context of the
service to utility logic.
Every organization has business entities that represent key artifacts relevant to how operational activities are carried out. The application of Entity Abstraction shapes the functional context of a service so that it is limited to logic that pertains to one or more related business entities. As with Utility Abstraction, the repeated application of this pattern establishes its own logical service layer (Figure 7).
Figure 7 – The application of Entity Abstraction restricts the agnostic context of the service
to entity logic.
The Inventory Analysis Cycle
When viewing the preceding set of patterns, one can see there are steps within a service-oriented analysis process. It is important to realize that this process (and its steps) is preferably carried out iteratively, as part of a cycle that identifies, defines, and also refines agnostic service contexts and agnostic capabilities.
This is commonly accomplished by decomposing a set of business processes that belong to a given domain within the IT enterprise. This domain represents the boundary of a planned service inventory. By iterating through a separate analysis and functional decomposition of each business process, agnostic service candidates and their capabilities can be continually refined until they reach a state where their reuse potential has been fully determined before they are physically designed and developed. This takes the guesswork out of applying the Service Reusability principle in that the reuse of each service is pre-determined based on the current state of the business. Future business change is naturally accommodated by leveraging the inherent characteristics and flexibility established by this and other principles.
Each of these service candidates is added to a collection that eventually results in a blueprint of the service inventory, as illustrated in Figure 8. The depicted analysis cycle is one of several ways to incorporate service-oriented analysis within an SOA methodology. A key consideration here is that the extent to which the cycle needs to be iterated is directly related to the scope of the planned service inventory. When applying Domain Inventory within an IT enterprise, multiple service inventories can co-exist and can be independently planned and defined with different approaches, each iterating through their own cycles within manageable boundaries.
Figure 8 – The cycle begins with the definition of business models (such as entity relationship models and business process definitions) and takes practical considerations into account via a step dedicated to the on-going definition of the required technology architecture that corresponds to the scope of the planned service inventory. As service candidates are produced or refined through repeated iterations of the service-oriented analysis (and service modeling) phase, required business models are defined or updated, the technology architecture is accordingly augmented, and the service inventory blueprint is gradually populated.
Building Up Solutions: Service Capability Composition and Recomposition
One of the fundamental characteristics that distinguish service-oriented technology architecture from other forms of distributed architecture is composition-centricity, meaning that there is a baseline requirement to inherently support both the composition and re-composition of the moving parts that comprise a given solution.
In this section, we cover some fundamental aspects of composition in relation to service-orientation by briefly describing relevant principles and patterns.
Service-Orientation and Service Composition
A baseline requirement for achieving the strategic goals of service-oriented computing, is that services must be inherently composable. As a means of realizing these goals, the service-orientation design paradigm is therefore naturally focused on enabling flexible composition.
This dynamic is illustrated in Figure 9, where we can see how the collective application of service-orientation principles share software programs into services that are essentially “composition-ready,” meaning that they are interoperable, compatible, and composable with other services as part of the same service inventory. The scope of this service inventory can vary, as long as it is meaningfully cross-silo (as per Domain Inventory).
Figure 9 – Service A is a software program shaped into a unit of service-oriented logic by the application of service-orientation design principles. Service A is delivered within a service inventory that contains a collection of services to which service-orientation principles were also designed. The result is that Service A can participate initially in Composition X and, more importantly, can be pulled into additional service compositions, as required.
What is being illustrated in Figure 9 is not just that services can be aggregated. All distributed systems are comprised of aggregated software programs. What is fundamentally distinct about how service-orientation positions services is that they are repeatedly composable, allowing for subsequent recomposition.
This is what lies at the core of realizing organizational agility as a primary goal of adopting service-oriented computing. By have a set of services (again, within the scope determined by the service inventory only) naturally interoperable and design for participation in complex service compositions, we are able to fulfill new business requirements and automate new business processes by augmenting existing service compositions or creating new service compositions with reduced effort and expense. This target state is what leads to the Reduced IT Burden goal of service-oriented computing.
Among the eight service-orientation design principles, there is one that is specifically relevant to service composition design. The Service Composability principle is solely dedicated to shaping a service into an effective composition participant. All other principles support Service Composability in achieving this objective (Figure 10). In fact, as a regulatory principle, Service Composability is applied primarily by ensuring that the design goals of the other seven principles are realized to a sufficient extent.
Figure 10 – A common objective of all service-orientation design principles is that they shape services in support of increasing composability potential.
Capability Composition and Capability Recomposition
Fundamental service identification and definition patterns can be assembled into an application sequence that forms a primitive service modeling process. However, those patterns result only in the separation of logic into individual functional contexts and capabilities. The application of these fundamental patterns need to be followed by patterns that reassemble the separated logic into aggregates. This is the purpose of Capability Composition and Capability Recomposition (Figure 11).
Figure 11 – Capability Composition is one of two patterns applied subsequent to the application of service identification and definition patterns. The relevance of the Capability Recomposition pattern is explained in the following section.
Capability Composition represents a pattern that is applied to assemble the decomposed service logic together into a specific service composition capable of solving a specific larger problem (Figure 12).
The importance of this pattern, beyond forming the basis for the basic aggregation of service functionality, is that it reinforces fundamental patterns, such as Logic Centralization and Service Normalization. It does so by preserving the functional boundaries established by service contexts in that it requires a service that needs access to logic outside of its context to access this logic via the composition of another service.
Figure 12 – Although generally referred to as service composition, services that compose each other actually do so via their individual service capabilities, hence the name of this pattern.
As previously mentioned, the recomposition of services is a fundamental and distinctive goal of service-oriented computing. This pattern specifically addresses the repeated involvement of a service via the repeated composition of a service capability. The patterns relationship diagram shown in Figure 13 highlights how service identification and definition patterns, together with Capability Composition, essentially lead up to opportunities to apply Capability Recomposition.
A very important consideration here is that the application of Capability Recomposition has a different purpose and different requirements than Capability Composition. As covered earlier, service-orientation design principles are geared specifically toward enabling the application of Capability Recomposition. And, as further shown in Figure 13, most other SOA design patterns solve their respective design problems in support of enabling the application of this pattern.
Figure 13 – Because of how core the repeated composability of services is to service-orientation and SOA, Capability Recomposition has many relationships with other SOA design patterns.
With the potential for Capability Recomposition to be applied frequently, a given service can find itself participating in different ways within a given service composition. Therefore, in order to better identify and describe the interaction between services within a service composition architecture, a set of runtime roles exist:
- composition controller – The service with a capability that is executing the parent composition logic required to compose capabilities within other services.
- composition member – A service that participates in a service composition by being composed by another service.
- composition initiator – The program that initiates a service composition by invoking the composition controller. This program may or may not exist as a service.
- composition sub-controller – A variation of the composition controller role that is assumed by a service carrying out nested composition logic (within a capability that is composing one or more other service capabilities while itself also being composed).
Services assume composition roles within the context of different service compositions, depending on the logic executed by service capabilities. In other words, a service’s capabilities will automatically enlist the service in one or more composition roles.
The entity and utility service models correspond to the Entity Abstraction and Utility Abstraction patterns respectively. These service models represent the two most common agnostic functional contexts for services (in other words, they represent the two popular means of further applying the Agnostic Context pattern).
When we abstract common types of logic into collections of services based on the same underlying service model, we end up establishing service layers. These logical layers are the result of the application of the Service Layers pattern, which provides us with an opportunity to organize and classify all services within a given service inventory.
Service Layers requires that at least two layers exist, and these layers are generally based on a fundamental separation of agnostic and non-agnostic service logic. Therefore, we typically end up with a task service layer, followed by a service layer based on one or more agnostic service models, as shown in Figure 14.
Figure 14 – At minimum, Service Layers requires that two logical layers of services be established within a service inventory.
The Three-Layer Inventory compound pattern essentially indicates that the most common application of Service Layers is via the combined application of Entity Abstraction, Utility Abstraction, and Process Abstraction. This establishes a logical layered architecture that tends to encompass the natural hierarchy formed by most service compositions (Figure 15).
Figure 15 – A composition of services that forms a hierarchy that spans the three service layers represented by the Three-Layer Inventory pattern. The top layer is defined via the application of the Process Abstraction pattern (explained shortly).
The fundamental service identification and definition patterns established earlier in this article focused on the separation of multi-purpose or agnostic service logic. When decomposing business process logic as part of a service-oriented analysis, what remains after multi-purpose logic is separated is logic that is specific to the business process. Because this logic is considered single-purpose in nature, it is classified as non-agnostic. The encapsulation of non-agnostic logic within a service is the basis of the Non-Agnostic Context pattern (Figure 16).
Figure 16 – By revisiting the decomposition process, we can now apply Non-Agnostic Context to establish a service context for the separated non-agnostic logic.
Process Abstraction and Task Services
Common types of agnostic services are generally (but not always) dependent on the existence of abstracted, non-agnostic business process logic that is encapsulated in task services (Figure 17). This is the result of the combined application of Non-Agnostic Context and Process Abstraction.
Figure 17 – Each task service represents is part of a parent service layer and is responsible for encapsulating logic specific to parent business process logic.
The runtime role is most commonly associated with the task service model is the composition controller because the functional scope of these services is typically focused on a parent business process. A variation of the task service model, called the orchestrated task service, is discussed shortly.
Orchestration builds upon service composition by aiming to establish a physical environment capable of centrally executing and governing multiple automated business processes. The Orchestration compound pattern represents such an environment via the co-existent application of a set of specific patterns (Figure 18).
Figure 18 – The Orchestration compound pattern.
Process Abstraction, Process Centralization, and Orchestrated Task Services
The Process Abstraction pattern is fundamental to orchestration because an orchestration platform is designed specifically to house and execute parent business process logic. Process Centralization is equally fundamental because an orchestration platform enables the centralized hosting, execution, and governance of the same parent business process logic.
The application of Process Abstraction alone results in the creation of task services, as explained earlier. However, it is the combined application of Process Abstraction and Process Centralization that defines the orchestrated task service model. This is because orchestrated task services are distinguished from regular task services by the fact that they are hosted within an orchestration platform.
In other words, although they logically still abstract the same non-agnostic service logic into a separate layer (Figure 19), they are different in how they are physically implemented and administered.
Figure 19 – Orchestrated task services appear identical to task services when viewed from a logical service layers perspective.
Orchestrated task services are built within and upon the specific features and architectural components that comprise an orchestration environment. This changes the baseline complexion of the task service architecture to such an extent that a separate service model classification is warranted.
Service Reusability is concerned with the identification of reusable logic as well as ensuring that the service architecture itself is capable of real world reuse. Several foundational service identification and definition patterns can be applied during iterations of the service-oriented analysis phase in order to identify, define, separate, and refine agnostic logic suitable for reuse.
Service Composability is focused on the effective and repeatable composition of service capabilities, as well as ensuring the agile incorporation of service architectures within multiple service composition architectures. Key patterns that relate directly to enabling service composition in support of the Service Composability principle include Capability Composition, Capability Recomposition, Non-Agnostic Context, and Process Abstraction.
Other service-orientation design principles and many other SOA design patterns directly contribute to and support the goals of the Service Reusability and Service Composability principles, as do numerous service technologies and platforms. However, it is important to understand that the foundation upon which we reuse and compose services is established when we first identify and define agnostic units of logic.
[REF-1] SOA Design Patterns, ISBN: 9780136135166, Prentice Hall, www.soabooks.com/patterns/
[REF-2] SOA Patterns Catalog, www.soapatterns.org
[REF-3] SOA Principles of Service Design, ISBN: 9780132344821, Prentice Hall, www.soabooks.com/psd/
[REF-4] SOA Principles, www.soaprinciples.com
[REF-5] SOA with.NET and Windows Azure: Realizing Service-Orientation with Microsoft Technologies, ISBN: 978013158231, Prentice Hall, www.soabooks.com/net/
[REF-6] SOA Glossary, www.soaglossary.com