7

So, I have Aggregate root that has some sub-entities with some sub-value objects (classic DDD design). I wanted also to use Event sourcing in Aggregate design. In AppService layer I receive Command, decode it and call method on the aggregate (I understood that this is common practice in ES):

public class AgRoot {

    private Int id;
    private List<SomeValueObj> objs;

    public void doSmthn(SomeValueObj arg){
        //check if arg (some logic) can be applied to this aggregate
        for(SomeValueObj o : objs){
            if(!o.canBeUpdatedWith(arg)){ throw Exception(); }
        }
        GenEvent event = constructeventfrom(arg);
        this.causes(event);
    }

    public void when(GenEvent event){
       //set all fields in this aggregate
       for(SomeValueObj o : event.objs){
            o.applyChangeActually(o)
        }
    }

}

Now, my question is: why we here have to check if this arg can be applied, then create event and only then we actually apply changes (write basically data values to object). Seems like we are separating part where we check if arg content is valid and can be applied from part where we actually copy values from arg to update object state. In standard DDD without ES, I would only pass arg down the object graph to the objs list objects - they would handle all the checking and updating by themselves.

Am I misunderstood ES concept?

UPDATE

Just to clarify a bit more: if I don't just have to do simple checks like if arg!=null (which is the usual thing all ES examples have) - e.g. before updating each SomeValueObj in obj list, I have to run expensive calculation and a lot of logic in each of objs objects - and possibly partially update this objects with new data in order to proceed with calculations - seems like when(GenEvent event) function will theoretically do the same thing again?? Seems like chicken-egg problem to me.

This looks like the thing I'm talking bout Complex Aggregate Structures

3
  • When I read your headline, my questions what kind of event you want to raise? Events are always in the past. - New Customer is created. - Customer <M> is updated. - New order <N> was created. Are you going to raise an event "Customer will be changed"? Who should do what with that information? There are no new information in the system. No jobs need to be trigger like scaled the new photo of the customer. Answer: Always raise an event past the change. Commented Dec 23, 2016 at 8:40
  • This is OK, but in event sourcing system you have to raise event before you actually send event to event handler that is going to modify state (since same thing is used in reply of events). The problem I have is that in order to generate event I possibly need to modify current state of aggregate, or clone aggregate in-memory that is going to be used as temp modification playground or apply same changes twice (for the first time aggregate is updated). Commented Dec 23, 2016 at 11:52
  • @bojanv55 It seems you are looking for deferred validation, which would be done externally, perhaps by a dedicated validator object. Sometimes it's just easier to transition into state and then check if that state is valid. However, it's rather rare that pre-emptive validations can't easily be performed but is possible when you have a flow of actions that are causing multiple state mutations where every mutation may invalidate the rest of the process.
    – plalx
    Commented Jan 5, 2017 at 21:41

1 Answer 1

2

Now, my question is: why we here have to check if this arg can be applied, then create event and only then we actually apply changes (write basically data values to object).

The main reason: doing it this way ensures that the contents of the event, and the state of the aggregate remain in sync.

In many cases, we simply copy state from the event to the in memory entity, and the distinction doesn't make much sense. But in the more general case, the state of the entity is derived from the state in the event, and you want to make sure that you perform the calculation the second time (when you are reloading the aggregate from its history) exactly the same way that you did the first time. The easiest way to ensure that this happens is to use the same code path in both cases.

If you like, you can think of the action happening in two parts

  • calculate the event (this is query; the calculation doesn't change the state of the aggregate at all)
  • apply the event (this is a command, which doesn't move the entity from its current state to its next state).

So teasing these two actions apart is consistent with Meyer's principle of command query separation.

This looks like the thing I'm talking bout Complex Aggregate Structures

Yup.

I find that keeping the event calculating query separate from the application of those events helps to keep the complexity of changes under control - in the query phase, each entity merges its own events with those of its subordinate entities, and bubbles those upward toward the root, that will in turn push them down the command side of the object graph.

1
  • Do you maybe have some code sample of this kind of more complex event generation? This introduction of ES inside more complex domain seems to me like polluting the domain and making it much more unreadable. Commented Dec 20, 2016 at 21:33

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.