I’ve spent some time recently renewing my old DDDSample.NET project. I understand that it is the projection of my subjective and uninformed view of Domain-Driven Design, but still I see a value in having some implementation compared to having nothing — it provokes discussion. That’s why I will continue to invest my time in it. If you happen to read this and want to take a look at the code, please remember that is is a sample (as the name suggests), not a guidance. The difference is following: a sample shows how I am doing things while a guidance would show how you are supposed to do things.

Journey through the stack trace

Classic version of DDDSample is a web application with simple UI created with ASP.NET MVC. This is where all starts. I would like to take you on a journey through the stack trace to explain various architectural decisions. Let’s register a new handling event.

NHibernateAmbientSessionManager

The very first class that gets a chance to process the request is NHibernateAmbientSessionManager. It is responsible for creating an ambient NHibernate session that will be bound to the request. After processing the request the session is released. It can be accessed anywhere in the code statically through CurrentSessionContext class. This is a built-in feature of NHibernate.

public void CreateAndBind()
{
    CurrentSessionContext.Bind(_sessionFactory.OpenSession());
}
public void UnbindAndDispose()
{
    var session = CurrentSessionContext.Unbind(_sessionFactory);
    if (session != null)
    {
        session.Dispose();
    }
}

HandlingController

Next is the HandlingController and it’s RegisterHandlingEvent method/action

[AcceptVerbs(HttpVerbs.Post)]
public ActionResult RegisterHandlingEvent(string trackingId, DateTime? completionTime, string location, HandlingEventType type)
{
    if (!completionTime.HasValue)
    {
        ViewData.ModelState.AddModelError("completionTime", @"Event completion date is required and must be a valid date.");
    }
    if (!ViewData.ModelState.IsValid)
    {
        AddHandlingLocations();
        AddHandlingEventTypes();
        return View();
    }
    _handlingEventFacade.RegisterHandlingEvent(completionTime.Value, trackingId, location, type);
    return RedirectToAction("Track", "Tracking", new { trackingId });
}

There’s nothing fancy here, but is shows in a nice way that in this design, the responsibility of a controller is data validation and parsing (mostly done by MVC internals). After ensuring that data conforms to the required format, it is passed to another class which is…

HandlingFacade

This class hides the design of internals of the application from the UI. As far as controllers are concerned, business logic is implemented in façade’s methods. The truth is slightly different, however.

public void RegisterHandlingEvent(DateTime completionTime, string trackingId, string location, HandlingEventType type)
{
    var command = new RegisterHandlingEventCommand
                        {
                            CompletionTime = completionTime,
                            TrackingId = trackingId,
                            OccuranceLocation = location,
                            Type = type
                        };
    _pipelineFactory.Process(command);
}

All the façade is doing is packing the arguments into a command object and sending this command to the pipeline where it is processed. Why create a separate class instead of putting this method on the controller? I like my controllers to be concerned only by the UI and have only one reason to change.

NHibernateTransactionCommandFilter

Before the command is actually executed, a number of filters are invoked. I use a very simple command pattern implementation I’ve written a few weeks ago for the sole purpose of using in DDDSample. It allows me to define these filters in a nice (again, subjective view) way

public void OnHandling(object command)
{
    _ambientSession = CurrentSessionContext.Unbind(_sessionFactory);
    _session = _sessionFactory.OpenSession();
    _transaction = _session.BeginTransaction();
    CurrentSessionContext.Bind(_session);
}
public void OnHandled(object command, object result)
{
    CurrentSessionContext.Unbind(_sessionFactory);
    _transaction.Commit();
    _session.Close();
    CurrentSessionContext.Bind(_ambientSession);
}

Before handling a command an aforementioned ambient NHibernate session is unbound from the current context. We are not going to use it while processing the command because we need a clear workplace. We open a new session and a a new transaction. Whatever happens in the command handler, stays in the command handler. After a command succeeds we unbind the session it used and commit the transaction. Then we restore the ambient session so that UI can use it.

Why don’t we just use a transaction on this ambient session? There is a couple of reasons. First, there can be a transaction started before processing the command and we don’t want to take part in it. Second, we want to be absolutely sure we don’t have any entities in the session-level cache. Why? Because we might use some hints to fetch them more efficiently in context of command processing (like for example force eager load on some relations). And last but not least, if command fails we don’t want to break the session UI was using because it may need it for whatever reason after the command processing attempt failed.

The corollary of this is, we don’t want to put any persistent (tracked by NHibernate) into the command. If we allowed this, we could attach it by mistake to this other session and very strange things could happen. The side effect is we can safely serialize commands which allows us, if the need comes, to put our domain model on a separate tier then its client (the web application).

RegisterHandlingEventCommandHandler

When we have the new session and transaction in place it’s time to do the actual work. Here’s how a typical command handler look like

public object Handle(RegisterHandlingEventCommand command)
{
    var trackingId = new TrackingId(command.TrackingId);
    var cargo = _cargoRepository.Find(trackingId);
    var occuranceLocationUnLocode = new UnLocode(command.OccuranceLocation);
    var occuranceLocation = _locationRepository.Find(occuranceLocationUnLocode);
    var evnt = new HandlingEvent(command.Type, occuranceLocation, DateTime.Now, command.CompletionTime, cargo);
    _handlingEventRepository.Store(evnt);
    return null;
}

The idea here is to have only one method or constructor invocation on an Aggregate Root in one command. As you can see, command handler’s responsibility is to convert the raw data from the command to the proper Value Objects. The validation of data is performed when constructing VOs. In this case we create a new AR so we first instantiate a new object and then call repository to store it.

HandlingEventRepository

What happens in the repository?

public void Store(HandlingEvent handlingEvent)
{
    Session.Save(handlingEvent);
    _eventPublisher.Raise(handlingEvent);
}

Two things. First, we save the newly created AR to the command’s session. Then we use an Event Aggregator to publish this AR as an event. I based this approach on Eric Evans’ What I’ve learned about DDD since the book presentation where he explains that in many domains you encounter Aggregate Roots that are immutable. He calls them Events.

CargoWasHandlerEventHandler

The Event Aggregator publishes the event to all interested parties. In our case there is only one

public void Handle(HandlingEvent handlingEvent)
{
    handlingEvent.Cargo.DeriveDeliveryProgress(handlingEvent);
}

It calls a method on a Cargo Aggregate Root to notify it about the event. One thing worth notice here is we are doing it synchronously in the sample but our contract does not guarantee synchronicity. We write our event handlers in such a way that they can be executed asynchronously to the transaction that published the event. It is good to have such possibilities open in case we need to scale.

Cargo

This is how we reach the Cargo AR

public virtual void DeriveDeliveryProgress(HandlingEvent lastHandlingEvent)
{
    Delivery = Delivery.DerivedFrom(RouteSpecification, Itinerary, lastHandlingEvent);
}

The method looks very simple and it is not a coincidence. In classic DDD we have limited testing options since we can’t set our Entities to proper state easily (as easy in if we use Event Sourcing). That’s why we don’t want to test Entities. We want to test Value Objects because they are immutable and truly persistence ignorant. All we do in an Entity is pass the arguments to a VO and replace the current value with a new one. The probability that we make a bug in this one-liner is small, at least I hope so.

Delivery

Finally we arrived at our destination, the Value Object. Here I won’t include any code as it is quite complex and lengthy. I’ve already said probably the most important thing about VOs in this approach: they are immutable. This property allows us to test them easily. The compromise we are willing to accept in regards to Value Objects is, we expose their state via properties. Because we don’t have Command and Query Responsibility Separation, we use same objects (but remember, fetched via different session) to read and to write.

Summary

I hope you enjoyed this journey through the layers of the onion. Remember that this is just a sample. Most of its features were tested in the field but some combinations of them were not. I am eager to hear what you think about this approach and also to hear about your approach to DDD when size and/or complexity does not justify CQRS.

VN:F [1.9.22_1171]
Rating: 5.0/5 (3 votes cast)
Classic DDD example, renewed, 5.0 out of 5 based on 3 ratings