When are Two Service Implementations Better than One? The Case for the Shared Service Lite
One of the huge potential benefits of an SOA is the possibility of eliminating the need to re-implement large chunks of application functionality by using shared services. For instance, rather than each application writing its own correspondence system to create and mail out letters, a shared service that could be invoked by all applications would do this generically.
A simple shared correspondence service in this case might maintain a number of templates (think of a Word template) and a message based API. The application would send a message containing the template ID, name and address of the correspondent and any other parameters to the service. The service would substitute in the parameterized data, mail out the letter and possibly return a confirmation message to the calling application.
So far so good, and if each application’s correspondence needs are limited to this then we are good to go. We have saved ourselves all the application code that hard-codes the specific correspondence in each of the applications, or alternatively replaced all the code in the application’s own internal template-based correspondence service.
However let’s say we have ten applications and all of them have slightly different correspondence requirements; one needs to be able to specify chunks of boilerplate text to be included in the final document, another needs to be able to mail the same document to multiple recipients, another needs to support high volume end of month mailings, and so on. As the service is extended to meet all these requirements it gets increasingly generalized and increasingly complex.
The shared service is likely to be significantly more complex than any one of the application-specific implementations that it is replacing. At one level this is a good thing. If any individual application needs to extend its correspondence capabilities in the future there is a reasonable chance that it can do so without much impact: just make a change to the request message, update a template or two and off you go. At another level, however, this is a potential problem.
SOA is looking to simplify the development of applications and the architecture as a whole. Flexibility usually comes at the cost of some complexity. Now each application has to understand, configure and test the correspondence service for its particular needs. If your original correspondence problem was a simple one this could mean replacing a relatively simple coded solution with a relatively complex configuration problem. Exacerbating this effect is that fact that many shared service implementations will be package solutions which are designed to deal with the varied correspondence requirements of multiple enterprises, some of which are features that none of your applications will use. When considering one service in isolation this might not be such big deal, but an SOA will be likely to have tens of services that application designers need to use.
Each service, like the correspondence service, will likely have a relatively simple API that the application uses to invoke it, but it will also likely have a configuration data base that is used to provide the flexibility the service needs. The correspondence service has its templates; the workflow service has its roles; tasks and routing rules, the security service has its roles, resources and access rules, and so on.
An application team now has to understand, configure and test each of these potentially complicated pieces of software. It also has to keep this configuration data in sync between services. Even with the help of a service specialist this could potentially be a daunting task. In short each application, no matter how simple its requirements for a service, has to deal with the complexity generated by a service complex enough to meet the current and future requirements of all the applications in the enterprise.
One solution to this problem is to implement two versions of a service. Let’s say you have ten applications, seven of which have very simple correspondence requirements. Start with a simple correspondence service solution that meets the needs of these seven applications, and later, as you migrate the first of the remaining three apps, you can implement the more complex generalized solution. This approach has a number of advantages:
- Assuming that most applications could get away with using the simpler service, and only require more robust services in a minority of cases, the overall complexity of the application is reduced.
- If an application can get away with using the lite version of the service it can have its cake and eat it, too: current simplicity and future flexibility. If its requirements change in the future it can upgrade to the full-function version with minimal effort, assuming we have done a good job of standardizing the interfaces between both versions of the services.
- It will reduce the time it takes to implement at least one version of each service when migrating to an SOA. Implementing the ultimate correspondence service is likely to take far longer than implementing a lightweight version. This could greatly reduce the amount of rework necessitated for applications developed early in the process before all the services are available.
- A lightweight package implementation is required early on in the SOA planning process anyway, in order to test out key concepts and educate developers in the new architectural practices.
- If carefully designed it might be possible to increase the degree of runtime decoupling in the architecture by building applications that can hot swap between the two services if one or other of them is not available. This might be valuable for applications with high availability requirements. This would depend on the application being able to make do with the functionality in the lite version of the service in an emergency. You could swap the other way from the full function to light version but you would obviously lose any productivity benefits you gained, as you now have to configure both services.
The downside of this approach of course is that you now have to maintain two shared services but this is still an improvement over each individual application coding its own functionality in each project. To summarize, when planning a migration path to an SOA, consider the benefits of implementing lite versions of each service early in the process and keeping them around even after more robust services have been implemented in order to reduce the overall complexity of application development.