The Service Refactoring pattern facilitates changes in service logic and/or underlying service implementation while preserving existing consumer contracts.
The Service Refactoring pattern allows the service provider to change the service implementation while preserving existing service contracts. This allows the provider the flexibility to honor existing consumers while taking advantage of streamlined service logic and/or better technologies. If this idea sounds familiar, it is based on the refactoring principles and techniques advocated by Martin Fowler in the object oriented design paradigm and aims to achieve the same result for services in a SOA context. This pattern requires the development of an adapter – that will translate messages conforming to the existing contract into the refactored contract and vice versa.
- Allows for phased migration of consumers who use existing contract to a new one
- Allows the provider to upgrade/enhance service behavior in phases. The refactoring can be accomplished via multiple steps and don’t all have to be bundled in a single release
- Eliminates the need for consumers to change code to take advantage of refactored service
- Allows new consumers to bind to the enhanced service contract and allows for new and existing consumers to co-exist
- Potentially enhance performance, availability, and scalability as new consumers come on board
There is a need for strong and coordinated service governance to make sure that consumers are aware of the refactoring effort, retest to validate the behavior, and ultimately provide sign-off for the service capability to be turned on in a production environment. At a minimum, this pattern needs to make sure that existing consumers conduct regression testing to guarantee that the refactored service doesn’t necessitate code changes.
The word ‘governance’ seems to conjure up all sorts of negative images for IT folks – needless bureaucracy seems to top that list. However, without lightweight governance, SOA and systematic reuse efforts will fail to achieve their full potential. Can you spot signs that indicate need for governance? I believe so and here are five:
- Every project seems to reinvent business abstractions that are fundamental to your problem domain. No sharing or consistency of information models – this will be painfully evident when projects are happening back to back and your teams seem to be running into overlapping data modeling, data definition, and data validation issues.
- Directly linked to above – is service definitions seem to not reuse schemas – i.e. each service has a unique schema definition for a customer or product (or some key object from your domain) and your service consumers are forced to deal with multiple conflicting schemas.
- Legacy capabilities are leveraged as-is without mediation – increasing coupling between consumers and legacy systems. Tell tale sign here is if you see arcane naming and needless legacy data attributes sprinkled all over service interfaces.
- Services seem to have inconsistent runtime characteristics – new service capabilities are added without regard to performance requirements – issues tend to manifest in production where users or entire processes/applications get impacted to service behavior.
- Business processes bypass a service layer and directly access underlying data stores – if you have seen a business process invoking several stored procedures, doing FTP, publishing to multiple messaging destinations – all from a monolithic process definition that is a clear sign that governance is non existent.
These are few signs but key indicators that services are being built in a tactical fashion. In a follow up post, will expand on how governance can be leveraged appropriately to address these issues.
Part 1 of a two part Article series on SOA adoption is up on the SOA magazine
New episode added to the Software Reuse Podcast Series on designing reuse-friendly XML schema definitions as part of SOA efforts. Elaborates on a core set of practices that will make your service contracts more maintainable and reusable.
There are a variety of components – that can encapsulate business logic (either simple algorithm/calculations or even complex orchestrations). These components can be invoked from business process orchestrations as well as stateless services. These reusable components could be business rules integrated as decision services or legacy services wrapped using a more decoupled interface. Business events such as a new account being opened or a new security getting added to a portfolio could trigger a core piece of logic – e.g. get statement preferences – that can be used to fulfill both these needs.
For instance, in the diagram below that two business processes and a stateless service invoke a common component via a request dispatcher (or a router module).
If you tightly couple a piece of logic that is applicable across business processes or service capabilities you can refactor it to create a new resuable component. This is all the more reason why it is a good idea to go through a service mediation layer when leveraging legacy services from business processes. If you decide to reuse the legacy service in a new orchestration it will be straightforward to plugin a new consumer.
Many teams that build service capabilities have to manage multiple versions – this is a problem for any shared asset really – be it a library, component, or service. Using extensible schema contracts (also referred to as Consumer Driven Contracts) you can design service contracts that allow both provider to evolve and consumer to integrate in a flexible manner. In this post, I want to suggest five additional tips when managing web services:
1. Figure out how many versions your team will support concurrently. Too little will force all your consumers to be on a single version and too many will become a maintenance nightmare for you (the provider). In past implementations, I have maintained upto 3 versions while actively moving all service consumers towards one target version. A related approach is to have multiple flavors for your service capability one that returns data that most consumers want, the second that provides the minimal set of attributes, and a third flavor that returns the full list of data items. This may or may not be possible in your case, but something to consider when designing contracts.
2. Figure out how you are going to support multiple versions as a service provider. You can use xml schema namespaces to indicate versions: http://some-company.com/services/CustomService_ver1_0.xsd, ver1_1.xsd and so on. Consider creating a service adapter that can translate back and forth between a new service implementation and the existing one. This can potentially help you with one server side implementation of the functional logic and still service your current and new consumers. This adapter component can perform necessary data transformations, error code & error message translations, and massage response with data attributes as appropriate.
3. Communicate the change in the service capability and gauge the appetite with existing consumers for their ability to absorb the changes in the same release time frame that you are targeting to drop your new version. If you co-ordinate the release, you can get them to new version when you go live. However, for mission critical applications you will want to support both your current and new version concurrently for a small time period before switching the old one off.
4. When you design forward-compatible schemas, you can test the data-binding against multiple platforms. For example, use WSDL2Java if you are using Apache Axis in Java or wsdl.exe if you are in .NET and generate appropriate web service proxy classes and data binding classes. What i have done is to implement JUnit and NUnit automated test cases that run everytime there is a new WSDL or service contract (XSD) change. This will not only validate the service functional logic, but also the forward-compatibility of existing clients. Make sure your when you generate bindings that you generate with both the new schema/wsdl (your updated version) and the existing schema/wsdl files (the version currently used by production clients).
5. Establish lightweight service governance – it is critical to plan how many service flavors and versions you will support, when will they get upgraded, deprecated, decommissioned, etc. and communicate those with your consumers. Identify checkpoints in your development process where contracts can be reviewed and service behavior can be discussed openly. The well thought out service orientation strategy is a benefit for both the provider and the consumers in your organization.
What other tips/techniques have you used?