Domain-Driven Design – Managing Aggregate Root with Many Children

domain-driven-design

I'll preface this question by saying I am relatively new to DDD so I may be making some fundamental mistakes here!

I working on a project which involves the concepts of Accounts and Transactions (in the financial sense). An Account can have many Transactions entered against it.

It seems to me that Account and Transaction are both Entities, and that Account is an Aggregate root containing Transactions since a Transaction cannot exist without the Account.

However when I come to apply this in code I immediately hit a problem. In many situations it's not especially useful for me to have a list of every Transaction in an Account at all times. I am interested in being able to do things like calculating Account balance and enforcing invariants such as a credit limit, but I also want to be able to easily work with a subset of Transactions (eg displaying those which fall within a date range).

In the latter case, if I was using a TransactionRepository I could efficiently access just those objects I need without loading the whole (potentially very large) list. However this would allow things other than the Account to work with Transactions which means I have broken the concept of Account as aggregate root.

How do people handle this kind of situation? Do you just accept the memory and performance implications of loading a potentially huge number of children for an aggregate root?

Best Answer

I'd recommend being careful with the "can't exist without" rule. This talks to the concept of composition in UML/OO design and may have been one of the prescribed approaches to designing Aggregates in the original DDD blue book (not sure about that) but has largely been revised since. It might be a better idea to see your aggregates from a transactional consistency boundary perspective.

The idea is to neither make your aggregates too large, where you would have performance problems such as the one you point out, nor too small, because some invariants would inevitably span multiple aggregates - causing aggregate locking and concurrency problems.

The right aggregate size would ideally match the contours of what you modify in a given business transaction, no more and no less. In your example, if there are not many domain invariants that span over multiple financial transactions, making Transaction an Aggregate Root in its own right might well be the best solution.

Related Topic