Chapter 16 Service Governance Patterns

image

Note

The governance patterns in this chapter focus only on design-related governance issues that pertain to service architecture. The upcoming book SOA Governance as part of this book series will provide a collection of broader technical and organizational best practices and patterns.

Despite best efforts during analysis and modeling phases to deliver services with a broad range of capabilities, they will still be subjected to new situations and requirements that can challenge the scope of their original design. For this reason, several patterns have emerged to help evolve a service without compromising its responsibilities as an active member of a service inventory.

Compatible Change (465) and Version Identification (472) are focused on the versioning of service contracts. Similarly, Termination Notification (478) addresses the retirement of services or service contracts.

The most fundamental pattern in this chapter is Service Refactoring (484), which leverages a loosely (and ideally decoupled) contract to allow the underlying logic and implementation to be upgraded and improved.

The trio of Service Decomposition (489), Decomposed Capability (504), and Proxy Capability (497) establish techniques that allow coarser-grained services to be physically partitioned into multiple fine-grained services that can help further improve composition performance. Distributed Capability (510) also provides a specialized, refactoring-related design solution to help increase service scalability via internally distributed processing deferral.

Table 16.1 Profile summary for the Compatible Change pattern.

image

Problem

After a service is initially deployed as part of an active service inventory, it will make its capabilities available as an enterprise resource. Consumers will be designed to invoke and interact with the service via its contract in order to leverage its capabilities for their own use. As a result, dependencies will naturally be formed between the service contract and those consumer programs. If the contract needs to be changed thereafter, that change can risk impacting existing consumers that were designed in accordance with the original, unchanged contract (Figure 16.1).

Figure 16.1 The name of a service capability is modified after version 1 of a service contract is already in use As a result, version 2 of the contract is incompatible with Consumer A.

image

Solution

Wherever possible, changes to established service contracts can be made to preserve the contract’s backwards compatibility with existing consumers. This allows the service contract to evolve as required, while avoiding negative impact on dependent compositions and consumer programs (Figure 16.2).

Figure 16.2 The existing capability is not renamed. Instead, a new capability with a new name is added alongside the original capability, thereby preserving compatibility with both Consumers A and B.

image

Application

There are a variety of techniques by which this pattern can be applied, depending on the nature of the required change to the contract. The fundamental purpose of this pattern is to avoid having to impose incompatible changes upon a service contract that do not preserve backwards compatibility and therefore risk breaking and invalidating existing service-consumer relationships.

Here is a collection of common changes for Web service contracts, along with descriptions of how (or to what extent) these changes can be applied in a backwards-compatible manner:

Adding a New Operation to a WSDL Definition– The operation can simply be appended to the existing definition, thereby acting as an extension of the contract without impacting any established contract content.

Renaming an Existing Operation– As explained in the previous diagrams, an operation can be renamed by adding a new operation with the new name alongside of the existing operation with the old name. This approach can be further supplemented with Termination Notification (478), if there is a requirement to eventually retire the original operation while allowing consumers dependent on that operation a grace period to be updated in support of the renamed operation.

Removing an Existing Operation– If an operation needs to be permanently deleted from the WSDL definition, there are no options for accomplishing this change in a compatible manner. Termination Notification (478) is highly recommended in this case in order to give consumer designers sufficient opportunity to transition their programs so that they are no longer using the to-be-terminated operation. Also, the technique of turning removed operations into functional stubs that respond with descriptive error data can also be employed to minimize impact on consumers that could not be transitioned.

Changing the MEP of an Existing Operation– To alter an operation’s message exchange pattern requires that its input and output message definitions (and possibly its fault definition) be modified, which is normally an incompatible change. To still proceed with this change while preserving backwards compatibility requires that a new operation with the modified MEP be appended to the WSDL definition together with the original operation. As when renaming an operation in this manner, Termination Notification (478) can be used to assist an eventual transition.

Adding a Fault Message to an Existing Operation– The addition of a fault message (when considered separately from a change to the MEP) may often appear as a compatible change because the option of issuing a fault message does not affect the core functionality of an operation. However, because this addition augments the service behavior, it should be considered a change that can only be compatible when adding the fault message as part of a new operation altogether.

Adding a New Port Type– Because WSDL definitions allow for the existence of multiple port type definitions, the service contract can be extended by adding a new port type alongside an existing one. Although this represents a form of compatible change, it may be more desirable to simply issue a new version of the entire Web service contract.

Adding a New Message Schema Element or Attribute– New elements or attributes can be added to an existing message schema as a compatible change as long as they are optional. This way, their presence will not affect established service consumers that were designed prior to their existence.

Removing an Existing Message Schema Element or Attribute– Regardless of whether they are optional or required, if already established message schema elements or attributes need to be removed from the service contract, it will result in an incompatible change. Therefore, this pattern cannot be applied in this case.

Modifying the Constraint of an Existing Message Schema– The validation logic behind any given part of a message schema can be modified as part of Compatible Change, as long as the constraint granularity becomes coarser. In other words, if the restrictions are loosened, then message exchanges with existing consumers should remain unaffected.

Adding a New Policy– One or more WS-Policy statements can be added via Compatible Change by simply adding policy alternatives to the existing policy attachment point.

Adding Policy Assertions– A policy assertion can be added as per Compatible Change (465) to an existing policy as long as it is optional or added as part of a separate policy as a policy alternative.

Adding Ignorable Policy Assertions– Because ignorable policy assertions are often used to express behavioral characteristics of a service, this type of change is generally not considered compatible.

Note

This list of changes corresponds to a series of sections within Chapters 21, 22 and 23 in the book Web Service Contract Design and Versioning for SOA, which explores compatible and incompatible change scenarios with code examples.

Impacts

Each time an already published service contract is changed, versioning and governance effort is required to ensure that the change is represented as a new version of the contract and properly expressed and communicated to existing and new consumers. As explained in the upcoming Relationships section, this leads to a reliance upon Canonical Versioning (286) and Version Identification (472).

When applying Compatible Change in such a manner that it introduces redundancy or duplication into a contract (as explained in several of the scenarios from the Application section), this pattern can eventually result in bloated contracts that are more difficult to maintain. Furthermore, these techniques often lead to the need for Termination Notification (478), which can add to both the contract content and governance effort for service and consumer owners.

Finally, when the result of applying this pattern is a loosening of established contract constraints (as described in the Modifying the Constraint of an Existing Message Schema scenario from the Application section earlier), it can produce vague and overly coarse-grained contract content.

Relationships

To apply this pattern consistently across multiple services requires the presence of a formal versioning system, which is ideally standardized as per Canonical Versioning (286). Furthermore, this pattern is dependent upon Version Identification (472) to ensure that changes are properly expressed and may also require Termination Notification (478) to transition contract content and consumers from old to new versions.

Figure 16.3 Compatible Change relates to several other service governance patterns but also may depend on some contract design patterns.

image

Table 16.2 Profile summary for the Version Identification pattern.

image

Problem

Whether a contract is subject to compatible or incompatible changes, any modification to its published content will typically warrant a new contract version. Without a means of associating contract versions with changes, the compatibility between a service and its current and new consumers is constantly at risk, and the service also becomes less discoverable to consumer designers (Figure 16.4).

Figure 16.4 As a service contract is required to change, a service consumer is left in the dark as to whether it is still compatible.

image

Furthermore, the service itself also becomes more burdensome to govern and evolve.

Solution

The service contract can be designed to express version identifiers that allow the consumer to confidently determine whether it is compatible with the service. The use of version identifiers further supports Concurrent Contracts (421) for versioning purposes, thereby allowing a consumer to choose the correct contract based on its expressed version, as shown in Figure 16.5.

Figure 16.5 Because the service contracts express versioning information, Consumer A can proceed to invoke version 3 of the service contract because it was designed to be compatible with that specific version.

image

Application

Versions are typically identified using numeric values that are incorporated into the service contract either as human-readable annotations or as actual extensions of the technical contract content. The most common version number format is a decimal where the first digit represents the major version number, and digits following the decimal point represent minor version numbers.

What the version numbers actually mean depends on the conventions established by an overarching versioning strategy. Two common approaches are described here:

Amount of Work– Major and minor version numbers are used to indicate the amount of effort that went into each change. An increment of a major version number represents a significant amount of work, whereas increases in the minor version numbers represent minor upgrades.

Compatibility Guarantee– Major and minor version numbers are used to express compatibility. The most common system is based on the rule that an increase in a major version number will result in a contract that is not backwards-compatible, whereas increases in minor version numbers are backwards-compatible. As a result, minor version increments are not expected to affect existing consumers.

Note that these two identification systems can be combined so that version number increases continue to indicate compatible or incompatible changes, while also representing the amount of work that went into the changes.

With Web service contracts specifically, a common means of ensuring that existing consumers cannot accidentally bind to contracts that have been subject to non-backwards-compatible changes is to incorporate the version numbers into new namespace values that are issued with each new major version increase.

Note

Whereas version numbers are often incorporated into the target namespaces for WSDL definitions, date values are commonly appended to target namespaces for XML Schema definitions. See Chapters 20, 21, and 22 in the Web Service Contract Design and Versioning for SOA book for code examples and more details.

Impacts

Version identification systems and conventions are typically specific to a given service inventory and usually part of a standardized versioning strategy, as per Canonical Versioning (286). As a result, they are not standardized on an industry level and therefore, when expressed as part of the technical contract, impose the constant requirement that service consumers be designed to understand the meaning of version identifiers and programmatically consume them, as required.

When services are exposed to new or external consumers, these same requirements apply, but the necessary enforcement of standards may be more difficult to achieve.

Relationships

This pattern is commonly applied together with (or as a result of) the application of Canonical Versioning (286) and is further an essential part of carrying out Compatible Change (465).

Figure 16.6 Version Identification relates primarily to other contract versioning patterns.

image

Note

Version Identification is comparable to Format Indicator (Hohpe, Woolf) when applied to express a version number as part of a message. Format Indicator differs in that it is message-centric and also enables the expression of other meta information, such as foreign keys and document formats.

Table 16.3 Profile summary for the Termination Notification pattern.

image

Problem

As services evolve over time, various conditions and circumstances can lead to the need to retire a service contract, a portion of a service contract, or the entire service itself.

Examples include:

• the service contract is subjected to a non-backwards-compatible change

• a compatible change is applied to a service contract but strict versioning policies require the issuance of an entirely new version of the service contract

• a service’s original functional scope is no longer applicable in relation to how the business has changed

• a service is decomposed into more granular services or combined together with another service

In larger IT enterprises and especially when making services accessible to external partner organizations, it can be challenging to communicate to consumer owners the pending termination of a service or any part of its contract in a timely manner.

Failure to recognize a scheduled retirement will inevitably lead to runtime failure scenarios, where unaware consumer programs that attempt to invoke the service are rejected (Figure 16.7).

Figure 16.7 The consumer program (right) invokes a service via its contract as usual today, but when the contract is terminated on the next day, the attempted invocation fails.

image

Solution

Service contracts are equipped with termination details, thereby allowing consumers to become aware of the contract retirement in advance (Figure 16.8).

Figure 16.8 The service contract includes a standardized statement that communicates when it is scheduled for termination. As a result, the consumer does not attempt to invoke it after the contract has been terminated.

image

Application

This pattern is most commonly applied by supplementing technical contract content with human-readable annotations that simply provide the termination date. However, with Web service contracts, there is also the option of leveraging the WS-Policy language to express termination notifications via ignorable policy assertions. This enables consumer programs to be designed to programmatically check for termination information.

It is also worth noting that in addition to expressing service contract termination, there are other purposes for which Termination Notification can be applied, such as:

Indicating the retirement of a specific capability or operation– This is especially relevant when choosing one of the transition techniques described in Compatible Change (465) where an original operation is preserved and a similar, but changed, operation is added.

Indicating the retirement of an entire service– This same approach can be used to communicate that an entire service program itself is scheduled for retirement.

Indicating the retirement of a message schema– Although policy assertions may not be suitable for this purpose, regular annotations can be added to schemas to explain when the schema version will be terminated and/or replaced.

Note also that governance standards can be put in place as part of an overarching Canonical Versioning (286) strategy to express termination notification information via standardized annotations or non-ignorable policy assertions. In the latter case, this can require that all Web service contracts contain termination assertions, regardless of whether they are due for termination. For those contracts that are not being terminated, a pre-defined value indicating this is placed in the assertion instead of a date (or the assertion is left empty).

Impacts

All of the techniques explained in this pattern description require the use of non-standardized extension content for service contracts. This is because there is no industry standard for expressing termination information. Termination Notification relies on the existence and successful enforcement of governance standards and therefore has a direct dependency on Canonical Versioning (286).

Relationships

As just mentioned, how this pattern is applied is often governed by Canonical Versioning (286). Both Compatible Change (465) and Proxy Capability (497) can lead to the need for Termination Notification.

Figure 16.9 Termination Notification relates primarily to other versioning patterns but also can support Proxy Capability (497).

image

Note

Termination Notification is similar in concept to Message Expiration (Hohpe, Woolf), a pattern that advocates adding a timestamp to a message to indicate when the message itself is no longer considered valid.

Note

For more examples of Termination Notification see Chapter 23 of Web Service Contract Design and Versioning for SOA.

Table 16.4 Profile summary for the Service Refactoring pattern.

image

Problem

Subsequent to its initial delivery, unforeseen performance and business requirements may demand more from a service than it is capable of providing (Figure 16.10). Replacing the service entirely may be undesirable, especially when several consumer programs have already formed dependencies upon its established service contract.

Figure 16.10 Consumers of an existing service demand new requirements for which the service was not originally designed. The red symbols indicate the different parts of this service architecture that could be independently versioned.

image

Solution

Software refactoring is an accepted software engineering practice whereby existing software programs can be gradually improved without affecting the manner in which they behave. When applied to service design, this approach provides more opportunity for services to evolve within an organization without disrupting their existing consumers. As shown in Figure 16.11, with the application of this pattern the underlying logic and implementation of a service can be regularly optimized, improved, or even upgraded while preserving the service contract.

Figure 16.11 All parts of a service architecture abstracted by its contract can potentially be refactored without compromising existing consumer relationships. The service contract and the remaining, externally facing message processing agents (red) are not affected by the refactoring effort.

image

Application

Software refactoring practices allow programs to be improved through a series of small upgrades that continue to preserve their interfaces and overall behavior. By limiting the scope of these upgrades, the risk associated with negatively impacting consumers is minimized. The emphasis of software refactoring techniques is on the cumulative result of these individual refactoring steps.

This pattern can be more successfully applied when the service has already been subjected to the application of Decoupled Contract (401) and the Service Loose Coupling design principle. The separation of service logic from a fully decoupled contract provides increased freedom as to how refactoring can be carried out, while minimizing potential disruption to existing service consumers.

Note

Several books covering refactoring techniques and specialized patterns are available. Two well-known titles are Refactoring: Improving the Design of Existing Code (Fowler, Beck, Brant, Opdyke, Roberts) and Refactoring to Patterns (Kerievsky), both by Addison-Wesley. The site www.refactoring.com provides additional resources as well as a catalog of proven “refactorings.”

Impacts

The refactoring of existing service logic or technology introduces the need for the service to undergo redesign, redevelopment, and retesting cycles so as to ensure that the existing guarantees expressed in the service contract (which includes its SOA) can continue to be fulfilled as expected (or better).

Because already established and proven logic and technology is modified or replaced as a result of applying this pattern, there is still always a risk that the behavior and reliability of a refactored capability or service may still somehow negatively affect existing consumers. The degree to which this risk is alleviated is proportional to the maturity, suitability, and scope of the newly added logic and technology and the extent to which quality assurance and testing are applied to the refactored service.

Relationships

The extent to which Service Refactoring can be applied depends on how the service itself was first designed. This is why there is a direct relationship between this pattern and Service Normalization (131), Contract Centralization (409), and Decoupled Contract (401). The abstraction and independence gained by the successful application of those patterns allows services to be individually governed and evolved with minimal impact to consumer programs.

Furthermore, depending on the nature of the refactoring requirements, Service Decomposition (489), Concurrent Contracts (421), or Service Façade (333) may need to be applied to accommodate how the service is being improved.

Figure 16.12 Service Refactoring relies on several key contract-related patterns to ensure that refactoring-related changes do not disrupt existing service consumers.

image

Table 16.5 Profile summary for the Service Decomposition pattern.

image

Problem

When modeling services during the initial analysis phases it is common to take practical considerations into account. For example, what may ideally be represented by a set of fine-grained business service candidates is later combined into a smaller number of coarse-grained services primarily due to performance and other infrastructure-related concerns motivated by the need to keep service composition sizes under control.

After a service inventory architecture matures and more powerful and sophisticated technology and runtime products are incorporated, larger, more complex service compositions become a reality. When designing such compositions, it is generally preferable to keep the footprints of individual services as small as possible because only select service capabilities are required to automate a given parent business task. However, when forced to work with overly coarse-grained services, composition performance can be negatively affected, and the overall composition designs can be less than optimal (Figure 16.13).

Figure 16.13 An Invoice service with a functional context originally derived from three separate business entities ends up existing as a large software program with a correspondingly large footprint, regardless of which capability a composition may need to compose.

image

Note

Another circumstance under which this problem condition can occur is when services are being produced via a meet-in-the-middle delivery process, where a top-down analysis is only partially completed prior to service development. In this delivery approach, the top-down process continues concurrently with service delivery projects. There is a commitment to revising implemented service designs after the top-down analysis progresses to a point where necessary changes to the original service inventory are identified. For more details regarding SOA project delivery strategies, see Chapter 10 in Service-Oriented Architecture: Concepts, Technology, and Design.

Solution

The coarse-grained service is decomposed into a set of fine-grained services that collectively represent the functional context of the original service but establish distinct functional contexts of their own (Figure 16.14).

Figure 16.14 The original, coarse-grained Invoice service is decomposed into three separate services, one of which remains associated with general invoice processing but only encapsulates a subset of the original capabilities.

image

Application

Carrying out this pattern essentially requires that the existing, coarse-grained service be broken apart and its logic reorganized into new, finer-grained functional boundaries.

Therefore, the first step is usually to revisit the service inventory blueprint and decide how the service can be re-modeled into multiple service candidates. As part of this process, new capability candidates will also need to be defined, especially if Decomposed Capability (504) was not taken into account during the service’s original design. After the modeling is completed, the new services are subject to the standard lifecycle phases, beginning with contract design (based on the modeled service candidates) and all the way through to final testing and quality assurance phases (Figure 16.15).

Figure 16.15 The new, fine-grained services each provide fewer capabilities and therefore also impose smaller program sizes.

image

Unless it is decided to also retrofit previous consumer programs that formed dependencies on the original service, Proxy Capability (497) will likely need to be applied to preserve the original service contract for backwards compatibility.

Note

The concepts behind this pattern can also be applied in reverse, where two or more fine-grained services are combined into one coarse-grained service. The use of Proxy Capability (497) would still apply for preserving the original service contracts. This is the basis of a pattern called Service Consolidation which, at the time of this writing, was classified as a candidate pattern that is available for review at SOAPatterns.org.

Impacts

The extent to which Service Decomposition can impact a service inventory depends on how established a service is and how many consumer programs have formed relationships on it. The more consumers involved, the more complicated and disruptive this pattern can be.

Because this pattern is commonly applied after an inventory architecture has matured, its application needs to be carefully planned together with the repeated application of Proxy Capability (497).

The preventative use of Decomposed Capability (504) can ease the impact of Service Decomposition and will also result in a cleaner separation of functional service contexts.

Relationships

Service Decomposition has a series of relationships with other service-level patterns, most notably Service Refactoring (484). When a service is upgraded as a result of a refactoring effort, the application of Service Decomposition may very well be the means by which this is carried out.

As explained in the pattern description for Proxy Capability (497), Service Decomposition relies on that pattern to implement the actual partitioning via the redevelopment effort required to turn one or more regular capabilities into proxies. As a result, this pattern shares several of the same patterns as Proxy Capability (497).

Service Decomposition is most frequently applied to agnostic services, therefore tying it to Entity Abstraction (175) and Utility Abstraction (168). However, the result of this pattern can introduce a measure of service redundancy due to the need for Proxy Capability (497) to violate Service Normalization (131) to some extent.

Figure 16.16 Service Decomposition is a refactoring-related approach to splitting up service logic that ties into numerous patterns that shape service logic and contracts.

image

Note

The preceding scenario describes one possible option as to how a service can be decomposed. Another design option is to split the one entity service into an entity and utility service in order to accommodate more practical concerns. Either way, how a service is decomposed is ultimately best determined by a thorough analysis to ensure that your business requirements are fully met.

Table 16.6 Profile summary for the Proxy Capability pattern.

image

Problem

As per Service Decomposition (489), it is sometimes deemed necessary to further decompose a service’s functional boundary into two or more functional boundaries, essentially establishing new services within the overall inventory. This can clearly impact existing service consumers who have already formed dependencies on the established service contract (Figure 16.17).

Figure 16.17 Moving a service capability that is part of an established service contract will predictably impact existing service consumers.

image

Solution

Capabilities affected by the decomposition are preserved, while those same capabilities are still allowed to become part of new services. Although the service’s original functional context is changed and its official functional boundary is reduced, it continues to provide capabilities that no longer belong within its context or boundary. These are proxy capabilities that are preserved (often for a limited period of time) to reduce the impact of the decomposition on the service inventory (Figure 16.18).

Figure 16.18 By preserving the existing capability and allowing it to act as a proxy for the relocated capability logic, existing consumers will be less impacted.

image

This does not prevent the capabilities in the new services from being independently accessed. In fact, access to the capability logic via its new service contract is encouraged so as to minimize the eventual effort for proxy capabilities to be phased out.

Application

Proxy Capability relies on the application of Service Façade (333) in that a façade is established to preserve affected service capabilities. The only difference is that instead of calling capability logic that is still part of the same service, the façade calls capabilities that are now part of new services (Figure 16.19).

Figure 16.19 When an existing consumer requests an Invoice service operation that has been moved due to the decomposition of the service (1), a newly added façade component relays the request to the capability’s new location (2), in this case the Invoice Reporting service.

image

Note

Termination Notification (478) is also commonly applied together with Proxy Capability in order to communicate the scheduled expiry of proxy capabilities.

Impacts

Although the application of this pattern extends the longevity of service contracts while allowing for the creative decomposition of service logic, it does introduce a measure of service denormalization that runs contrary to the goals of Service Normalization (131).

Proxy capabilities need to be clearly tagged with metadata communicating the fact that they no longer represent the official endpoint for their respective logic to avoid having consumers inadvertently bind to them.

Furthermore, this pattern alone does not guarantee that a proxy capability will continue to provide the same behavior and reliability of the original capability it replaced.

Relationships

Whereas Distributed Capability (510) prepares a service for the eventual application of Service Decomposition (489), Proxy Capability actually implements the decomposition while preserving the original service contract.

This is supported by Decoupled Contract (401), which allows the contracts of both the original and the decomposed services to be individually customized in support of the proxy capability. Service Façade (333) also plays an integral role in that it can be used to relay requests (act as the proxy) to and from the newly decomposed service.

And as previously mentioned, this pattern does end up going against the goals of Service Normalization (131). From an endpoint perspective especially, this pattern introduces the appearance of redundant functionality, a trade-off that is accepted in support of service evolution.

Figure 16.20 Proxy Capability alters the structure of a service in support of the creation of a new service and therefore touches several patterns related to service logic structure and the service decomposition process.

image

Table 16.7 Profile summary for the Decomposed Capability pattern.

image

Problem

Some types of services are more prone to being split after they have been developed and deployed. For example, entity services derive their functional context from corresponding business entities that are documented as part of common information architecture specifications. Often, an entity service context will initially be based around a larger, more significant business entity or even a group of related entities.

This can be adequate for immediate purposes but can eventually result in a number of challenges (Figure 16.23), including the following:

• As the service is extended, many additional capabilities are added because they are all associated with its functional context, leading to a bulky functional boundary that is difficult to govern.

• The service, due to increased popularity as a result of added capabilities or high reuse of individual capabilities, becomes a processing bottleneck.

Figure 16.23 An Invoice entity service (middle) derived from a group of Invoice-related business entities (left) exposes coarse-grained capabilities that are difficult to decompose when service decomposition requirements present themselves. Each of the affected Invoice service capabilities needs to be split up in order to accommodate the new services (right).

image

Despite a foreknowledge of these challenges, it may still not be possible to create a larger group of more granular services because of infrastructure constraints that restrict the size of potential service compositions. Sometimes an organization needs to wait until its infrastructure is upgraded or its vendor runtime platform matures to the point that it can support complex compositions with numerous participating services. In the meantime, however, the organization cannot afford to postpone the delivery of its services.

Solution

Services can be initially designed with future decomposition requirements in mind, which generally translates into the creation of more granular capabilities. With an entity service, for example, granular capabilities can be aligned better with individual business entities. This way, if the service needs to be decomposed in the future into a collection of services that represent individual business entities, the transition is facilitated by reducing the need to deconstruct capabilities (Figure 16.24).

Figure 16.24 The Invoice service (middle) derived from the same business entities (left) introduced in Figure 16.23 now exposes a series of more granular capabilities, several of which correspond directly to specific business entities. This increases the ease at which subsequent service decomposition can be accomplished. The decomposed services (right) are no longer in conflict because the capabilities affected by the decomposition are clearly mapped to the new services. Those same capabilities also remain in the Invoice service contract (top right) as per Proxy Capability (497).

image

Application

This pattern introduces more up-front service modeling effort in order to determine the appropriate service capability definitions. Specifically, the following considerations need to be taken into account:

• how the current functional scope can potentially be divided into two or more functional contexts

• how capabilities can be defined for these new functional contexts

This modeling effort follows a process whereby a collection of service candidates are defined in association with the scope of the service in question. These service candidates represent future services that can result from a decomposition of the current service and therefore provide a basis for capability candidates to be defined in support of the decomposition.

Note

This pattern differs from Contract Denormalization (414) in that the latter introduces redundant, granular capabilities for the purpose of supporting consumer requirements. Decomposed Capability allows for targeted granular capabilities (which may or may not be redundant) in order to facilitate the long-term evolutionary requirements of the service and the service inventory as a whole.

Impacts

The initial service contract that results from applying this pattern can be large and difficult to use. The increased capability granularity can impose performance overhead on service consumers that may be required to invoke the service multiple times to carry out a series of granular functions that could have been grouped together in a coarse-grained capability. This may lead to the need to apply Contract Denormalization (414), which will result in even more capabilities.

Even after the service has been decomposed, the existing consumers of the initial service may still need to be accommodated via proxy capabilities as per Proxy Capability (497), requiring the original service contract to remain for an indefinite period of time.

Also, it is sometimes difficult to predict how a service will be decomposed when initially defining it. There is the constant risk that the service will be populated with fine-grained capabilities that will never end up in other services and may have unnecessarily imposed performance burden upon consumers in the meantime.

Relationships

The key relationship illustrated in 489) because this pattern is applied in advance with the foreknowledge that a service will likely need to be decomposed in the future. It can therefore also be viewed as a governance pattern in that its purpose is to minimize the impact of a service’s evolution. For this same reason, it relates to Proxy Capability (497) that will usually end up being applied to one or more of the capabilities decomposed by this pattern.

Figure 16.25 Decomposed Capability prepares a service contract for eventual decomposition, making it closely related to patterns associated with Service Decomposition (489).

image

As already mentioned, the more fine-grained capabilities introduced by this pattern may require that Contract Denormalization (414) also be applied.

Table 16.8 Profile summary for the Distributed Capability pattern.

image

Problem

Each capability within a service’s functional context represents a body of processing logic. When a service exists in a physically implemented form, its surrounding environment may not be able to fully support all of the processing requirements of all associated capabilities.

For example, there may be a capability with unique performance, security, availability, or reliability requirements that can only be fulfilled through specific architectural extensions and special infrastructure. Other times, it is the increased processing demands on a single capability that can tax the overall service implementation to such an extent that it compromises the performance and reliability of other service capabilities (Figure 16.27).

Figure 16.27 The Consolidate operation of the Invoice Web service is subject to high concurrent usage and long response periods when it is required to perform complex consolidation calculations. These factors regularly lock up server resources and therefore compromise the performance and reliability of other service operations.

image

The logic supporting such a capability can be split off into its own service implementation. However, this would result in the need to break the original functional context for which the service was modeled.

Solution

Capability logic with special processing requirements is distributed to a physically remote environment. Intermediate processing logic is added to interact with local and distributed service logic on behalf of the single service contract (Figure 16.28).

Figure 16.28 The logic for the Consolidate operation is relocated to a separate physical environment. A service façade component interacts with the consolidation logic on behalf of the Invoice service contract.

image

Application

This pattern is commonly realized through the application of Service Façade (333) in order to establish the intermediate logic that essentially acts as the controller of a “component composition.” The component(s) representing the distributed capability logic interact with the façade logic via remote access.

Performance requirements can be somewhat streamlined by embedding additional processing logic within the façade so that it does more than just relay request and response message values. For example, the façade logic can contain routines that further parse and extract data from an incoming request message so that only the information absolutely required by the distributed capability logic is transmitted.

An alternative to using Service Façade (333) is Service Agent (543). Event-driven agents can be developed to intercept request messages for a specific service capability. These agents can carry out the validation that exists within the corresponding contract (or perhaps this validation is deferred to the capability logic itself) and then simply route the request message directly to the capability. The same agents can process the outgoing response messages from the capability as well.

Impacts

This pattern preserves the purity of a service’s functional context at the cost of imposing performance overhead. The positioning of the contract as the sole access point for two or more distributed implementations of service logic introduces an increased likelihood of remote access whenever the service is invoked.

If the capability logic was separated to guarantee a certain response time during high volume usage, then this may be somewhat undermined by the remote access requirements. On the other hand, overall service autonomy tends to be positively impacted as the autonomy level of the separated capability logic can be improved as a result of its separation.

Relationships

When structuring a service to support distributed capability processing, the service implementation itself exists like a mini-composition, whereby a façade component takes on the role of both component controller and single access point for the distributed service logic. This is why this pattern has such a strong reliance on Service Façade (333) and why it is supported by Decoupled Contract (401) in particular.

Contract Centralization (409) is also an essential part of the service design because it ensures that the contract will remain the sole access point, regardless of the extent the underlying logic may need to be distributed.

When a distributed capability needs to share access to service-related data, Service Data Replication (350) can be employed to help facilitate this access without the need to introduce intra-service data sharing issues. Additionally, this pattern is often the result of applying Service Refactoring (484) and can therefore be considered a continuation of a refactoring effort, especially when applied after the service’s initial deployment.

Figure 16.29 Distributed Capability supports the internal decomposition of service logic and therefore has relationships with both service logic and contract-related patterns.

image
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.144.131.62