Saturday, March 16, 2013

Simplifying design with Domain Events

Following post notes down how I used the concept of Domain Events to refactor the message processing component of an Enterprise Web Application. The outcome was great where the main achievements was a code base which was easier to maintain. The 'All hell break loose' kind of classes were gone, and instead a compact, self-explanatory, rich set of new classes were born.
The inspiration for the refactoring is this MSDN article from Udi Dahan.

Problem :
Managing a business process where multiple domain object updates are taken place. Depending on the new state of the domain, there are additional tasks to be performed.
E.g: Notifying stake holders about a milestone being reached.

Goals :
Encapsulate business logic to the Domain Model as much as possible while;

  • Not increasing the complexity of the code
  • Keeping the code testable
  • Keeping the code robust for future changes

Existing Solution:

  • All of the domain object updates (domain logic) sits safely within domain objects.
  • How ever there were lots of other business logic leaking out of domain objects. These were mainly reactions to the new state of the domain. Most of them were cross cutting operation that can't be attributed to a domain object thus ended up in the Service layer. To be honest for simple cases this might not be a problem, however as your code base gets more and more complex this becomes the class everyone wants to hate. Have a look;

Although the domain logic is nicely encapsulated in the domain object (Order) there are few problems with this code.

  • Complexity of the Service Layer will increase with time making it harder and harder to introduce changes
  • Same business logic (i.e What to do when an order is confirmed) may be required in another part of the application paving way for redundancy

Solution with Domain Events:
Rather than orchestrating the event dispatch logic in the Service layer,  the logic is modeled with events inside the domain it self. Each event and it’s handlers are separated to its own class which minimizes and transfers the complexity from 1 single class/method to a collection. (Note: 1 event could have more than 1 handler). All of the handlers extend a marker interface which is used by the dependency injection framework (In my case, Unity) to resolve the classes that handle a particular event.

Here’s the base class for all handlers

The following set of classes show how we can decompose different events and their respective handlers into their own classes.
The domain entities (Or any other class for that matter) should be able to raise these events easily, responding to different business conditions. This is achieved by having a generic static class exposing a Raise method as follows.

Here's how the domain entity has regained control of the situation by raising events as responses to business conditions internal to it. At the same time have a look at how bare bone the service has become.

NOTE:Here’s how you configure multiple implementations for the same interface using Unity.

QUESTION: How can we extend this design to handle events that respond to business states that depend on multiple domain objects? (E.g. Order is cancelled and User is a premium customer) 
Post a Comment