Saturday, April 12, 2008

Abstraction First

When designing services, the common wisdom is to opt for a contract-first approach, instead of an implementation-first one. There is no question that this is a valid approach but I think the emphasis should be put on the necessity to design a good abstraction first.

Consider this: technical implementations, especially in strongly typed languages, often result into a pollution of the client model by the service model. Interfaces or stubs used by a client to perform remote invocations can very easily become mixed with its own domain.

This creates a tension between a service provider and its consumers, as they often tend to drive the contract too much on their side because they consider the local crystallization of the contract as a part of their model. Exacerbated, this tendency can result in tight coupling between both parties.

Let me give you an old but typical example from my tumultuous past.

A little more than a decade ago, I worked on a corporate centralized contact management system. It was supposed to serve contact details (persons, organizations, addresses and whatnot) to all the applications in use in the company, including secretaries' word processors. Admittedly an interesting project, it in fact quickly turned to be a death march. I soon learned this was the sixth attempt of such an endeavor and that people wanted to see how a n00b like me would fare.

I then realized that each department wanted very different things out of this system and their views would not be reconcilable. I ended shipping a version that was only usable by the secretaries, which I think was a smart move as you must
always be good to them!

The next n00b was assigned the creation of version 7 of the contact manager, built on what I did with the goal to generalize it to all departments. Of course it failed and the project disappeared for ever. Maybe the mythical number 7 was to be reached before the whole stuff could have been killed.

At that time, if I would have known better, I think the best I could have done would have been to advocate for the deployment of an LDAP provider. Indeed a directory server accessed via this protocol does not try to be everything for everybody and does not present a contract that any application would consider using in its own domain model. Yet it offers a simple and powerful abstraction that an application can use to query directory information and then tie them with its own object model.

Let me quote Uncle Bob:
"Abstraction is the elimination of the irrelevant and the amplification of the essential"

To me this sounds almost like a caricature, where the most prominent features are made so obvious and visible that there is no doubt left about what really matters. A good abstraction for a service should then translate in clear intents and well defined boundaries, which would guide the creation of valuable contracts.

Finally, for all these existing services that want to invade your application domain, there are fortunately ways to remain insulated. For example you could:
  • use dynamic language scriptlets to perform remote invocations and set values on your local domain,
  • use Dozer to tie client stubs and your objects,
  • consider invocation responses as raw XML and extract values out of them with XPath.

1 comment:

David Dossot said...

As a note to myself, I just realized that real brains like Arjen Poutsma came to the same conclusions regarding lax invocation.

He blogged about this in March 2007.

For the record, this idea of moving away from the usage of crystallized web service clients started to grow in me in 2006, when I was wading through the J2EE web services spaghetti plate festival.