DDD applied

Introduction

In my last post DDD revisited I talked about what is important when using domain driven design (DDD) as an architectural pattern. I have had the pleasant surprise that this post was event mentioned on InfoQ. Today I want to discuss and show in a realistic context how DDD can be applied. As with CQRS, DDD does not imply any specific additional architectural patter, tooling or infrastructure.

The domain

In this post I will concentrate on the domain of personal loans. A person with a regular income and a decent credit score can apply for a personal loan to e.g. finance a new car or a trip around the world to name just a few possibilities. This domain is of sufficient complexity to justify the use of domain driven design (DDD).

Ubiquitous language

When talking with subject matter experts one can start to identify nouns and verbs that are used in all discussions when talking about the business (processes). In our particular domain we might identify specifically one noun that is mentioned over and over again. This noun is Loan Application. We might also identify other nouns that come up like Prospect, Customer, Lead, etc. On the other hand we hear domain experts using verbs like

  • start (a loan application)
  • submit (an application)
  • approve, withdraw, etc.
Let’s concentrate on the Loan Application for now. When talking about such a “thing” we get to know that part of it are personal infos of the applicant like first and last name as well as date of birth, social security number, job, salary, etc. Other information that is part of a loan application is financial data like requested loan amount, type of loan, etc. All these attributes or properties will be part of the Loan Application “thing”.

Implementation

When it comes to the implementation of the domain using DDD the nouns will become aggregates and the verbs the actions executed upon the aggregates. Normally this is equivalent to the methods we implement in an aggregate. Of course aggregates do not live in isolation and some infrastructure is needed around the aggregates. Those other parts will be application services, repositories, APIs, etc. to just name the most important ones.

Contracts

When talking about contracts I am referring to commands, events and interfaces. These are the elements with which the elements of the domain (model) communicate with the outside world. Here the outside world can be the user interface or another system. Commands most often are triggered by user action. They transport the intent of the user. Each command has exactly one target in the domain. The target can either accept the command and execute it or refuse it.

Events tell “the world” that something (interesting) has happened. Events can have zero to many listeners that react to the event. Events are things that have happened (in the past) and thus cannot be refused. History cannot be undone. Interested listeners have to just accept the fact that this particular event has happened.

Interfaces are the connection points over which different components interact. Usually messages are exchanged over such connection points. Here message is a common denominator for either a command or an event.

The aggregate

Let’s start with the aggregate. This is the component where the interesting stuff happens. Here we find all the business logic that is specific to the context the aggregate represents. The aggregate is infrastructure agnostic. It doesn’t care where it comes from and where it goes. The aggregate is very self-centric and doesn’t care about it’s environment. The aggregate has no dependency to any infrastructure component and it encapsulates its state; that is, the state is private to the aggregate and not directly accessible from outside.

I start by defining the aggregate as a class named according to the noun I identified in the ubiquitous language (loan application) with a post fix aggregate. The aggregate has a constructor

public class LoanApplicationAggregate : IAggregate
{
	private LoanApplication _state;
	
	public LoanApplicationAggregate(LoanApplication state)
	{
		_state = state;
	}
}

As you can see the constructor expects one parameter which is the state of the aggregate. I prefer to define the state as an encapsulated object containing all the properties necessary to define the aggregate. The aggregate implements the following interface

public interface IAggregate
{
	object GetState();
	// more members...
}

Now for each verb that I identified in the ubiquitous language I define a method on the aggregate. Let’s take the verb withdraw as a sample.

public class LoanApplicationAggregate : IAggregate
{
	private LoanApplication _state;
	
	public LoanApplicationAggregate(LoanApplication state)
	{
		_state = state;
	}
	
	public void Withdraw()
	{
		// code needed to withdraw this loan application
	}
}

This method has no parameters. Another sample would be the verb accept (offer)

public class LoanApplicationAggregate : IAggregate
{
	private LoanApplication _state;
	
	public LoanApplicationAggregate(LoanApplication state)
	{
		_state = state;
	}
	
	public void Withdraw()
	{
		// code needed to withdraw this loan application
	}
	
	public void AcceptOffer(int offerId)
	{
		// code omitted
	}
}

in this case the method has one parameter, namely the id of the offer that the user accepted for his loan.

The application service

Each aggregate needs a host which provides it the necessary infrastructure. The application service is this host. This service is among other responsible to re-hydrate the aggregate from storage and after acting upon it to persist the changes back to the storage. The application service also provides the aggregate with the necessary (helper) services if needed and facilitates the collaboration of more than one instance of an aggregate where appropriate.

public class LoanApplicationService
{
	public void When(WithdrawCommand cmd)
	{
		var aggregate = repository.GetById<LoanApplicationAggregate>(cmd.Id);
		aggregate.Withdraw();
		repository.Save(aggregate);
	}
}

The service implements a public method called When with one parameter, which is the command we want to handle – in this case the Withdraw command. In the method we use the repository to re-hydrate the aggregate from storage using its unique ID which must be provided by the command. Then we act upon the aggregate and finally we use the repository again to persist (the changed state of) the aggregate back to the storage. Any other command we handle very similarly, here the accept offer command as a sample

public class LoanApplicationService
{
	public void When(WithdrawCommand cmd)
	{
		var aggregate = _repository.GetById<LoanApplicationAggregate>(cmd.Id);
		aggregate.Withdraw();
		_repository.Save(aggregate);
	}
	
	public void When(AcceptOfferCommand cmd)
	{
		var aggregate = _repository.GetById<LoanApplicationAggregate>(cmd.Id);
		aggregate.AcceptOffer(cmd.OfferId);
		_repository.Save(aggregate);
	}
}

Since all methods look somewhat the same we can refactor this class like so

public class LoanApplicationService
{
	public void When(WithdrawCommand cmd)
	{
		Execute(cmd.Id, agg => agg.Withdraw());
	}
	
	public void When(AcceptOfferCommand cmd)
	{
		Execute(cmd.Id, agg => agg.AcceptOffer(cmd.OfferId));
	}
	
	private void Execute(Guid id, Action<LoanApplicationAggregate> action)
	{
		var aggregate = _repository.GetById<LoanApplicationAggregate>(id);
		action(aggregate);
		_repository.Save(aggregate);
	}
}

This reduces the amount of code needed significantly.

Persistance

In our imperfect world where computers can shut down due to hardware failure or power outage we need to have a means to persist the state of our domain model or more specific of our aggregates. In DDD we most often use the repository pattern to provide persistance. The repository object abstracts the underlying storage technology to the domain. The repository can be used to load or re-hydrate an aggregate from storage and to save or persist it (or its state) to the storage.

Our repository implements the simple interface

public interface IRepository
{
	T GetById<T>(object id);
	void Save(IAggregate aggregate);
}

Only two methods are needed, the one to re-hydrate an aggregate instance and the other to persist the changes (in the state) of the aggregate.

The implementation of the repository depends on the storage mechanism or library used for persistance. If we use NHibernate a simple implementation could look like this

public class NHibernateRepository : IRepository
{
	private ISession _session;
	
	public NHibernateRepository(ISession session)
	{
		_session = session;	
	}
	
	public T GetById<T>(object id)
	{
		var state = _session.Get(id);
		var aggregate = Activator.CreateInstance(typeof(T), new object[]{state});
		return (T)aggregate;
	}
	
	public void Save(IAggregate aggregate)
	{
		var state = aggregate.GetState();
		_session.Save(state);	
	}
}

The API

The messages are fed into the domain through some API. This can be e.g. a REST-ful API, a message bus handler or even an RPC style interface. In this case let’s assume that we have a REST-ful API implemented using the ASP.NET Web API. An implementation using Node JS and Express JS would be very similar to achieve.

Here is how I implement a REST-ful API. I am using attribute routing to make the definition of (arbitrary) endpoints super easy. In the following snippet I defined the two endpoints for withdraw and accept order

public class LoanApplicationsController : ApiController
{
        [Route("{applicationId}/withdraw")]
        [HttpPost]
        public void Post(Guid applicationId)
        {
            //code omitted
        }
        
        [Route("{applicationId}/acceptOffer/{offerId}")]
        [HttpPost]
        public void Post(Guid applicationId, int offerId)
        {
            //code omitted
        }
	
}

The controller is only an API component and does nothing else that immediateley forward control to the application service which hosts the target aggregate.

public class LoanApplicationsController : ApiController
{
	LoanApplicationService _appService;
	
	public LoanApplicationsController(LoanApplicationService appService)
	{
		_appService = appService;
	}
	
        [Route("{applicationId}/withdraw")]
        [HttpPost]
        public void Post(Guid applicationId)
        {
        	var cmd = new WithdrawCommand{Id = applicationId};
            	_appService.When(cmd);
        }
        
        [Route("{applicationId}/acceptOffer/{offerId}")]
        [HttpPost]
        public void Post(Guid applicationId, int offerId)
        {
        	var cmd = new AcceptOfferCommand{Id = applicationId, OfferId = offerid};
            	_appService.When(cmd);
        }
}

Summary

In this post I have presented a sufficiently complex context in which the application of DDD can make sense. I have shown for this particular context which part comprise the domain and how I implement each part.

About Gabriel Schenker

Gabriel N. Schenker started his career as a physicist. Following his passion and interest in stars and the universe he chose to write his Ph.D. thesis in astrophysics. Soon after this he dedicated all his time to his second passion, writing and architecting software. Gabriel has since been working for over 25 years as a consultant, software architect, trainer, and mentor mainly on the .NET platform. He is currently working as senior software architect at Alien Vault in Austin, Texas. Gabriel is passionate about software development and tries to make the life of developers easier by providing guidelines and frameworks to reduce friction in the software development process. Gabriel is married and father of four children and during his spare time likes hiking in the mountains, cooking and reading.
This entry was posted in architecture, DDD, How To. Bookmark the permalink. Follow any comments here with the RSS feed for this post.
  • Pingback: The Morning Brew - Chris Alcock » The Morning Brew #1850()

  • Davide

    Hi Gabriel, nice article, thank you. But I have one question: how can the repository know which changes have been made to the aggregate? From your code it seems you’re using saving the entire object, but suppose you’re saving some changes to an order object that contains multiple items (product code, quantity and price for each one). How can the repository know which items have been added, removed or modified? Does it have to get all the orderitems saved in the db and check one-by-one if they exists in the “new” state of the order aggregate?

    Sorry if the question looks stupid, but I’m new to DDD ;-)

    Bye,
    David

    • gabrielschenker

      In my case NHibernate with its dirty tracking feature takes care of this. MS Entity framework or any other ORM works similarly.

      • Davide

        Yes, of course… it really was a stupid question! ;-)

        Thanks!

  • Ike Casteleyn

    Hi Gabriel,

    I’m following this series of posts with great interest. Thanks.
    I also 2 questions.

    - How do you handle information that needs to go back to the caller from the domainmodel?
    For instance in the AcceptOffer, the offerID is no longer valid (past it’s duedate).
    void AcceptOffer(int offerid)
    {
    //code
    bool offerStillValid = …;
    if (!offerStillValid)
    // what to do here
    }
    I’m guessing an event will be fired, but not sure.

    - How do you handle additional info needed from the caller in the domainmodel?
    void WithDraw()
    {
    // code
    bool specialCase = …;
    if (specialCase)
    // ask for extra data
    }

    Best regards,
    Ike

    • gilligan_MH

      1) there are multiple patterns to handle domain notifications. One is to use Events, one is to pass in a notification handler, and yet another is to throw an exception. One popular approach (and my preferred one) is to move all validation to the command itself, so in this case the LoanApplicationService, and run a LoanApplicationValidator. IT is commonly thought that an Aggregate should be responsible for managing state, not both validation and state.
      2) you should pass in all the data required for the special case ahead of time. The Domain Model should be able to make all its decisions based on a combination of its internal state and its method parameters. In extreme (Read: extreme) cases you can pass a service to it to get extra logic, but usually if you feel this is necessary then your aggregates are not modeled correctly, or you are not listening to the right Domain Events.

      Source: Almost ten years of development in making mistakes with DDD and currently on a two-year Domain-driven responsive Warehouse Mangement System.

    • gabrielschenker

      I tend to favor what Greg Young repeatedly said: “Make you commands highly likely to succeed”. What that means is that before you send the actual command you query the back-end about the factors that will decide upon success or failure; e.g. whether the selected offer is still valid or not. If the answer is yes, then you send the command, if not then you display a message to the user.

  • Hi, Gabriel! In your example of RESTful API you are just calling application service, but in real system you would need to check if route parameters are valid and create response with proper error codes and messages. For example, if “applicationId” value in route is not found then it should send 404 response code. How would you handle it? Would you call repository’s GetById from controller to check if application exists or would you create “query” method in application service?

    • gabrielschenker

      the application service is re-hydrating the aggregate(s) thus it might throw an appropriate exception which turns into a 404. The controller never should do such tasks.

      • How would you handle response on Post method where you are creating new resource and has to send back new resource Location. Can command return necessary data (Id) to create location URI?

        • gabrielschenker

          You can either use the location header in the response to point to the newly create resource or just return the ID as a part of the response body. I know this seems to violate CQRS but I do not see it like this… it’s just an ID that you create before even creating the resource (I prefer code generated IDs rather than DB generated ones)

  • I have another question :)

    In your example loan application might be in states – new, withdrawn and accepted. Accepted loan can’t be withdrawn and withdrawn can’t be accepted. And each action would add some additional data to entity – for example, offer acceptance might set some transaction Id. How would you handle state transitions of Entity in DDD?

    I found several ways and all has some pluses and minuses:

    - state pattern with state enum on entity and throwing exceptions or ignoring operation when invalid method called: http://stackoverflow.com/questions/10011859/state-pattern-and-domain-driven-design

    - state pattern with state object which transitions entity between states and throws exceptions when invalid method called: http://www.javacodegeeks.com/2011/02/state-pattern-domain-driven-design.html

    - have separate classes for each state: http://codebetter.com/gregyoung/2010/03/09/state-pattern-misuse/

    I am leaning towards last option, but it complicates persistance. Second option – state object requires you to expose internals of your entity to outside, so that state class can mutate it.

    Probably answer to this question is another blog post :)

  • This design will inevitably lead you towards the God class anti-pattern. Having LoanApplication as an aggregate might seem okay for now, but beware of dragons. Before you know it, you’re facing an aggregate spanning thousand lines of code and having more responsibilities than a janitor.

    In my experience, it’s much more valuable to identify aggregate boundaries through the discovery and definition of invariants instead of turning nouns into aggregates and verbs into commands. More than often, I see that the most effective models comes from treating use-cases as aggregates, since this is where you’d most often want to protect your invariants.

    • gabrielschenker

      I tend to agree with you if and only if you do not partition your overall problem into bound context. Once you have defined your fairly limited bound contexts there is no danger of aggregates getting “out of control” since the scope and complexity of each individual bound context is limited.

  • Huz thank,very good post

  • Pingback: From my reading list #26 – May 25th, 2015 | Pascal Laurin()

  • Marco

    As I said in one of your previous posts, I just don’t get it why you keep mixing resources and actions in your rest api definitions. Withdraw and AcceptOffer are actions you can perform a given resource, no resources you can actually retrieve.

    A better approach to define those URLS would be: applications/{applicationId}?action=acceptOffer and applications/{applicationId}?action=withdraw&amount=100.

    • gabrielschenker

      Let’s just agree that I am defining a Web API which has some similarities to a REST-ful API. For me it is more important that the API is intention revealing and works nicely with a backend that uses CQRS and DDD than to be pure in regards to REST. I try to be as pure as possible on the read side though.

      • Marco

        I agree with you on that an API should be clear, I just didn’t agree with the REST definition, but if you say that it only bear some similarities with a REST API while not being fully REST then is grand, I just find it a bit deceiving for other who might take your example as a RESTfull resource. Thanks for clearing it up tho :)

  • Caio Ferreira

    Hello! I’m mostly a desktop application’s writer (not yet a fully developer), so I’m trying to see it in my way. For the most part, your post kill my doubts about the implementation of DDD. But yet, two things remaing:
    The state class of your aggretate can be seeing as an entity?
    It’s a good approch to use DDD in desktop application. And, if so, patterns like WPF MVVM are a good choice for the presentation layer?

    • gabrielschenker

      The state class is part of the entity. An entity is the entirety of state and behavior. And DDD is a good choice whenever you have a complex system that is more than forms over data. Thus yes, it might be a good choice also in a desktop application.

      • Caio Ferreira

        So we can separate an entity in two classes: one of state e another of behavior? Or se just use a instance of the entity(a class containing state and behaivor) as the field? Sorry if it is a silly question, I’m just a beginner!

        • gabrielschenker

          This is just one way of separating concerns, one of the base principles of good object oriented programming. But it is important that state remains encapsulated by the entity, another principle of good OOP. In this case the entity is the class that implements the behavior and owns the state.

          • Caio Ferreira

            OK! Thanks for the answers, it’s clear my mind a lot! The post, by the way, is amazing like the whole blog! Congratulations!

  • rustem

    Hello, Thanks for the great post.
    I get a little confused about the following line(the application service 2nd line) :

    “This service is among other responsible to re-hydrate the aggregate from storage and after acting upon it to persist the changes back to the storage”

    The reasing I’m asking this because I get a little confused what to unit test in this service. Assuming you have unit tests for Withdraw() and AcceptOffer() in Aggregate Root tests, so what should I unit test in application services?

    If your answer is different from “Only the methods calls?(Times.Once)”, could you please explain why?

    • gabrielschenker

      All the important (business) logic is in the aggregate and thus normally the application service doesn’t need to be unit tested. I am not a big fan of 100% code coverage by unit tests. Test where it makes sense.