Don't publish Domain Events, return them!

During a discussion around some of the code examples in Vaugn Vernon’s book Implementing Domain Driven Design we got stuck at what first appeared to be a tiny detail: where the domain events are published. Is it part of the domain or not? But more importantly, what is the programming model for publishing events? I think this issue highlights how object oriented programmers are so used to carelessly mutating state that they don’t even consider any alternatives. I will not go into monads or anything, but only show how using normal return values can simplify your code.

In many DDD examples of code that generates domain events you often find a EventPublisher (or MessageBus, DomainEventsRaiser etc) that is injected into the domain object or worse accessed statically as argued by Udi Dahan. The aggregate then use the EventPublisher to send all the events that are generated when processing the command. When reading the code many people think it is very clear and easy to understand. However, there are many problems with this approach.

I will use my current favorite domain rock-paper-scissors. For a more complete example that also uses event sourcing, have a look at Aggregates + Event Sourcing distilled. (In the following example I will not use event sourcing and will in fact mutate state directly in the command handler. The reason for doing this is that in this blog post I target traditional object oriented programmers. If you are already into functional programming, you should probably read Event Sourcing in Clojure instead.)

The idea is that once the game is started either player can make their move first and when both players have made their move the game is over.

Can you spot the bug?

No event is generated when “lastMove” equals “move”, that is no GameTiedEvent is generated! Since the event publishing for the winning event occurs in a separate method it can be easy to miss this.

First, we write a test case to try to find the bug:

To make the test work we need to do the following:

  • Know that events are published
  • Create an EventPublisher and inject into Game
  • Remove all events after the first command since we don’t want to verify these

Since the test fails you start the debugger. You step over the first “eventPublisher.publish” method in the debugger and then think to yourself “hmm, the MoveMadeEvent have been published, maybe it is a concurrency issue. Maybe somewhere else some weird behavior is triggered by this MoveMadeEvent”….

However, as you will realize after an hour or so of debugging is that the event has not at all been published. The EventPublisher only publishes the events when the entire command has been processed! Otherwise the command will not be atomic! This is typically setup in the Application Service that start the transaction.

Of course, one solution to this is rename the EventPublisher to EventTracker or something, but that is only a workaround and still makes it hard to understand for new developers what is going on. Even worse, since your domain depends on this code it means that you might have to explain event publishing/tracking to a domain expert. From their perspective event publishing/tracking is a technical detail that they couldn’t care less about.

Now lets consider a revolutionary new approach: use return values! :-)

Implementing the Game logic becomes:

Immediately we get a compiler error saying that generateWinningEvent is missing a return value! Let’s fix it:

And the test case:

The domain has no knowledge about event publishing or event tracking. The test only have to check the return value it cares about. Clean and simple. It is easy to understand and easy to test.

But a Command returning values, isn’t that a violation of Command Query Separation? Or perhaps Tell, don’t ask? Perhaps, but the reason is not the fact that I’m returning events, instead the reason is I am returning events AND mutating state. By using event sourcing you separate the mutation to when the event is handled. But, it gets even better. Event sourcing is not object oriented, instead it is functional. Then “Tell, don’t ask” does not apply as it is a object oriented advice. Michael Feathers also talks about Tell above, ask below as a way to combining OO and functional. Another good point is made by Robert Harvey:

If you are using the result of a method call to make decisions elsewhere in the program, then you are not violating Tell Don’t Ask. If, on the other hand, you’re making decisions for an object based on a method call to that object, then you should move those decisions into the object itself to preserve encapsulation.

So where are the events actually published? In the Application Service of course:

This code is just boiler plate, see Aggregates + Event Sourcing distilled how you can in fact use a completely generic Application Service for all command handlers using aggregates.

Sure, there are cases where injecting something like an EventPublisher or even accessing it statically may be useful. However, typically this is because you are either writing your own framework or working around someone else’s framework. I hope I have convinced you how normal return values can be a lot simpler and easier to understand!

12 Comments

  1. events is not business, so when in a business method return
    events, it intrudes business logic.

    • Not really sure I understand what you mean. Domain Events are part of the Domain by definition, so clearly it is something the business cares about. Why would it intrude on business logic?

  2. Frisian

    These methods do too much IMHO. How about separating the logic of the actual game in one class and event handling in a decorator?
    The return value of performMove should be a class Result with an Outcome enum (move, win, tie) and the player id as attributes. That is pure domain logic.
    The decorator then has enough information to create the MoveMadeEvent from the passed arguments, if there are no exceptions, and the result events from the return value.
    The EventDispatcher can be injecting into the decorator without affecting the domain objects.

    • Did you look at the other blog post “Aggregates + Event Sourcing distilled” ?

      I agree that these methods do too much, but by removing the state manipulation you only return one or two events (MoveMade and perhaps GameWon or GameTied) which is very similar to what you are proposing.

      The difference compared to using a separate Result class is mainly a matter of explicitly restricting the number of possible return values, ie a question of static vs dynamic typing. Instead of returning a List of Events, you can only return the specific outcomes ie:
      * OnlyMoveResult = 1 MoveMadeEvent
      * WinningMoveResult = 1 MoveMadeEvent + 1 GameWonEvent
      * TiedMoveResult = 1 MoveMadeEvent + 1 GameTiedEvent

      hmm… sure, why not! Instead of using a decorator you could do something like this:

      Although it creates a bit more boilerplate I can see the value of doing something like this. However, personally I prefer the solution in Clojure and then this extra static typing info is not needed.

  3. Bob

    If you really wanted to be sure to cover all events, you’d have an else without an if at the end. To expect that the code as it was written covers all cases is stupid.

  4. Roy Phillips

    Great post, thanks for that – I was struggling to incorporate domain event publishing into my AR, and it felt all wrong. But an aggregate method that takes a command and returns a maybe-empty Seq of domain events seems both cleaner and logical, and much easier to dispatch to a publisher, wired into an app service, for example.
    And yeah, following V.V.s book, we have domain experts talking about events that happen in their domain, nothing techie there.

  5. orpouser

    That is an interesting situation. In my opinion, you need to return an object when clients expect a result. In this simple scenario returning the events works fine but in a more complex situation this will easily fail i.e. think in the typical example where you are processing an order end the output is an invoice but also have to deal with the events.

    • What I’m talking about is the implementation of your domain code. If you have a REST API that is calling your domain logic, of course you can return whatever you want from that. The best approach is by doing a projection of the domain events.

      My point is simply that you should make your domain logic free from side-effects and put the side-effects on the outside.

  6. I would imagine it would be easier on your infrastructure so add these events to list then have a separate method to get that list. That way each controller action does not need to wire into every method you call on the model. This is in fact what most event sourced cqrs systems do. One of the main points of calling the publisher directly is that you are piping though a common interface where infrastructure can be easily plumbed, instead of into the wide world where you get no infrastructure support.

    • Yes, I know that many cqrs systems do this in a different way. However, I believe my approach is better! :-)

      • Adding events to a list? A separate method for getting that list? Sounds like a lot of mutation going on. I really don’t like that. It makes my programs harder to test and very difficult to make them thread-safe.
      • Easily plumbed? Actually no. You have to use dependency injection or some kind of singleton. Sure, not super hard to do, but compared to not doing anything at all it is definitely more work. Have a look at my blog-post about Aggregates + Event Sourcing and in particular the ApplicationService implementation

Trackbacks for this post

  1. Error handling – part 2 – keeping it easy | Software Passion

Leave a Reply