Wherein our narrator makes a fortuitous discovery in a most unexpected place.
One of the struggles I face in trying to explain my objections to the Indigo API is creating concrete examples of the abstract, and sometimes seemingly abstruse, notion I have that the Indigo API itself leads developers down the wrong path in building distributed applications. It's easy to come up with scenarios that demonstrate the ideas, but these scenarios often seem forced and are always open to the criticism that they're contrived specifically to prove my point. Imagine my delight and surprise when a post showed up in my aggregator that perfectly illustrates my argument and that post is written by a Microsoft expert in API usability. Please take a few moments to read and ponder the significance of this
post by Steven Clarke. Now, I think Steven drew the wrong lesson from his experience, but before we get to that, let's take a look at the situation he set up. He has some UI programmers using data binding to link the UI to a backend Indigo service. This is a key scenario for SOA. In this case the problem domain is an album list. I'm going to assume (based on the names of the methods in his interface) that this is a personal list of music albums. Steven's understanding of his problem is that he made errors in the way he maintained state within his service and the assumptions that the UI programmers made. To understand how fundamentally wrong this is, we need to think a bit about the problem domain, the interface he exposed, and how the Indigo API enabled him to create the situation.
An album list is rather obviously a document. Except that to many software architects and developers, that's not obvious at all. The database folks will immediately think of a relational model and the OO crowd will think in terms of objects and their methods (state + behavior), but normal people will naturally have a conceptual model of a document. It is absolutely critical to maintain the document oriented view if you want to be build excellent distributed applications. The main reason that service orientation is the best way to build distributed applications is that it provides an effective way to map document-oriented business processes onto the physical constructs of a computer network. The basic principles of service orientation have been around as long as the pyramids of Giza. Indeed, they enabled the ancient Egyptians to build the pyramids. The system they used was based on the same asynchronous messaging architecture that I use to build systems today. Granted, their messages were either verbal or written on papyrus in hieroglyphics, their network used people to physically move those messages, and the services were all performed manually, but from an abstract systems view, it is the same.
Unfortunately, the current Indigo API doesn't encourage a document oriented approach to service design. Take a look at Steven's service contract:
[ServiceContract(Namespace = "http://Usability.Task")]
interface IAlbumService
{
[OperationContract]
Album[] GetAlbumList();
[OperationContract]
void AddAlbum(string title);
[OperationContract]
int GetNumberOfAlbums();
[OperationContract]
void SellAlbum(string title);
}
Now, if you're a veteran of the global struggle against rampant unscalability, you'll immediately see issues with this design. The AddAlbum method is the very definition of a chatty interface. And if you don't think scalability matters for an album list, I'd just point you this
guy. More fundamentally, this interface confused the UI developers it was supposed to support. I don't think you place the blame for these problems with Steven Clarke. He's clearly a very intelligent guy. I've learned a lot from his writings on API usability. Nor can we write this off to inexperience. He's been working with Indigo as long as anybody. I think the fault here clearly lies with the API itself. What I find most interesting about Steven's post is Steve Swartz's advice. Unlike most Indigo developers, Steven has direct access to the Indigo architects. Steve's advice is very standard RPC thinking. He presents two choices. The first is add Open and Close methods to the API to represent the state management. The second is to add a parameter to each function to represent a session identifier. Both of these solutions pollute the service interface with details that are irrelevant to the problem domain and force the service to relinquish some its autonomy to the service consumer.
There is a better way. Microsoft's own Patterns and Practices group calls it the
Document Processor pattern. If you apply that pattern, you get an interface that would look more like this:
[ServiceContract(Namespace = "http://Usability.Task")]
interface IAlbumService
{
[OperationContract]
AlbumList GetAlbumList(string Owner);
[OperationContract(IsOneWay = true)]
void StoreAlbumList(AlbumList Albums);
}
This is a huge improvement over the original API. No need for Open and Close methods, no extraneous session id parameters, and no chatty calls. But there is still a problem. I wouldn't want to tie up my pretty Avalon UI while waiting on Brad's 1000+ album list to come back from the service. Other implementers of the service caller might choose to block on that call, especially if the service caller isn't a UI. Unfortunately, the async design of Indigo is totally messed up. It's based on the async pattern of the .Net framework which is a pattern for calling synchronous local methods asynchronously. There is a much simpler approach that's possible when you realize that all network traffic is fundamentally asynchronous and that only the caller is able to make the choice whether or not its code should block waiting for the response. I'll outline this approach in my next post.
Posted
Sep 04 2005, 01:18 PM
by
john-cavnar-johnson