1
votes

1) a) Entities within an Aggregate should only be accessed via Aggregate root. While it is possible for the root to pass transient references to internal entities to external objects ( for the duration of a single operation ), I assume in most cases if external object needs to performs some operation on internal entity, it should call method(s) defined on the Aggregate root ( contrived example - Order.SetOrderLineTitle(...) )?

2) Only AGGREGATE roots can be obtained directly. All other objects must be found by traversal of associations.

a) When we say that external objects should access non-root entities by traversal of associations, do we mean they should call methods on Aggregate root ( e.g. Order.SetOrderLineTitle(...)), which in turn would perform operations on internal objects or do we mean that Aggregate root should pass a reference to internal entity to an external object or both?

Thank you

2

2 Answers

4
votes

1) Yes, this is the best way for the aggregate to maintain its integrity. Some say that this can result in aggregates with very large number of methods, however in that case there may be multiple aggregates at play.

2) Ideally, the aggregate would perform the required operation without passing references. There may be a case where passing a reference makes sense, but this should be implemented with care as it makes reasoning about integrity more difficult.

2
votes

I assume in most cases if external object needs to performs some operation on internal entity, it should call method(s) defined on the Aggregate root

Just to add a slightly different take on this, the reverse approach might also be used. Adding methods to the Aggregate Root in most cases forces you to divide your domain in very small Aggregates lest the roots become bloated, violating SRP. This slicing might come at the cost of sacrificing the natural business cohesion of your Aggregates.

Instead, you could decide that in most cases you will let external objects get transient references to internal entities and manipulate them as they wish. In rarer cases, especially ones that imply enforcing invariants that span across multiple entities, it would be a better idea to implement these operations directly on the Root.

That approach is discussed here : https://groups.google.com/forum/#!topic/dddcqrs/mtGanS39XYo

the way I see it is although an aggregate root is responsible for the life cycle of entities within, that doesn't mean that it should be the exclusive interface ( other than returning a specific entity) to all methods called on any item within the aggregate.

Overall, the final decision will depend on whether you want to design your aggregates primarily with domain/functional cohesiveness in mind or you first want to think of them as transactional safeguards.