Domain Model in Brief

This series is getting quite interesting so I decided to post something about Domain Model. Just a little introduction to understand what is and what is not Domain Model.

Honestly this pattern is often misunderstood. I see tons of examples of anemic models that reflect 1:1 the database structure, mirroring the classic Active Record pattern. But Domain Model is more than that …

Let’s start as usual with a definition, and we take this definition from one of the founder of the Domain Model pattern, Martin Fowler:

An object model of the domain that incorporates both behavior and data.

But unfortunately I almost never see the first part (behaviors). It’s easy to create an object graph, completely anemic, and then hydrate the graph using an ORM that retrieves the data from the database; but if we skip the logical part of the object graph, we are still far from having a correct Domain Model.

This means that we can have anemic objects that represent our data structure, but we can’t say that we are using Domain Model.

Our Domain Model

In order to better understand the Domain Model pattern we need a sample Domain, something that aggregates together multiple objects with a common scope.

In my case, I have an Order Tracking System story that I want to implement using the Domain Model pattern. My story has a main requirement:

As a Customer I want to register my Order Number and e-mail, in order to receive updates about the Status of my Order

So, let’s draw few acceptance criteria to register an Order:

  • An Order can be created only by a user of type Administrator and should have a valid Order id
  • An Order can be changed only by a user of type Administrator
  • Any user can query the status of an Order
  • Any user can subscribe and receive updates about Order Status changes using an e-mail address

If we want to represent this Epic using a Use Case diagram, we will probably end up with something like this:

image

Great, now that we have the specifications, we can open Visual Studio (well I did it previously when I created the diagram …) and start to code. Or better, start to make more investigations about our Domain objects.

It’s always better to have an iteration 0 in DDD when you start to discover the Domain and the requirements together with your team. I usually discover my Domain using mockups like the following one, where I share ideas and concepts in a fancy way.

Snapshot

Create a new Order

An Agent can created an Order and the Order should have a proper Order Id. The order id should reflect some business rules so it’s ok to have this piece of validation logic inside our domain object. We can also say that the Order Id is a requirement for the Order object because we can’t create an Order object without passing a valid Order Id. So, it makes absolutely sense to encapsulate this concept into the Order entity.

A simple test to cover this scenario would be something like this:

[Fact]
public void OrderInitialStateIsCreated()
{
    this
        .Given(s => s.GivenThatAnOrderIdIsAvailable())
        .When(s => s.WhenCreateANewOrder())
        .Then(s => s.ThenTheOrderShouldNotBeNull())
            .And(s => s.TheOrderStateShouldBe(OrderState.Created))
        .BDDfy("Set Order initial Status");
}

image

If you don’t know what [Fact] is, it is used by xUnit, an alternative test framework that can run within Visual Studio 2013 test runner using the available nuget test runner extension package.

From now on, we have our first Domain Entity that represents the concept of Order. This entity will be my Aggregate root, an entity that bounds together multiple objects of my Domain, in charge of guarantee consistency of changes made to those objects.

Domain Events

M. Fowler defines a Domain event in the following way:

A Domain event is an event that captures things in charge of changing the state of your application

Now, if we change the Order Status we want to be sure that an event is fired by the Order object, which inform us about the Status change. Of course this event will not be triggered when we create a new Order object. The event should contains the Order Id and the new Status. In this way we will have the key information for our domain object and we may not be required to repopulate the object from the database.

public void SetState(OrderState orderState)
{
    state = orderState;
    if(OrderStateChanged != null)
    {
        OrderStateChanged(new OrderStateChangedArgs(this.orderId, this.state));
    }
}

Using the Domain Event I can easily track the changes that affect my Order Status and rebuild the status in a specific point in time (I may be required to investigate the order). In the same time I can easily verify the current status of my Order by retrieving the latest event triggered by the Order object.

The ubiquitous language

With my Order object create, I need now to verify that the behaviors assigned to it are correct, and the only way to verify that is to contact a Domain expert, somebody expert in the field of Order Tracking System. Probably witht this person I will have to speak a common language, the ubiquitous language mentioned by Eric Evans.

With this language in place, I can easily write some Domain specifications that guarantee the correctness of the Domain logic, and let the Domain Expert verifies it.

image

This very verbose test, is still a unit test and it runs in memory. So I can easily introduce BDD into my application without the requirement of having an heavy test fitness behind my code. BDDfy allows me to produce also a nice documentation for the QA, in order to analyze the logical paths required by the acceptance criteria.

Plus, I am not working anymore with mechanical code but I am building my own language that I can share with my team and with the analysts.

Only an Administrator can Create and Change an Order

Second requirement, now that we know how to create an Order and what happen when somebody changes the Order Status, we can think of creating an object of type User and distinguish between a normal user and an administrator. We need to keep this concept again inside the Domain graph. Why? Well, very simple, because we choose to work with the Domain Model pattern, so we need to keep logic, behaviors and data within the same object graph.

So, the requirements are the following:

  • When we create an Order we need to know who you are
  • When we change the Order status, we need to know who you are

In Domain Driven Design we need to give responsibility of this action to somebody, that’s overall the logic that you have to apply when designing a Domain Model. Identify the responsibility and the object in charge of it.

In our case we can say to the Order object that, in order to be created, it requires an object of type User and verify that the user passed is of type Administrator. This is one possible option, another one could be to involve an external domain service, but in my opinion is not a crime if the Order object is aware of the concept being an administrator.

So below are my refactored Behavior tests:

image

The pre-conditions raised in the previous tests:

  • order id is valid
  • user not null
  • user is an administrator

are inside my Order object constructor, because in DDD and more precisely in my Use Case, it doesn’t make any sense to have an invalid Order object. So the Order object is responsible to verify the data provided in the constructor is valid.

private Order(string orderId, User user)
{
    Condition
       .Requires(orderId)
       .Contains("-","The Order Id has invalid format");
    Condition
       .Requires(user)
       .IsNotNull("The User is null");
    Condition
       .Requires(user.IsAdmin)
       .IsTrue("The User is not Administrator");

    this.orderId = orderId;
}

Note: for my assertions I am using a nice project called Conditions that allows you to write this syntax.

Every time I have an Order object in my hands I know already that is valid, because I can’t create an invalid Order object.

Register for Updates

Now that we know how to create an Order we need to wrap the event logic into a more sophisticated object. We should have a sort of Event broker also known as Message broker able to monitor for events globally.

Why? Because I can imagine that in my CQRS architecture I will have a process manager that will receive commands and execute them in sequence; while the commands will execute the process manager will also interact with the events raised by the Domain Models involved in the process.

I followed the article of Udi Dahan available here and I found a nice and brilliant solution of creating objects that act like Domain Events.

The final result is something like this:

public void SetState(OrderState orderState)
{
    state = orderState;
    DomainEvents.Raise(
        new OrderStateChangedEvent(this.orderId, this.state));
}

The DomainEvents component is a global component that use an IoC container in order to “resolve” the list of subscribers to a specific event.

Next problem, notify by e-mail

When the Order Status changes, we should persist the change somewhere and we should also notify the environment, probably using a Message Broker.

We have multiple options here, I can just picture some of them, for example:

  • We can associate an Action<T> to our event, and raise the action that call an E-mail service
  • We can create a command handler in a different layer that will send an E-mail
  • We can create a command handler in a different layer that will send a Message to a Queue, this Queue will redirect the Message to an E-mail service

The first two options are easier and synchronous, while the third one would be a more enterprise solution.

The point is that we should decide who is responsible to send the e-mail and if the Domain Model should be aware of this requirement.

In my opinion, in our specific case, we have an explicit requirement, whatever there is a subscribed user, we should notify. Now, if we are smart we can say it should notify to a service and keep the Domain Model loosely coupled from the E-mail concept.

So we need to provide a mechanism to allow a User to register for an Update and verify that the User receives an E-mail.

image

I just need a way to provide an E-mail service, a temporary one, that I will implement later when I will be done with my domain. In this case Mocking is probably the best option here, and because my DomainEvents manager is providing methods using C# generics, I can easily fake any event handler that I want:

var handlerMock = 
      DomainEvents.Container
         .Resolve<Mock<IHandles<OrderStateChangedEvent>>>();
handlerMock
      .Verify(x => x.Handle
                        (It.IsAny<OrderStateChangedEvent>()), 
                         Times.Once());

Now, if you think for a second, the IHandles interface could be any contract:

  • OrderStateChangedEmailHandler
  • OrderStateChangedPersistHandler
  • OrderStateChangedBusHandler

Probably you will have an Infrastructure service that will provide a specific handler, a data layer that will provide another handler and so on. The business logic stays in the Domain Model and the event implementation is completely loosely coupled from the Domain. Every time the Domain raise an event, then the infrastructure will catch it and broadcast it to the appropriate handler(s).

Conclusion

The sample shown previously is a very simple object graph (1 object) that provides behaviors and data. It fits perfectly into BDD because the business logic is behavior driven thanks to the ubiquitous language and it does not involve any external dependency (services or persistence).

We can test the logic of our Domain in complete isolation without having the disadvantage of an anemic Domain that does not carry any “real” business value. We built a language that can be shared between the team and the analysts and we have tests that speak.

Probably an additional functionality could be to design the Commands in charge of capture the intent of the user and start to test the complete behavior. So that we will have an infrastructure where the system intercepts commands generated by the User and use these command to interact with the Domain Model.

Again, even for Domain Model the rule is the same than any other pattern (architectural and not). It does not require a Data Layer, it does not require a Service Bus and so on. The Domain Model should contain behaviors and data, then the external dependencies are external dependencies …

Now, if you will do your homeworks properly, you should be able to have some good fitness around your Domain Model like the following one:

image