I am fairly new to implementing CQRS and Event Sourcing, while applying rules of domain driven design. Let's say I have an Order
aggregate and inside it is a list of OrderLine
entities. I'm using this model in the context of an event-sourced system (with CQRS) and so the state changes are mainly driven by events. Changes to the aggregate should run through the Order
as it serves as the aggregate root. When, for example, an event like ItemAdded
is raised, the respective Order
aggregate will be called to apply it to itself, something like order.apply(itemAdded)
. This will then trigger a creation of a new internal OrderLine
object to represent the newly added item in the order. In terms of implementation, does it make sense for the new OrderLine
object to apply the event to itself directly? Or, should I just leave it to the Order
aggregate to create the OrderLine
object itself through a constructor?
Which one is more appropriate?
void apply(ItemAdded itemAdded) {
OrderLine orderLine = new OrderLine();
oderLine.apply(itemAdded);
orderLines.add(orderLine);
}
or
void apply(ItemAdded itemAdded) {
OrderLine orderLine = new OrderLine(
itemAdded.getId(),
itemAdded.getProductId(),
itemAdded.getQuantity(),
itemAdded.getPrice()
);
orderLines.add(orderLine);
}
For now, I think the first approach is more concise and easier to understand. There are events whose fields can get very lengthy and having the internal entity itself deal with construction makes the code cleaner. The problem, however, I think, is that, by providing an apply
method in the OrderLine
, I'm opening it up for possible mutation outside the context of the Order
. If I provide an accessor, say, getOrderLines()
, in Order
, even if I make the collection/list itself unmodifiable, the objects contained will still be mutable. One way to prevent this is to return clones, but that can get a little cumbersome to implement for fairly complex nested entities.
To address this, what I'm thinking is to keep the apply
method in OrderLine
class, but limit its visibility. The approach that gives me most flexibility in this regard is to make OrderLine
a nested class under Order
class. This means I can keep the apply
method private but still accessible within the context of Order
class. However, this could mean a very long Order
class especially if I need to add more nested entity in the future.
Alternatively, I can limit access to the apply
method at package level, which means I have to do some restructuring to limit all domain classes in one package.
Any advice regarding this?
ItemAdded
is an event that is important to the system, which also affects theOrderLine
entity internally.Email
value object. When the user changes email theEmail
VO is not responsible for holding this information, theUser
AR is.