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.)

  public void performMove(String playerId, Move move) {
    if (gameOver) {
      throw new IllegalStateException("Game is already over");
    }
    if (playerId.equals(this.lastPlayer)) {
      throw new IllegalStateException("Already made your move");
    }
    this.eventPublisher.publish(new MoveMadeEvent(playerId, move));
    if (lastMove != null) {
      generateWinningEvent(playerId, move);
      gameOver = true;
    }
    lastMove = move;
    lastPlayer = playerId;
  }

  private void generateWinningEvent(String playerId, Move move) {
    if (this.lastMove.beats(move)) {
      this.eventPublisher.publish(new GameWonEvent(this.lastPlayer, playerId));
    } else if (move.beats(this.lastMove)) {
      this.eventPublisher.publish(new GameWonEvent(playerId, this.lastPlayer));
    }
  }

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:

  InMemoryEventPublisher ep = new InMemoryEventPublisher();
  Game game = new Game(ep);

  @Test
  public void same_move_should_result_in_tie() {
    // given
    game.performMove("ply1", Move.rock);
    ep.removeEvents();
    // when
    game.performMove("ply2", Move.rock);
    // then
    List events = ep.removeEvents();
    assertThat(events, hasItem(new GameTiedEvent()));
  }

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:

  public List performMove(String playerId, Move move) {
    if (gameOver) {
      throw new IllegalStateException("Game is already over");
    }
    if (playerId.equals(this.lastPlayer)) {
      throw new IllegalArgumentException("Already made your move");
    }
    List events = new ArrayList<>();
    events.add(new MoveMadeEvent(playerId, move));
    if (lastMove != null) {
      events.add(generateWinningEvent(playerId, move));
      gameOver = true;
    }
    lastMove = move;
    lastPlayer = playerId;
    return events;
  }

  private Event generateWinningEvent(String playerId, Move move) {
    if (this.lastMove.beats(move)) {
      return new GameWonEvent(this.lastPlayer, playerId);
    } else if (move.beats(this.lastMove)) {
      return new GameWonEvent(playerId, this.lastPlayer);
    }
  }

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

  private Event generateWinningEvent(String playerId, Move move) {
    if (this.lastMove.beats(move)) {
      return new GameWonEvent(this.lastPlayer, playerId);
    } else if (move.beats(this.lastMove)) {
      return new GameWonEvent(playerId, this.lastPlayer);
    } else {
      return new GameTiedEvent();
    }
  }

And the test case:

  Game game = new Game();

  @Test
  public void same_move_should_result_in_tie() {
    // given
    game.performMove("ply1", Move.rock);
    // when
    List events = game.performMove("ply2", Move.rock);
    // then
    assertThat(events, hasItem(new GameTiedEvent()));
  }

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:

  @Transactional
  public void performMove(String gameId, String playerId, Move move) {
    Game game = this.gameRepository.load(gameId);
    List events = game.performMove(playerId, move);
    this.eventPublisher.publish(events);
  }

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!

This Post Has 47 Comments

  1. banq

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

    1. Jan Kronquist

      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.

    1. Jan Kronquist

      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:

      public interface Result {
        List events();
      }
      
      public class AbstractResult implements Result {
        private List events;
        public AbstractResult(Event... events) {
          this.events = Arrays.asList(events);
        }
        public List events() {
          return events;
        }
      }
      
      public interface MoveResult extends Result {
      }
      
      public class OnlyMoveResult extends AbstractResult implements MoveResult {
        public OnlyMoveResult(MoveMadeEvent event) {
          super(event);
        }
      }
      ...
      

      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.

    1. Jan Kronquist

      Sure, but many mistakes are stupid once you see them. The point is that by using a return value you are forced to write correct code.

  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.

    1. Jan Kronquist

      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.

    2. Adam

      I’m not sure that processing an order and generating the invoice belong in the same function. It would imo be cleaner to process the order as a command, and then pass the processed order into a factory method to generate the invoice for it. In general, returning values from a command is a code smell.

      1. Jan Kronquist

        I think I agree with you!

        The point of this blog post was a simple one: Use a pure function to handle commands, ie avoid side effects such publishing events. The events should instead be returned from the command handler and perform any side effects (eg managing transactions, writing to databases, publishing events, sending data to a client) outside the command handler.

        For the specific example with orders and invoices I would most likely publish the events from creating the order and then generate the invoice based on the events somewhere completely different, ie asynchronously. This would also give me the possibility to create a single invoice for multiple orders and or perhaps generate the invoice when the order is delivered, etc.

  6. Gilligan

    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.

    1. Jan Kronquist

      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
  7. Piyush

    Thanks for this post. Recently i read Vaugn Vernon’s book Implementing Domain Driven and had similar question in my mind like dependency injecting publisher to aggregate will make testing harder and seems more coupling. This makes more sense.

  8. Lauri Taimila

    Thanks for this eye-opening blog post. This is an elegant and obvious (once someone tell’s it to you) solution to the problem.

  9. Greg Young

    Why not go one step further and have the “service” be a function that returned them then you could get something like …

    PatternMatch
    MyCommand : StartTransaction |> EnrichContext |> ProcessMyCommand |> Publish

    Cheers,

    Greg

  10. Roberto Simoni

    Thank you for this.
    In my view, there is a “semantic” issue designing api where the “client” asks you to do something and you return events to him… I prefer to see a Listener in the signature where you can be notified about events.
    And I think this is also simple to design it using TDD…
    What do you think, Jan?
    Thanks Bye
    R

    1. Jan Kronquist

      As I mentioned in previous comments the client of the domain is the application service, not a client application. Since the Application Service is responsible for the transaction and other infrastructure concerns, I think it is perfectly reasonable that the domain returns events. The Application Service asks the domain (aggregate) : “What would happen if this command would be executed given the current state?”, the domain replies “These events would occur!”, and the Application Service commits by saying “These events occurred at this time”.

      My goal is to keep the domain code as clean as possible, ie avoid all infrastructure and cross cutting concerns. For example if you want a Listener, then you probably want this for all commands. By moving the responsibility to the Application Service you can easily have a listener for all events. Have a look at this blog post for a completely generic Application Service:

      http://blog.jayway.com/2013/03/08/aggregates-event-sourcing-distilled/

  11. Alex Farcas

    I like this approach of returning events instead of using an event publisher, but what about situations when your domain method needs to return something else?

    Take Udi’s article: http://www.udidahan.com/2009/06/29/dont-create-aggregate-roots/ and imagine that you want to create a Shipment out of an Order. The correct way to do it would be to call order.createShipment(…) which would need to return the newly created Shipment.

    1. Jan Kronquist

      My guess is that Udi Dahan uses the old definition of aggregate and not the one updated by Eric Evans just a few months earlier to Udi’s post. The new definition and the one I’m using is to view aggregates as “consistency boundaries for transactions, distributions and concurrency”. The way I implement this is by not allowing the clients to interact directly with the aggregate code. Instead the client sends a command that is handled by an application service that creates the transaction and delegates to the appropriate aggregate. All the aggregate does is return the domain events that should be published.

      I could allow the Order aggregate to return a ShipmentCreatedEvent(shipmentId) and thereby creating the Shipment. However, notice that all events that are returned must have the same aggregate id otherwise this would violate the definition of an aggregate as a consistency boundary for the transaction. The more “correct” way would be to return a OrderShippedEvent(orderId) and then have a saga convert this into a ShipmentCreatedEvent(shipmentId, orderId) (the first attribute being the aggregateId).

      Also notice that in the client code you can have all the utility classes or DSLs you want. That is, if you want to write your client code as order.createShipment(...) then that is ok, but the order object is not the actual aggregate implementation. Instead this order class would look something like this:

      public class OrderClient {
         private UUID orderId;
         ...
         public ShipmentClient createShipment() {
            applicationService.process(new CreateShipmentCommand(orderId));
            // ...for simplicity assuming the process method is synchronous...
            ShipmentDTO s = shipmentProjection.findLatestShipmentByOrderId(orderId);
            return new ShipmentClient(s);
         }
      }
      

      a more modern version using RxJava might look like this:

      public class OrderClient {
         private UUID orderId;
         ...
         public Observable createShipment() {
            return applicationService.process(new CreateShipmentCommand(orderId))
            .flatMap(ignore -> shipmentProjection.findLatestShipmentByOrderId(orderId))
            .map(dto -> new ShipmentClient(dto));
         }
      }
      

      Hope this explains how I think!

  12. Nick

    What about situation when Game has a timeout and you want the Game instance published TimeoutEvent after some period of time? One way is to have a service that holds a collection of timers but I think this is not right as TimeoutEvent is a business rule, i.e. it is a part of business logic, and should not be in Application Layer (Service Layer).

  13. Richard Clayton

    I’m trying to wrap my head around the same scenario (not injecting or statically referencing an “EventPublisher” in each model). But I’m kind of struggling with this notion of returning the events as the result of a “command”. To me, returning an arbitrary array of events feels like you are embedding an event model into the business logic. I also wonder what happens if you need to return something from the command:

    Receipt = account.deposit(fromAccount, new Currency(20, Currencies.USD));

    Are you saying I should wrap the receipt in one of the domain events? Maybe in something like a DepositEvent? If that’s the case, it may make sense if (and only if) one event is returned. But still it kind of seems funky.

    Alternatively, I was wondering what you think of using a traditional Listener model on the class and bubbling up Global events from an attached listener? (excuse my Java, it’s been a couple of years)

    “`
    public interface EventProducer {
    void addSubscriber(Subscriber subscriber);
    }

    class Account implements EventProducer {
    public Receipt deposit(Account fromAccount, Currency amount){
    // …
    this.fire(new DepositEvent(this, fromAccount, amount);
    return receipt;
    }
    }
    “`

    Then you can subscribe to domain events by subscribing to the model.

    Alternatively, in languages supporting AOP, we could use method interceptors to interpret results from method calls can create Domain Events (though to me that seems an unnecessary separation of Domain Events from the model).

    Truly curious what you think; and by the way great article – I love it when programmers can have these kinds of discussions.

    – Richard

    1. Jan Kronquist

      There are a couple of points I would like to make:

      1. Clients are not supposed to call the command handler directly. Instead the application service should handle client requests and turn them into commands that may have a response. Understanding the difference between command handlers and application service and their different responsibilities is crucial.
      2. If you want to return a receipt what you probably want is to create a receipt, which would actually require an event, for example ReceiptCreatedEvent. Otherwise there would be no record of the receipt.
      3. I think the Listener model you are proposing is exactly the same thing as an event publisher.

      Hope this helps!

      1. Richard Clayton

        Jan,
        Like Roc, I’m back! Over the course of two years, I’ve had shifting views on how to implement this scenario. I’ve generally converted to the idea of returning events, however, I’m curious about how you implement persistence in this pattern? Are you using event handlers to save entities that change? Event Sourcing seems like the obvious methodology to use, but in a more traditional application what would you recommend?

        Thanks,

        Richard

        1. Jan Kronquist

          Have a look at the post Aggregates + Event Sourcing distilled for a more complete example with event sourcing. The code is available here, although only an in-memory event store.

          If you are not using event sourcing, then I don’t really have a good recommendation.

    1. Jan Kronquist

      The constructor is the technical way that objects gets constructed in Java. I think you need to separate that from the command that is creating the aggregate in your domain, ie you need to have a command handler method for this.

  14. Rock Johnson

    For more than two years I’ve been revisiting this blog post. As an OO programmer, it wasn’t until I’ve become interested in functional programming that this post means something to me.

    Excellent work here!

  15. 0xmarcin

    Your approach is good but I like to modify it a bit, instead of returning events I would prefer to save them to transient field on aggregate. This is not my idea I borrowed it from: https://lostechies.com/jimmybogard/2014/05/13/a-better-domain-events-pattern/. This way you may subscribe for some Hibernate event/add listener and handle publishing events for all entities automatically.

    1. Jan Kronquist

      The whole point of this blog is that I want to avoid solutions like that. By having pure functions your code will be much easier to both understand and test.

  16. developeruldeserviciu

    This is a great ideea. My problem was that during my DomainService execution I was firing some events, like OrderStatusChange, OrderChange. One problem was if there was a database error: my sql operations were in rolled-back , but some jobs were already into the air: for example a job of sending mail for status change (as a listener os OrderStatusChange).

    In this way I can rollback or commit my database in the Application Service Layer in the same time with firing or ignoring my events.

    One downside is that using my Domain does not imply that events are fired, so some “domain logic might be broken” – that logic that depends of event-wiring

  17. ObjectOriented

    Oh please! Don’t generalize a particular solution to a particular problem. Definitely not by “targeting OOP programmers”. And conveniently breaking another pattern (CQRS) just to justify your own solution? Those are telltale signs of a bad design and implementation.

    1. Jan Kronquist

      CQRS is not broken as it is an architectural pattern for how to structure your application and not about an individual class or module.

  18. Sean

    I like and agree with this blog post, but am interested in how you would publish events on aggregate root construction.
    Given that the constructor is the usual way of creating objects in most OO languages and one would have a command handler to create objects, would the handler create the ObjectCreatedEvent? Or would you have a factory that returned say the aggregate root and the list of events that apply during creation to the AR and any aggregates?

  19. Sean

    Hi Jan,

    That blog post made sense. However, I am wondering how you rehydrate an aggregate from a sequence of events?
    Would you have a static method on the aggregate root to do this, or something else?
    Do you have any blog posts showing your approach?
    Thanks,
    Sean

    1. Jan Kronquist

      This is done by the Application Service. Despite its name, this can typically be completely generic and is not part of the domain. Its responsibilities are:

      • Load events for the event store
      • Instantiate a new aggregate
      • Apply all events on the aggregate
      • Send the command to the aggregate
      • Store the new events

      see https://blog.jayway.com/2013/03/08/aggregates-event-sourcing-distilled/

  20. Alexander

    I really like this idea, but how to return events when creating an entity, if it is necessary to return the entity itself?

      1. Alexander

        I will clarify my question. When creating a new aggregate inside a command handler, the new aggregate must be returned so that it can be placed in the repository. In this case, how can a factory method, a constructor, or a method of another aggregate return creation events?

        1. Jan Kronquist

          You can’t create a new aggregate from within a command handler as each command handler can only act on its own aggregate. My definition of aggregate is “the consistency boundaries for transactions, distributions and concurrency”, ie if one aggregate creates another you will have a transaction spanning over two aggregates. You need to use a Saga in order to create a new aggregate based on events from the first aggregate.

          Also, I recommend taking a look at https://occurrent.org/ which is a library that implement these and many other good ideas.

Leave a Reply