Geeks With Blogs
Greg Young Greg.ToString()

I have been seeing alot of questions lately in regard to context boundaries within domains and various methods of implementing the contracts between them. I figured it may be worthwhile to write up a little about the various mechanisms of handling this issue.

For those who are unaware of what a context might be, a classic example would be a marketting domain that needs to access an accounting domain in order to perform some operation (or to retrieve some information). We seperate these domains as there is an obvious natural breaking point between the two and often it will in fact be two seperate teams implementing the domains which can often be two seperate systems.

In dealing with this issue alot of focus will be on the contract that is being exposed from the second domain (the producing domain) to the first domain (the consuming domain). In general our goal will be to make that contract as thin as possible in order to isolate the first domain from changes in the second.

The first step in minimizing our contract width will be to create a facade representing the functionality we wish to use from the domain either in the originating domain or within an encapsulating library. Depending on how we connect the operations together (discussed further below) using an encapsulating library can be an extremely powerful method of limiting the width of our contract with the consuming domain. In general we want to use an encapsulating library unless we are using a further decoupling method discussed later and have direct access to the originating domain.

Once this facade is created; we need to create a method for the consuming domain to access the newly created facade.

Shared Database Access

Although a bit off topic (no facade) this is generally a "no no" I felt was worthwhile to mention as it seems to sprout up quite a bit. In some situations, we are forced down this route because the producing domain is an application provided by a 3rd party which does not contain an API. If we are to do this we must actually build our own API to the system and keeping the systems in synch through upgrades etc can be an extremely time consuming process. We also run a grave risk of getting data incorrectly from the other system because we do not know all of the business rules that the application is providing, due to this; this model should be avoided at all costs when WRITING to the other domain as you could possibly create data that the other domain is incapable of handling thus cauaing the other application to fail upon reading our data.

Direct Access

The most obvious answer is to have the domains directly access each other forming a coupling between the domains. This can be a good solution at times, such as when we manage both domains and there is alot of intermingled behavior. The largest issue is that when we simply add a direct reference to the other domain; we consume not just the contract of the facade that we are interested in and its related objects but instead the entire public contract of the originating domain. This can be easily worked around with disciplined engineers who know to only use a certain area of the contract but it leaves the possibility of broadening this contract open to people who are in the domain.

Another large issue that exists with the direct access methodology is that the libraries for the producing domain must now be managed and shipped in conjunction with the consuming domain. If not carefully monitorred this situation can bloat quickly as every change to a producing domain will force an upgrade to all using the consuming domain. An example of this can be seen in a windows forms application in that it would need to be "re-released" every time a change was made to the accounting domain so that the clients have the correct version. A similar issue exists in the possible race condition that can occur if a change is not backwards compatible (a perfect example would be that the domain now must insert a new mandatory 1-1 relation which the previous version will receive a SQL failure from)

Remote Calls

In order to get around the hassle of trying to manage these releases for clients is to place (or wrap) the facades as services. By placing them into stand alone services we prevent ourselves from having to update the clients everytime a change is made, instead we simply update the service itself. Since the service and the client have a strong contract between the two of them, any non-contract changing upgrade to the server will not require a change to the clients consuming the service.

Remote calls can be made in many ways but the best fit for many circumstances is a webservice.

Webservice (SOA)

In .NET when I create a webservice, a WSDL is created based upon the types I am returning (in many cases these may be my domain objects or may be specificly limited DTOs (Data Transfer Objects)). When I add a webservice to my project, the WSDL is read and a proxy class is created. Along with the proxy class, shell classes that represent the objects on the other side are created. This process offers huge benefits in terms of decoupling because the consuming domain is not operating on the actual types within the producing domain but instead upon its own local types which happen to have the same XML layout when serialized. A large benefit of webservices is that they are language/platform agnostic (the accounting system could be implemented in java running on an IBM mainframe while the marketting domain could eist in .NET on a windows machine)

When a change to the contract is made, a re-generation of the WSDL and the proxy will be required. As this is an "semi-automated" task the amount of overhead in changing the contract is fairly limited but will as all RPC does require a change to the clients as well as the service.

Webservices should in general be the preferred method of connecting contexts in a synchronous pull type environment as they create a wonderful level of abstraction between the two contexts. They do carry a bit more overhead than remoting but in general the flexibility gained easily makes up for the performance lost due to the larger size of serialization.

Remoting

In .NET remoting types are shared between the two domains. The consuming domain and the producing domain must share atleast some level code. Not only classes can be shared; it is a common pattern to define only an interface for the facade within the shared code. There are three large benefits to using remoting as opposed to say webservices.

The first benefit is binary serialization, remoting with binary serialization will use far less bandwith than the XML based messaging used by webservices.

The second benefit is the ability to asynchronous messaging (aka events). The producer can push events out to the consumer as opposed to having to implement a synchronous delta based polling mechanism. A perfect example of where this can be useful is if the marketting system were interested in a particular type of booked item being created in the accounting system.

Many patterns can easily be implemented accross remoting because the end points are sharing a code base.

These benefits come at the cost of being non-platform agnostic.

MSMQ

A queuing solution such as MSMQ can be another method to move data between contexts. A queuing solution can guarentee data arrival to the other domain of a call. Since queuing is by its very nature asynchronous, it is best used when the operations being pushed are also asynchronous. An example of such a method can be seen if the marketting system wanted to tell the accounting system that a sale had been made but did not care about any information in return from this operation (in other words it is NOTIFYING the accounting system).

Queuing solutions have become quite advanced in their functionalities allowing such things as load balancing multiple servers, message scheduling, and often times even include generic tools for common admin tasks such as viewing or managing the queues. They also offer the ability to define events from a given domain allowing the domain to be contently oblivious of who is consuming those events (I am sure some people are thinking command pattern combined with observer as a ncie generic way of doing this ... it is)

The disadvantages to queuing are directly related to it's asynchronous nature ... performing synchronous operations such as GetOrdersByDate(). An operation such as this would actually consist of 2 asynchronous operations, often times this type of behavior is not desired.

Once we have determined our method of transport between the domains, we create a service (facade) in the consuming domain in order to abstract the rest of our domain from the methology we have chosen.

Tomorrow (if I can find time) I will try to dicuss a bit more in depth methods to help limit the physical contract width of the service to help reduce coupling between the domains.

Posted on Monday, March 20, 2006 10:12 AM | Back to top


Comments on this post: Domain Context Seperation : Transport Mechanisms

No comments posted yet.
Your comment:
 (will show your gravatar)


Copyright © Greg Young | Powered by: GeeksWithBlogs.net