Reputation: 3413
I'm pretty new to implementing a DDD + CQRS + event sourcing system. The following is the business context I'm modelling:
A
User
can create anOrganization
. AnOrganization
can have multipleMembers
.Members
can either beRegular
members orAdmin
members. The user that creates the organization is by default the firstAdmin
.
In particular, im trying to represent the act of creating an organization in an implementation that is domain rich. The following is what I have so far.
class User extends Aggregate {
constructor(
public readonly id: UserId,
public readonly name: Name,
public readonly email: Email
) {
super(id);
}
createOrganization(orgId: OrgId, name: Name) {
const creator = new Member(orgId, MemberRoles.Admin, this.id);
return new Organization(orgId, name, [creator]);
}
}
class Organization extends Aggregate {
public readonly members: Member[];
public readonly name: Name;
constructor(
id: OrgId,
name: Name,
members: Member[],
) {
super(id);
this.name = name;
this.members = members
}
addMember(member) { /**/}
removeMember(memberId) { /**/}
}
I like the fact that I have a .createOrganization()
method on the User class since it illustrates the fact that a user has the ability to do so. But where should I raise UserCreatedOrganizationEvent
? Should I do it in the User class? Is it not wrong to create events in one aggregate (User
) which would then be used to directly hydrated another aggregate (Organization
)? I keep hearing that each aggregate should hydrate themselves from their own events to ensure invariants are always ensured. Then does it make more sense to have a static create
method on the organization? But I can't raise an event associated to my aggregate from a static
method. Any thoughts on this would be appreciate.
Upvotes: 0
Views: 50
Reputation: 3260
Creating the Organization aggregate as part of your User aggregate is wrong because the User aggregate ends up understanding the intricacies of the Organization aggregate. They end up being tightly coupled.
The Admin user is just one of the many details that go into creating the organization. I would think of it as an Authentication/Authorization concern that would validate if the user performing the action should be allowed to go through it.
And yes, typically, you would create a factory method (a class method) within the Organization aggregate that would instantiate the Aggregate and raise an event on the instantiated aggregate object. The factory method would be invoked by a Command Handler, handling the command to create an organization.
Think of the contra argument to clearly understand why the user creating the organization via the user aggregate is not sustainable. Technically, every single action in your application would be performed by a user. That does not mean that the user aggregate is responsible for all other Aggregates in the system.
Upvotes: 1