After focusing mostly on the event sourcing and XNA parts of the project I recently shifted a bit to focus more on domain-driven design (DDD). I found I was accumulating a lot of junk on what was fast becoming a godlike aggregate root and felt there was a ton of room to clean things up. Things went smoothly for a while but I found my ability to model the domain was limited a bit by the fact that I could only raise events from the aggregate root. That's just how the SimpleCQRS code I started from was implemented. After a little searching it seemed the common solution is to allow the aggregate root's child entities to raise events as well and then merge them into one big stream for the whole root.
I hacked up the SimpleCQRS example a bit to introduce the the entity concept. Here are some rambling thoughts on my implementation that I guess are mainly for me to come back to later:
- All child entities must set the Guid EntityId property. It currently forces guid but I don't really like that restriction for a few reasons: 1) I prefer entities to have a natural id if possible, 2) The entity id doesn't need to be global, it only needs to be unique within the aggregate root. So a Globally Unique ID might be a bit overkill. Actually I think it will be pretty simply to change this, can probably just make a custom EntityId that initially wraps a Guid and go from there.
- All events have an EntityId property that is filled out if the event is raised by an entity and left null otherwise.
- In the constructor of every entity I have to register which events it handles otherwise it will handle none. It bothers me a little so see this registration in every entity's constructor but I guess it's not a huge deal so I'll let it go for now.
- When an aggregate rebuilds itself from an event history it must route all the events that originated from an entity back to the right entity. This is why both Entity and Event require an EntityId property. The current implementation is kind of dumb though because the event is applied to the aggregate root in addition to the entity. Typing it out makes that sound extra double dumb and I should go remove that soon.
- I chose to have each child entity delegate to the aggregate root to raise events. This way the aggregate root maintains a single list of changes and since new events are added to the end they are always in the right order. I saw other implementations that involved each entity having its own set of events that are then merged and ordered. This just feels simpler.
Wow, alright. Time for Tosh.
No comments:
Post a Comment