11

I can think of two places where to put the domain logic in an event sourced system either one has a drawback.

  • In an event handler of the Aggregate, called locally after creating the event. (That's what I saw in most examples though most of them have very simplistic logic)
    Issue: The event stored in the event store and published to subscribers does not include this processed data and therefore on the projection the same logic has to be applied to the event.
  • Before creating the event. Now the processed data can be stored in the event and the projection doesn't have to know anything about business logic. (I haven't seen this method in examples)
    Issue: In this case though the event only includes the processed data which possibly can lead to information loss.
    Even worse: I also loose the possibility to correct wrong business logic by replaying the events because the event data already has been calculated.

Example: Calculating a metric from some data.
Either I have to calculate the metric twice (one time in the domain model, one time in the projection)
or I have to calculate it before sending the event and including it there.

Marian Bäuerle
  • 371
  • 2
  • 15

2 Answers2

13

The flow of control is usually like this:

  • Command is sent to a command handler and properties in the command are pre-validated, like identities are pointing to existing entities and all mandatory information is present and is in correct format
  • Command handler retrieves an aggregate from repository (by reading the event stream, but this is not important) and calls the aggregate method(s) based on what needs to be done by this command
  • Aggregate methods must ensure that their parameters and the aggregate state mutually allow the operation to be performed.

  • Aggregate method then creates an event and calls this When or Apply method to handle the event

  • The event handler only mutates the aggregate state, no logic there!

  • Control flow is then returned to the command handler and it persist all new events in the store

Further actions are related to projections.

The reason to put invariant protection aka business logic into aggregate events, before applying events is because when event is generated there is no turning back. This thing has already happened. You cannot deny applying an event. Think about replaying events when recovering the aggregate from the event stream (reading from repository), how would this possibly work if one day you decide to have an if-throw combination there?

So, in short:

  • Initial logic is applied before the command is sent
  • Some additional logic is in the command handler
  • Aggregate protection in aggregate methods (could very well be also in the command handler)
  • No logic in the event handler, only state mutation

No one ever said that event sourcing would help you fixing issues in your calculations. To make an extra safety net you might want to save commands but then you will have to issue compensating events or truncate streams, which is not really what you would want to do.

Alexey Zimarev
  • 17,944
  • 2
  • 55
  • 83
  • Fixing calculation issues is definitely described as a benefit by some. See here: "Fixing errors. You might discover a coding error that results in the system calculating an incorrect value. Rather than fixing the coding error and performing a risky manual adjustment on a stored item of data, you can fix the coding error and replay the event stream so that the system calculates the value correctly based on the new version of the code." (From https://msdn.microsoft.com/en-us/library/jj591559.aspx#sec2) But other than that, thanks for the clarification. – Marian Bäuerle Nov 25 '16 at 12:31
  • 1
    If calculation takes place in the projection to the read model - this does make sense. Calculation in the event apply to mutate the aggregate state does not. – Alexey Zimarev Nov 25 '16 at 20:43
  • "No logic in the event handler, only state mutation" - What do you exactly mean by state mutation here? Modifying or updating fields? – ssmallya Jan 08 '20 at 19:46
  • Modifying, updating and mutating are synonyms. Changing an object state. – Alexey Zimarev Jan 08 '20 at 20:11
0

I suppose you have some state in your Aggregate Root. This should contain the logic about your business. So it should have enough data to create the event based on command.
The consumer of this event (query model), does the computation. So if the intent is to compute averages, it has to manage to store itself in given manner.
I did similar thing. Once it was a part of business logic, so it was in Aggregate and once it was in Query model, because it was not part of business logic, but more the metric computation.
Don't be afraid to have data stored on multiple places. The responsibility of consistency should be delegated to events distribution, not to your business logic.

hellxcz
  • 76
  • 4
  • Do you have some graphics how you did it? – Marian Bäuerle Nov 22 '16 at 13:06
  • I don't quite get the last part, so you are saying you split the logic, one part is in the Aggregate and the other one in the query model? – Marian Bäuerle Nov 22 '16 at 13:17
  • Here is nice article, where CQRS/ES is described. https://msdn.microsoft.com/en-us/library/jj591559.aspx – hellxcz Nov 23 '16 at 20:20
  • Thanks for the link, it gives a nice overview to Event Sourcing. But it doesn't really answer the question where to put the domain logic. – Marian Bäuerle Nov 25 '16 at 12:38
  • 2
    Business logic should be placed to AggregateRoot, which holds command model. This command model has to have enough information to do the business decission. Based on this decission the event is emmited. Thats flow. Event is then consumed by Read Model (Query model), but it is really just view or projection of what happened from domain (business) point of view. This point of view can be some precalculation based on system changes, organized documents (in NoSQL) ready for fast reads (with all data, so without joining tables, aggregating functions overhead...) or even generating pdf files. – hellxcz Nov 26 '16 at 09:41
  • Query model should not contain any business flows. Just projetions of business decissions. It may also contain some averages, sums computation, but that is still projection scope. – hellxcz Nov 26 '16 at 09:42