Command Handler with Event Sourcing - Newbie Question

569 views
Skip to first unread message

Leo Leon

unread,
Feb 28, 2017, 12:25:21 AM2/28/17
to DDD/CQRS
Hi Guys,

Long time lurker, first time asking question here...
I'm currently trying to implement an event source system for a small part of an existing application. I have a few questions regarding several implementation.

Beforehand, the goal is to be able to query the object at any particular point in time, and hence, the ability to rebuild the aggregate model itself to that point in time is a critical requirement for the business case that we currently have.

1. The usual command handler pattern contains for example: repository.Save(someAggregate) inside the pattern. Supposedly if we would like to replay the events to a particular time, do we just disable the repository update, or do we create a separate handler to handle updating the object separately than saving to the repository (hence the ES modeller updates through that handle instead)? The problem here at the moment is that if we use the same handler, it will be update the repository as well.

2. Several aggregates of the current application model have some problem of (what I believe) is its value objects. Mainly is that, they reference them by Id. Removing it from the aggregates basically by marking those object for deletion (rather than removing it via aggregates). This causes a major issue. In a small ES prototype that I have, as the changes gets applied, the value objects does not have any Id correspond to it, and cannot be removed / updated / add properly.

Any pointer in general for starting small prototype of ES is very much appreciated as well.

Thank you!!

~ Leon

Ramin

unread,
Feb 28, 2017, 7:48:59 AM2/28/17
to DDD/CQRS
Hi Leon,

there seems to be some confusion.

1. Querying an object is done via the read side, not the write side. You dont query the object (I guess you mean aggregate), but a read-side representation of it. That's basically what CQRS stands for. There usually is one command handler per aggregate root. It gets the aggregate/current state from the repository, calls command methods on the aggregate, and saves it back to the repository. The repository always holds the current state of the aggregate. When the aggregate changes state, it does so by raising events (if you use event sourcing, which you are implying). The aggregate "consumes" these events as it raises them, i.e. it always has current state. In order for the read side to have a representation of the aggregate state, event handlers will handle these events and build one or more read models from them. How the event handlers "get" the events is up to the infrastructure (push/pull, synchronous/asynchronous, etc.) Now, if you want to query for the state at any particular point in time, you don't query the object, but some read model built by one or more event handlers. If you want to query for the state at a particular point in time, you can have an event handler which only handles events until that point in time and builds a read model for that point in time, which can then be queried. Building a snapshot like that every time the state is to be queried may have performance issues. It would be better to have one event handler to build a read model which can be directly queried for particular points in time. There are different ways to do this, depending on requirements.

2. Referencing value objects by Id is wrong by definition. Entities have Id values, value objects do not by definition. If you mean lookup values, and these have Id values, then they are not value objects.

Hope that helps
Cheers
Ramin

Leo Leon

unread,
Feb 28, 2017, 7:45:13 PM2/28/17
to DDD/CQRS
Thanks Ramin.

Another question implementing ES in an existing system, how do you initialize the existing database into the ES?

~ L

Ramin

unread,
Mar 1, 2017, 3:00:29 AM3/1/17
to DDD/CQRS
By having events together with event handlers which initialize the existing state. Basically these initial events represent the current db state, and if handled by event handlers, the exact db state (read model) will be the result.

The initializing events will probably simply be CRUD events (Create and possibly Update events). Remember that a domain model is driven by behavior. I have built some systems which are basically CRUD using event sourcing, which can be a good start for learning the technical aspects of event sourcing.

Cheers
Ramin

Leo Leon

unread,
Mar 2, 2017, 7:54:54 PM3/2/17
to DDD/CQRS
Thanks for the answer, that clears up some things for me.

Another question related to the question no 2 I asked above. In DDD, I recalled that an aggregate may have an entity or value objects inside it. In our case, the Ids are database generated. When replaying the event for the aggregate, how do we assign the Id for the entities inside the aggregate?

The event could be for example ProductSpecificationsAdded, in which the command could be adding more than 1 specifications created for the specific product. In this case, the product is the aggregate root, and the specification could only be added through Product domain model. The specification is however a complex entity on its own.

~ L

Ramin

unread,
Mar 3, 2017, 3:08:18 AM3/3/17
to DDD/CQRS
I will ask anyone to jump in here for their own piece of advice.

The way I see it is that a product and a specification have their own life cycles. You can have the product reference specifications by their Id values. In this case the product has no control over the referenced specifications and their invariants, and will allow for the referenced specifications to change freely. On the read side, you can have a model which joins the product with the referenced specifications to represent the product in its entirety with all specifications. Note that the product in the domain does not have full control over its read side representation in this case, because it has no control over the referenced specifications.

The other possibility is to copy the specifications, or some properties of them, to the product. Now the product has full control over its specifications. It can enforce invariants, and will not change if some specification (template) changes. Think of the product as a written document, including all specifications. Do you want the document to read "Product 1: Specifications { [1: Id 71, 2: Id 5, 3: Id 45] }" with possibly changing specifications being referenced by their Id values?  Or do you want the document to read "Product 1: Specifications { [ 1: "Details of specification 71", 2: "Details of specification 5", 3: "Details of specification 45"] }. Now the product has full control over the specifications, and it will not change automatically if a specification changes. The "Details of a specification" can include a reference to the "specification", possibly with the used version. It can also only include the properties of the specifications you don't want to reference. You can always update the specifications in a product by some mechanism, for example by manually triggering an update. Of course, if you want all products to always update their specifications if a specification changes, you may as well reference them.

So how you do it depends on the requirements. Also, it is sometimes not easy to move from a relational database view over to a domain driven view. In "the database think", it makes sense to put a reference to specifications on the products, and use the product in different use cases, because it is "the product". In the "domain think" you may determine that a product in one state can reference specifications, and once it is "locked in" it needs to be invariant, and thus will contain the specification details instead of just referencing them. You would probably have two different aggregates for these two product states, because they mean different things.

Hope it helps,
Cheers
Ramin

Ramin

unread,
Mar 3, 2017, 3:11:49 AM3/3/17
to DDD/CQRS
Just to clarify my last sentence "You would probably have two different aggregates for these two product states, because they mean different things.". I don't mean instances of the same aggregate type, but two differenct aggregate types. Just want to avoid confusion.

Cheers
Ramin
Reply all
Reply to author
Forward
0 new messages