Monday, May 19, 2008

Layered Service Models are Bad

Open any number of books out there on SOA and you'll find guidance on defining the service model for your enterprise in terms of process, task and entity services. This in essence sets up three layers of services, with process services as the top layer, task services underneath the process services, and entity services at the bottom.

The purpose of entity services is to provide an abstracted view of business document repositories. The actual structure of the underlying data and the platform holding the data are abstracted into the form of entity service contracts.

The operations exposed by entity services are your basic CRUD centric operations such as GetCustomer, GetOrdersForCustomer, UpdateCustomer and DeleteCustomer.

Task services each represent a single atomic business action. Task services leverage entity services to manage state.

Process services are then created in support of business processes. Each process service wires up any number of task services in support of a specific business process. Process services can also "invoke" other process services when there are sub-processes to be reused by those processes.

Consider the following two vastly oversimplified business processes:

Policy Creation
This process involves the creation of a new policy. An underwriter uses a composite application to first go and get a premium quotation, and then if the customer accepts the premium create a new policy.

Policy Reinstatement
This process involves reinstating a previously cancelled policy.

Note that the Allocate Commissions and Raise Invoice tasks are "reused" between the Policy Creation and Policy Reinstatement processes.

Translated into a service model based on process, entity and task services, we get the following:

For those who follow this blog, you would probably guess that I'm dead against this kind of service model. There are so many problems with this model it's hard to even know where to start:

Transactionality: The task services must perform updates across numerous entity services. The task services are atomic in nature, which means that either the entire task must succeed or fail. This means we need to have cross-service transactions between entity services.

As I've explained in previous posts, cross-service transactions are bad for performance reasons and because they hurt the autonomy of services. One entity service can have records locked while waiting for another entity service to either commit or rollback its local transaction. One entity service can heavily influence the execution of another.

Performance: As mentioned above, cross-service transactions hurt performance. However, the other thing to notice about this architecture is that it is full of synchronous request-reply communications. This approach simply does not scale.

Robustness: As I've mentioned previously, synchronous request-reply interactions between services seriously hurts the robustness of your architecture. If one of those entity services goes down, you can pretty much say goodbye to a large number (perhaps even the majority) of systems in your enterprise.

Cohesion: With this service model, multiple services deal with very similar business concepts. You have the same entities being managed by multiple services. You have multiple task services dealing with the same entities. This means you are likely to get considerable duplication of logic and information representation between services.

This means your developers need to write considerably more code. Furthermore, the communication between services is likely to be very chatty, involving a large number of finely grained messages.

This in turn means greater coupling between services. This results in even more code to be written in order to handle the vastly increased number of message types. In essence, the proposed services in this model are too finely grained.

Coupling: As mentioned above, the low cohesion between services means greater coupling. You also get temporal coupling as a result of all the synchronous request-reply communications.

Complexity: There are simply too many services defined in this service model. With this approach, you will likely end up with hundreds or even thousands of services supporting an entire enterprise - each with dependencies to be managed and understood.

Encapsulation: By exposing data directly via entity services, any service can update any data in whatever way they see fit. This results in very poor encapsulation. We want our data to be surrounded by business logic that enforces our business rules.

Service Contract Stability: The implementation details of cohesive business processes are exposed in the service contracts of the task and entity services. As the needs of the process services they support change, the service contracts will need to be updated. I'll cover service contract stability in another post.

People are usually allured into using this kind of service model by the promise of reusability. That is in fact the fundamental premise of the architecture - that process, task and entity services can by simply reused by dropping boxes that invoke those services onto a process orchestration design surface.

However as I've previously discussed, the promise of this kind of reuse is false. It is all very good in theory, but as usual the devil is in the detail and you simply don't get this kind of reuse in practice.

In conclusion, services should be self contained; aligning with cohesive business areas/capabilities. The concerns of a single cohesive business capability should be supported by a single service. Not by many process, task and entity services.

In my next post, I'll describe the service model that I would suggest to support these business processes, so stay tuned!


Philohobo said...

(YAGP) Yet another great post, Bill. Your blog has been a godsend to this SOA-newby. I recently went down this path (layered services) for a design and thought 'this is way too complex to build and maintain'. I look forward to your recommendations.


Anonymous said...

I going to have to empty my cup of tea and relearn. ;) Another brilliant post Bill. I have always gone down the layered service approach and have had problems. I look forward to your next post.

So when are you going to publish a book? :)

Bill said...

Hi Peter,

Thanks for your kind words. I too years back considered going down this road, but could see it would have taken a huge amount of effort only to produce an unmaintainable and fragile mess.

It illustrates how important it is to critically assess everything you read rather than just take it all on face value.


Bill said...

Hi Dave,

Actually I'm strongly considering starting work on a book at some point later in the year. :)


Anonymous said...

Another good post thanks Bill.

I wonder if you would be able to give us a diagram of how this architechture should look the way you describe it? I for one would find it helpful.



Bill said...

Hi Dirk,

My next post illustrates the service model I would suggest for this example.


Unknown said...

A book?!!? Do it, would be great!

Anonymous said...

I think this topic would make for a great debate with somebody like Thomas Erl, who's clearly a proponent of a layered architecture. What would it take to make that happen? :-)

Bill said...

Hi Troy,

Yes I'd thoroughly enjoy the opportunity to discuss this with Thomas Erl. No idea what it would take to make it happen though. I've been hoping to catch up with him at a conference somewhere but it hasn't happened as yet. Fingers crossed though!


jeff said...

It seems like a few of your concerns are orthogonal to a layered service architecture.