Sponsored By Aspose - File Format APIs for .NET

Aspose are the market leader of .NET APIs for file business formats – natively work with DOCX, XLSX, PPT, PDF, MSG, MPP, images formats and many more!

Command Handlers and the Domain Model

Couldn’t sleep on the train from Oslo to Bergen so I decided to start writing a bit. Correction, the train is stuck now in a tiny little town about two hours from Bergen, have to say, a beautiful spot to have to say it is a beautiful spot to be stuck.  

 

Many people are talking about Command Handlers and how they work when they are really just CRUD handling very simple operations. Likely there is little or no validation in them and they are simply passing through information.

 

A perfect example of this might be the name of a customer in a CRM. There are no invariants of the customer object that need the name (there could be invariants imagined such as all customers who have a name of ‘greg’ get a 15% discount when buying things but let’s imagine for a minute that such invariants do not exist in this case). Many people have been suggesting to just use the command handler as a pass-through to then publish the event (transaction script like). The code would look something like this (simplified).

 

class ChangeCustomerName : Handles<ChangeCustomerNameCommand> {

    public void Handle(ChangeCustomerNameCommand cmd) {

          if(somebasic logic) throw new Exception();

          DomainEvents.Publish(new CustomerNameChangedEvent(cmd.FirstName, cmd,LastName));

    }

}

 

A more stereotypical version of this might look something like.

 

class ChangeCustomerName : Handles<ChangeCustomerNameCommand> {

    private CustomerRepository repository;

    public ChangeCustomerName(CustomerRepository repo) {

        repository = repo;

    }

    public void Handle(ChangeCustomerNameCommand cmd) {

        var customer = repo.FetchById(cmd.Id);

        customer.ChangeNameTo(cmd.FirstName, cmd.LastName);

    }

with customer then creating the event.

There is nothing wrong with either of these solutions, both have their merit. Unfortunately the Ubiquitous Language becomes extremely interesting in the first case as there is no concept of a Customer in the domain model. There is a concept that the customer’s name can be changed and that when it is there is a CustomerNameChangedEvent but there is no explicit concept of what a customer is within the domain model.

 

This is perfectly ok if DDD is not being applied (and there are many places where doing this style of transaction script command handler can be very useful). If DDD is being applied though this is probably not a good pattern to be following. Very little code is being saved (the same new of the event is just being put on the customer object instead of in the command handler) and a concept within the domain is being lost. This becomes especially true if the other object already exists within the domain model as there are other behaviors associated with it. 

 

If it is the case that there are just a few operations on an Aggregate and they don’t access current state for invariant protection the domain object will probably only contain an aggregate id and the basic if statements that are present in the command handlers otherwise. These thin little objects still have benefit though as they are defining and making explicit the aggregate boundary as well as giving vocabulary to what the aggregate is and the behaviors contained within its boundary.

 

It is also however a great example of how Domain Driven Design is not a pre-requisite to using CQRS and even events. For a great many systems the first command handler will be a much better choice than the second command handler (especially for line of business or simple web systems). It can also be a good idea to use a hybrid approach where although many things exist in a given context most of them are simple and not specifically modeled and the domain model itself is focused only on those cases where a domain model makes sense.

This entry was posted in Uncategorized. Bookmark the permalink. Follow any comments here with the RSS feed for this post.

9 Responses to Command Handlers and the Domain Model

  1. Pingback: Baby Carrier Backpacks » Blog Archive » Hybrid Baby

  2. Greg says:

    Ah simple misunderstanding, the thing is there *is* a customer in their language :)

  3. @greg
    >Why would creating a customer be wrong?
    you tell me ;)…I simply interpreted it that way since you were saying:
    “Unfortunately the Ubiquitous Language becomes extremely interesting in the first case as there is no concept of a Customer in the domain model”
    which led me to believe that in this made up example the domain experts never talk about Customer so it really shouldn’t be in the domain model.

    However after reading it for the 10th or so time I think I do get what you mean by *interesting* – as in : the interesting part is how can we do a change on something thats not defined in our context. Correct?

    Considering my DDD shortcomings I have nothing backing me up about what is right or wrong, so I try not to – hopefully your course next week will change it to the better :)

  4. Greg says:

    Why would creating a customer be wrong?

  5. for every post you make it first enlightens me then when I really start thinking I just get more confused…Maybe I’m just stating the obvious here below, but I am not so experienced in all this, so here we go:

    I understand the parts of no added value with just passing the data from the handler on to a Customer object.

    You say “This is perfectly ok if DDD is not being applied” and “Domain Driven Design is not a pre-requisite to using CQRS and even events”.
    That also explains the simple fact that CommandHandler raises an DomainEvent – which made me just go ???????.
    You are simply making a point, this is not DDD but still can be ok – “even events”

    If we were gonna make it somewhat DDDish:
    Introducing a Customer agg root is wrong. I buy that. If we assume major remodeeling is out of question, my guess is that introducing a domain service, ChangeCustomerNameService ,which gets called by the CommandHandler,
    would be somewhat correct?

  6. Greg says:

    @Ernst it can be a valid .. and you can certainly build a transaction script based system with CQRS

  7. Ernst says:

    I was asking myself this exact question yesterday. Thanks for the answer! I’m now at peace again :)

    Your last paragraph has me thinking. Could I really build a transaction script system on a CQRS design ? Actually, is that a valid migration plan from a legacy system: keeping the same old services and all but introducing commands and events ?

  8. Greg says:

    @svb It is on the events … the domain model *could* use it when loading from events but if its not being used in an invariant why bother?

  9. svb says:

    You are stating that “there are no invariants of the customer object that need the name” and because of this you just publish an event when that name is changed. Am I correct when I say that in a CQRS environment this would mean that the name is only stored in the read-model as it has no real meaning in the domain model itself?

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>