I've been studying DDD for the past several days, using both Evans and Nilsson's books. When I start trying to apply the concepts to my projects I'm having some difficulty identifying using aggregates. I'm attaching the current model diagram I'm playing with, only showing the connections between the classes -- I've indicated the multiplicity, but not the directionality... as the directionality is one of the key things I'm trying to work out with regards to what that means for the aggregates.
The application has two main aspects -- registration for competitions and result tracking across competitions. This dual nature is what's causing my problems.
In the first case just about everything is always scoped by a Competition. Having a Competition Aggregate that includes Competition, Style, Dance, Level, Event, Registration, and Registration Entity would make total sense. The connection between Registration Entity and Person would be unidirectional (navigatable to Person). Going the other way would require navigating from Person to Competition and then asking the competition for which events this person is in. This is great and reflects the way the business works and thinks. This would lead to three aggregates -- Competition, User, & Person -- and I'm very happy.
In the second case (result reporting) the Result is the central concept. Their are two primary queries: a) List the results for a given event b) List the results for a given person
Case a is easy under the model outlined above. Simply include Result in the Competition Aggregate.
Case b seems to start throwing me off. The business would think of a set of results attached to a person. This seems to require that Result be an aggregate (to allow Person to hold a connection to it). But now Result needs a connection to the Event and Registration Entity its for. And it can't pull them into its aggregate since the registration side of the house needs it. So suddenly both Event and Registration entity have to become their own aggregates as well. This causes a further cascade that forces the style/level/dances into their own aggreate so that both competition and event can refer to hem. Suddenly every object is its own repositoty...
The other option I've though of is to introduce some sort of parallel implementation of the Competition/Event concept. One set for registration issues and one set for result/reporting issues so that the two areas can have appropriate aggregates. In some sense these two aspects should be in separate modules anyways, but it seems like there would be some very odd duplication of the classes involved.
Am I making any sense with how I'm thinking through this? Can anyone offer any advice for teasing apart aggregates in DDD when you have use cases that basically require orthogonal navigation through the object model?
The obvious and not very helpful reply would be that your model isn't sufficiently representative of your domain - yet. Also you are talking about "reports" - the domain model aims to model the business behavior which does not necessarily present data in a structure that is optimal for reporting. Often it is simpler to drive reports directly from data that is returned from relational queries (there are just too many ways (i.e. views) to look at the same data).
Now that being said and taking your current model at face value it is apparent that your Registration/Result cannot be part of another aggregate because both the Competition and the Person have at least an implied relationship with a collection of Registrations. The Competition is "interested in" the collection of registrations against the Competition, while the Person is "interested in" a collection of all the Person's registrations. So the Registration repository would need a findByPerson and a findByCompetition method.
Hmm I think I'm getting ahead of myself... The current port hasn't gotten to dealing with either registration or reporting or non-user people.
So at present I would be fine only having Competition and User Aggregates/Repositories. And I can cross the other bridge when I get there (TDD based development).
However I am trying to apply the ideas from DDD, so I sketched up a portion of the domain model (shown in the first post). Obviously I missed a lot of important concepts. Here is a slightly more involved version (I'll admit I got a little lazy with marking multiplicities)
The main difference really is the Policy objects. Two of which, registration and eligibility, work to constrain the legal registrations given either current registration or past results, respectively. This changes the requirements on result list from pure reporting to actual domain knowledge use...
These added pieces make my start to feel better about having Competition/Event/Result/User/Person all as top level aggregates. Though it still feels like everything is becoming a root. And I'm a little concerned about how to deal with the objects that descend from the EventDescriptor (Level, Style, etc).
Each competition has its own list of these -- they shouldn't interact. If Competition A changes a name of a level it shouldn't change the name in Competition B. However each Event is restricted to being described by a level from its containing Competition. And if the name of a level is changed in competition A, all of its contained events should reflect that change.
I don't see how this invariant can be maintained without Event being in the same aggregate as Competition... Nor can I really tell if EventDescriptors are entity or value objects.... Within the Competition/Event aggregate it acts as an entity object -- shared references, change one, change all....
However if Competition and Event are in separate aggregates then they can't share the event descriptors as you aren't allowed to share the entity between two aggregates....
Joined: Aug 19, 2005
Originally posted by Eric Nielsen: So at present I would be fine only having Competition and User Aggregates/Repositories. And I can cross the other bridge when I get there (TDD based development).
These added pieces make my start to feel better about having Competition/Event/Result/User/Person all as top level aggregates. Though it still feels like everything is becoming a root.
Reading both of your posts gives me the impression that "Registration" or some concept in its neighborhood is actually at the core of your problem domain and that Competition/Event and User/Person merely help to establish the context in which the Registration exists. Would that change in perspective help?
Also if the event could be demoted to a value object (as in "type of event given by the competition") then Registration could reference the Competition as the aggregate root and simply identify the "event type" it is for.
I might be going down the wrong path here but I'm imagining an application where you establish a context (either competition or person) that identifies the relevant registrations to formulate a search. Once you have an individual Registration you can easily navigate to the other context relevant to that Registration.
Joined: Dec 14, 2004
Thank you. Something for me to ponder for a while.... Registration is a key/fundamental concept, but I'm not sure I'll be able to convert an event to a value object.... If I can, I think your suggestion would help the model start to solidify around a new core.