Search code examples
eventsdomain-driven-designcqrs

Projecting aggregate state in Read Model, extra logic on read side vs more data in the event


Let's say, I'm using event sourcing and my aggregate root (match) builds its state from "PlayerWonPoint" and "PlayerLostPoint" events (it also has two corresponding commands). If simplified, state goes from InProgress to Final. Read side is responsible for representing points history and some stats. For tennis, for example, points would be represented as

MatchStarted    -> 0-0
PlayerWonPoint  -> 15-0
PlayerLostPoint -> 15-15
PlayerWonPoint  -> 30-15
PlayerWonPoint  -> 40-15
PlayerWonPoint  -> Player won the game
  • Do I tell Read Model (using event data) what is current score representation, so read model will take it as given and just append to the table? In this case read side is very simple, but we add some extra data into source events that is not really required for aggregate itself.
  • Or, we can let Read side to figure out scores representation? It will require extra logic which will be very similar to what is used in the aggregate for tracking it's current state.

Another question: if player wins the point and aggregate sees that it is a GamePoint, SetPoint or MatchPoint, do I record different event type for that or I just keep using only PlayerLostPoint/PlayerLostPoint events? Because, again, the aggregate can re-hydrate itself from the latter two events types. But, with only two event types read model gets even more complicated (i.e. need to track games, sets, etc.). I see no big harm adding extra even types to simplify ReadModel, potentially extra event types maybe useful for aggregate too, for example, it can skip processing all points events if last point event is "PlayerWonTheMatch"?


Solution

  • Do I tell Read Model (using event data) what is current score representation

    I think that's the way you should go. Otherwise you should build another aggregate on read model. Cause only aggregate knows what was the score after you performed a specific action on it. Also consider that events may come out of order, or come twice. Be ready for that.

    if player wins the point and aggregate sees that it is a GamePoint, SetPoint or MatchPoint, do I record different event type for that or I just keep using only PlayerLostPoint/PlayerLostPoint events?

    I think you should do it if your domain requires it. It gives more detailed info about the game, but make sure its needed, don't program the reality, other wise you would end up with events like: ABallBoySuppliedTennisBallToPlayerEvent which could be useless for your domain.