2

I'm playing with DDD and this question pop up. How I load child Aggregate Roots? Several performance issues would arise. Imagine the following example:

public AggregateRoot1
{
     #region
        properties
     #endregion

     public AggregateRoot2 AR2{get;set;}

     public IEnumerable<AggregateRoot3> AR3List{get;set;}

     (...)
}

If I load AggregateRoot2 and AggregateRoot3 list when I get AggregateRoot1, the graph would me massive. This not seem a nice approach.

I have two options:

  1. Substitute AggregateRoot2 AR2 by Guid AR2Id and IEnumerable AggregateRoot3> AR3List by IEnumerable Guid> AR3ListIds. All AR references should be substituted by the ID.
  2. Because i don't like the IEnumerable ARListIds approach I'm thinking in remove 0...* references to AR's. All the operations that need that AR's list data should be made through domain services like David Masters sugest here

BTW, I'm not considering using lazy loading.

I'm looking forward to ear your opinion about child AR's loading. Thanks

Community
  • 1
  • 1
JPP
  • 360
  • 6
  • 22

2 Answers2

7

Ideally, references between aggregates should be by identity only. This is option 1. However, you should evaluate each reference to see if it is required for consistency of the reference holding aggregate. Sometimes, the relationship between two aggregates can itself be made an aggregate to be loaded individually. Overall, take a look at Effective Aggregate Design by Vaughn Vernon for in depth analysis of the various trade-offs when designing aggregates. This is also what David Masters points to in the linked question.

eulerfx
  • 36,769
  • 7
  • 61
  • 83
  • @eulerfx-Thanks for your reply. I agree about reference to another aggregate root being with the ID, but how about a collection of AR's. Should converted in a array of AR's ID's? I never saw an implementation similar, the examples that I see is only a relationship of 1-1. – JPP Mar 13 '13 at 16:22
  • Moreover, since Guids are not part of the ubiquitous language, if you really need them to ensure the business invariants, you should use [shared identifiers](http://epic.tesio.it/doc/manual/shared_identifiers.html) instead. – Giacomo Tesio Mar 13 '13 at 16:28
  • A collection of AR ids would work, take a look here: https://github.com/MarkNijhof/Fohjin – eulerfx Mar 13 '13 at 17:08
  • i agree with eulerfx and want to add that i don't think loading the entire object graph is a big problem in general as this is what most DI containers do unless those object load huge amounts of data from network or hard drive. – Ibrahim Najjar Mar 14 '13 at 01:44
0

If the graphs are getting too massive and you can't use lazy loading, it's probably a sign that your model could use some work - you likely have entities which should properly be their own aggregate roots.

By using factories and repositories, large objects can be bettered managed. You can cache large objects, or implement a singleton pattern within the factory of AggregateRoot1.

One reason to follow DDD is the encapsulation of complexity. But having IDs of non-root objects breaks this encapsulation. While there can be performance considerations, prematurely optimizing code for performance does not often create good software.

Mathieson
  • 1,698
  • 2
  • 17
  • 19
  • I agree with you, but the point of the question is having references to child aggregates root, or your aggregate root never have references to another aggregate root? The point is in the load of a child aggregate root. – JPP Mar 13 '13 at 22:20