domain-driven-designcqrsdddd

DDDD: Event data


I'm trying to get my head around DDDD in Greg Young's style.

There is much talk about how to implement DDDD with CQRS+EventSourcing and there are some sample implementations ... and altogether it can be quite confusing...

In Gregs view aggregates don't have getters or setters - just state-changing methods which emit an corresponding event.

Basicly a event decribes a state-transitions that happend in the past. It's data describes what changed.

Some say, that this data can be "enriched" by additional data.
Where can this additional data come from?

i.e. I have User and Usergroup - both aggregate roots (can exist independently, have identity). User has a method called AddToUsergroup.

public class User : AggregateRoot
{
    // ...
    public void AddToUsergroup(Usergroup usergroup)
    {
        // validate state
        RaiseEvent(new UserJoinedUsergroup(this.Id, usergroup.Id));
    }
    // ...
}

public class Usergroup : AggregateRoot
{
    private string _displayName;
    // ...
    public void ChangeDisplayName(string displayName)
    {
        // validate state
        RaiseEvent(new DisplayNameChanged(this.Id, displayName));
    }
    public void Apply(DisplayNameChanged e)
    {
        this._displayName = e.DisplayName;
    }
    // ...
}

If I would like to "enrich" the event with the name of the Usergroup (for debug reasons or something like this), how would I do that?

Injecting such things as repositories into User is not allowed (am I right here?!?), like

Bottomline questions:

And (little off-topic but the sample is here)

Looking forward to your answers!

Lg
warappa


Solution

  • Should something like repositories be injected to aggregate roots?

    No and there is no need to in this case. It can be appropriate to pass a domain service to a behavioral method on an aggregate, but again, not needed in this case.

    Should a event only use data available through parameters and internal state of the aggregate?

    Yes, the original domain event should be such that it can be easily built by the aggregate and can be replayed in a deterministic fashion.

    Should events only contain the minimum data describing the state-change?

    Yes. However, to address requirements of external subscribers, this is where content enricher comes into play. To dispatch a domain event externally, it is first committed to the event store then you can dispatch in the same tx or have an out of process mechanism which publishes events externally. At the point of publishing externally, you will normally use a different contract for the message since subscribers may need more than what is on the domain event itself. In this case, you need the user group name. The publisher, then, can pull up the user group name and place that data into the enriched event. This publisher can have access to a read-model repository for user groups which would allow it to retrieve the name.

    Should AddToUsergroup take an Guid instead of an full aggregate root?

    Yes. Passing the entire aggregate may not be possible and also creates the illusion that something other than the ID may be used, which should not be the case.