0
votes

I've been doing a lot of research on DDD and have been stumbling a bit on the concept of Aggregates vs Aggregate Roots.

Say I'm trying to model a space game that exists in a strict hierarchy, with a Sector Entity that wraps around everything contained within it. It can have a collection of PlanetarySystem, each of those can have a collection of Star, the stars can have a collection of Planet which themselves can have a collection of Moon

I want all of these objects to either be associated with that Sector, situated nicely in the hierarchy, but it can also be associated with no sector. Each item can have a 0 or 1 relationship with the object in the hierarchy above it... floating in the ether if need be. I want to be able to delete a Planet without deleting all the Moon entities it has, but it can be done optionally.

Am I wrong to think that these should each be their own Aggregate Root in this scenario, with references to the Aggregate Root instances that they contain? Or should the Sector be the actual Aggregate Root, orchestrating everything as the object at the top of the hierarchy?

2

2 Answers

1
votes

An aggregate root should never contain a reference to another aggregate root. You should use either an id to reference an associated aggregate or a value object containing the id and some other pertinent data.

Anything that is floating in the ether would be an aggregate root since it has a lifecycle of its own.

I reckon the hierarchy should just work in a unidirectional manner as far as the domain is concerned. If you need to query lower level items based on higher level containment then you either need joins or need to denormalize the relevant higher level identifiers/data into the lower level items.

My advice would be to attempt to keep any aggregate a single level deep but if that isn't practical then try something deeper but it gets unwieldy rather quickly.

0
votes

Remember something can be an Aggregate in one use case and an Aggregate Root in another. If your use case is AddPlanetarySystemToSector, then Sector is your Aggregate Root. If your use case is AddMoonToPlanet, then Planet is the AR.

The difference is that an AR should not be saved unless it and all Aggregates it owns satisfy all business rules. The higher level your AR, the more business rules you must test and satisfy. Therefore your use cases should be a specific as possible and target the proper AR.

If this poses problems, a work around is to have ARs own value objects instead of aggregates. So a Sector would own PlanetarySystemVOs. If the Sector needs to modify a PlanetarySystem, it can launch a PlanetarySystem use case that performs the proper action.