Domain-Driven Design and Command-Query Separation example application

Erik Rozendaal

Ever since attending Greg Young's Unshackle Your Domain talk at QCon '08 in San Francisco and a later two-day training course given by Greg Young I've wanted to build a sample application that made use of the principles of Command-Query Responsibility Separation (CQRS).

However, other interesting things intervened and I never got around to doing this.

But every few months we have a one day internal training course at Xebia Software Development and after Sjors Grijpink and I proposed to give a training on DDD and CQRS we got some time to actually prepare and implement a CQRS example application.

The Xebia Lottery

The application is fairly simple (as it should be for a one day training course) but touches on all the major components needed for a full-blown CQRS implementation.

CQRS components

The source code for the training exercises can be found at github. There are three branches:

  1. exercise - the code used for doing the training exercises.
  2. solution - the same code as above but with the solutions added.
  3. master - the main development branch, currently used to implement more advanced features like snapshotters, command-event conflict resolution, historical tracing, etc.

The Xebia ITR CQRS presentation is also available.

All-in-all the training was a success and I think that the basic CQRS principles are the way forward when you need to build enterprise applications with a complicated domain logic or strong auditing or historical tracing requirements.

Comments (17)

  1. Silvester van der Bijl - Reply

    December 3, 2009 at 9:52 am

    Hi Erik,

    Great post! Just took a quick tour of the GitHub project and it seems you put quite a lot of effort into this. Is the framework implementation also going to be released as part of some (open source) project?

    Thanks again!
    Silvester

  2. Erik Rozendaal - Reply

    December 3, 2009 at 10:04 am

    Hi Silvester,

    Currently we just plan to make the current framework more "production ready" to support the sample application. It would be cool to extend it into an open source framework, but I'm afraid it may mean that the framework becomes rather complicated to meet all the needs of different applications. This would be counter to one of the things I like about CQRS: each component is relatively straightforward and should not take more than a week to develop, depending on the needs of your application.

    So right now the best way to reuse may be to fork the project and adapt to suit the specific needs of the system you're building.

    This Sunday (December 6th) we'll have a coding session somewhere in Amsterdam to develop this further, so anyone willing to join is invited to do so.

  3. Mark Nijhof - Reply

    December 3, 2009 at 11:34 pm

    Hi Eric,

    Very cool, it is good to get some more examples (leave it to the Dutch guys) out there especially using different implementations. I assume you saw my example and blog post on the same topic as well: http://elegantcode.com/2009/11/11/cqrs-la-greg-young/ (it is for the .Net world). I am intending to make it more into a framework where you should be able to use it as NHibernate (Hibernate for you guys :) and have normal po(c|j)o's.

    -Mark

  4. Erik Rozendaal - Reply

    December 4, 2009 at 8:13 am

    Hi Mark,

    I did see your blog. Very useful explanation the actual code and components! Looks like the .NET world has a head start here (and I wish we had something like nServiceBus, MassTransit, RhinoServiceBus, ...).

    Currently I prefer to keep the domain free of any ORM or proxy-like tooling, mainly for simplicity and to not break the standard Java OO model. In the reporting component I can see some use for an ORM... but mainly as a nicer, portable "SQL" tool.

    Still, it is very interesting to see the different approaches and to find out what works and what doesn't. I lot of this is still needed, since the CQRS model allows for many knobs to be turned and tuned :)

    Regards,
    Erik

  5. David Perfors - Reply

    December 4, 2009 at 8:45 am

    Hi Erik,
    This looks great. I took a quick look and found the OnEvent method on the aggregate roots. I think that when you have a lot of different type of events that will be a massive method. I must admit that I don't know another solution in Java, I am not doing that much with it any more :P...

    David

  6. Mark Nijhof - Reply

    December 4, 2009 at 12:36 pm

    Hi Erik (sorry about the use of c),

    It is absolutely a good idea to have different implementations to slve the same problem, then 'hopefully' the best one will survive. In my example I am not using an ORM just something using reflection of DTO's on the reporting side. What I meant when I compared it with NHibernate was how you use NHibernate, so without a base class or any knowledge of persistence.

    -Mark

  7. Erik Rozendaal - Reply

    December 5, 2009 at 11:05 am

    Thanks David. The onEvent method may certainly become a concern when you start handling a lot of events, although this may also be an indication your class starts to do too many things.

    I've an implementation of AggregateRoot that uses reflection and annotations to automatically invoke the correct handler methods, but for the training example I found it a bit too "magical". The current onEvent method makes it very clear how events are dispatched internally.

    Another approach could be to use the visitor pattern, but again I think this is probably overkill.

    Erik

  8. [...] Domain-Driven Design and Command-Query Separation example application by Erik Rozendaal (in Java) [...]

  9. Colin - Reply

    December 24, 2009 at 11:44 pm

    Eric,
    Example application let me know a lot about CQRS. Thanks.
    But, I have a question. All Entity must extend AggregateRoot, how to differentiate Entity and AggregateRoot? As you know "Aggregate is: Group of Entities & Value Objects; One entity within the aggregate is the aggregate root".

  10. colin - Reply

    December 25, 2009 at 3:39 am

    Sorry about the use of c.

  11. Erik Rozendaal - Reply

    December 28, 2009 at 9:12 am

    Hi Colin,

    The example application's "domain" support currently doesn't support multi-entity aggregates. Obviously, it should and I have some experimental code. Basically each Entity that is part of the same Aggregate gets a reference to the AggregateRoot and reports it's state change events there.

    To reduce the complexity of the AggregateRoot class I moved the tracking of entities and dispatching of events into a separate class called "Aggregate". I'll see if I can check in the code into the master branch today.

    Regards,
    Erik

  12. colin - Reply

    December 28, 2009 at 10:19 am

    @Erik
    I am glad to hear that.

  13. Jonas Van Poucke - Reply

    December 30, 2009 at 8:10 pm

    Hi,

    Have you seen http://www.gridshore.nl/2009/12/21/cqrs-made-easy-with-cqrs4j/
    as an Open Source Framework (Apache 2 license)?

    Maybe you could help get that one at production quality?

    Jonas

  14. Colin - Reply

    January 18, 2010 at 11:39 pm

    Erik,
    Recently, I was studying CQRS by your lottery codes.
    I got a problem:How to deal with concurrency issues? For example, two users purchasing the same lottery at the same time : )

  15. Erik Rozendaal - Reply

    January 19, 2010 at 9:42 am

    @Jonas: I've talk to Allard about cqrs4j and will probably meet up soon with him. I'll also be giving a talk at the next http://www.dddnl.org/ meetup on CRQS (March 9th).

    @Colin: Currently this will result in an optimistic locking failure. It was left as an exercise to add command/event conflict detection and resolution. Probably worth a blog post on itself, but the short version is that when a command is received for an older version of an aggregate you can compare the command to all events that have happened. If any of the events is conflicting (lottery drawn, etc) you get an optimistic locking failure. If there are no conflicts (someone else bought a lottery ticket) then you can proceed to process the command.

  16. [...] is Erik Rozendaal who wrote a lottery example to help train his coworkers. Erik’s code is written in [...]

  17. jfly - Reply

    October 7, 2012 at 7:25 pm

    Hi,Erik,your job is great! I'm not good in English:(, I can't understand the 90 line in RepositoryImpl.java, why "actual" is " result.getVersionedId().getVersion() - 1", not "result.getVersionedId().getVersion() "?

Add a Comment