Aggregate relationships in Domain Driven Design - domain-driven-design

I have a question related to relationships between aggregates in Domain Driven Design.
I have the following situation: I have an aggregate (questionnaire) which has some children (questions). The questions are entities, but because they are inside the questionnaire aggregate they can have local identities (i.e. question with id 1 in questionnaire with id 1234; I can have another question with id 1 but in another questionnaire). So to refer to a question you always have to qualify it with its parent questionnaire id.
On the other side I have another aggregate (collection campaign) which stores data (response set) for the questions in a questionnaire (the collection campaign points to the questionnaire by its id, and a response set points to a question again by its id). I can have several collection campaigns (which took place at different times perhaps) and each collection campaign stores different response sets, but for the same questionnaire (and questions).
So my question is: have I designed this well (according to DDD)? Or do I have to keep the questionnaire and questions as separate aggregates of themselves in order to refer to them from the collection campaign/response sets?
I hope this makes sense and thank you.

Ask yourself this: what are the invariants that should be protected?
In your case you must ensure that a question that is answered during a campaign exists (i.e. its index is between zero and number of question in the questionaire - 1) and its an allowed one; other invariant could be that a questionaire must not be modified after at least one question is answered; in any of these cases the campaigns must be synchronized with the questionaire. I see at least 2 solutions:
The simplest solution would be to have a single big aggregate, the Questionare aggregate, with questions, campaignes and answers as sub-entities so you can protect those invariants; this has some performance implications, but only you should know is it is acceptable.
The second solution would be to use a event-driven architecture like CQRS+Event Sourcing. In this case you could have separate aggregates and keep them in sync using a simple Saga that forwards some events from Questionare aggregate (like QuestionAdded, QuestionRemoved) as commands to Campaingn aggregate. I prefer this solution as better separates the responsabilities.

Related

Domain Driven Design - Can you use a simplified existing Aggregate in a different Aggregate Root

I have an aggregate called Survey - you can create a Survey, send a Survey and respond to a Survey.
I also have an aggregate called Person. They can receive a Survey and respond to a Survey. This aggregate includes demographic information that describes the Person.
I think my Survey aggregate should contain a list of people that have received the Survey. That would include the date they received it and any of their answers, if they have responded. But I feel like I don't need most of the demographic information that would normally come along with my existing Person aggregate.
I tried playing around with different concepts, like calling a send a "Delivery" and calling the employees "Recipients", but the business doesn't speak in those terms. It's just - "I create a Survey and then I send that Survey to people".
So does it make sense to create a different Person aggregate just within Survey? The action of sending a Survey to someone exists as records in the DB, along with responses to the Survey. Is this a better use case for Value Objects?
As soon as you use phrases like "I don't need all of the...data" or "this is like that but with a few more attributes but not these original ones" you are implicitly introducing the notion of a projection of an entity from one bounded context into another bounded context.
In your case a Person is in a different bounded context from a Person taking a survey (I will call the latter a SurveyParticipant) because even though it's the same actual person taking the survey, the focus of the two entities is different.
Here's a possible solution to your problem (expanded a bit, just for context).
Person is projected into the Survey Taking bounded context as a SurveyParticipant. As a bonus, Survey is really the definition of a survey, but SurveyInstance is a Survey that can be/is taken by these SurveyParticipants.
SurveyParticipant is not a Person. A SurveyParticipant is a person who is (going to) participate in completing a SurveyInstance.
Bottom line,
Can you use a simplified existing Aggregate in a different Aggregate Root
Yes. You do this by projecting the data from one aggregate to an entity in another context (at least in my proposed solution).
So does it make sense to create a different Person aggregate just within Survey?
Sort of. An aggregate can never contain another aggregate, but it can refer to one in the same bounded context. I didn't do this in this solution. The alternative, as shown, is that an aggregate can contain information from another aggregate as a projection of that other aggregate.
This is a strategic design problem.
I think you have two Bounded Contexts here, so you should split your Person domain model between them. Person from Survey Context will contain only data and behavior you need for your Surveys. Person from other one (Marketing Context for example) covers marketing team needs.
Here is an example from Martin Fowler's blogpost about BC's
So you're almost right with other aggregate, but it is not a simplified version, it's a separate one.

DDD Aggregate Design

I'm trying to decide whether to use a single aggregate or if I can get away with using three separate aggregates.
I have three entities, Quiz, Question, and Answer to represent multiple-choice quizzes. Conceptually, a quiz contains multiple questions, and each question contains multiple answers. Each answer belongs to only one question and each question belongs to only one quiz. A separate quiz is created for each user.
One business rule is that once a quiz is submitted answers can no longer selected or deselected. The quiz's grade is calculated when it is submitted, so if an answer is changed after the quiz is submitted it would put the domain in an inconsistent state.
If I model this as a single aggregate with Quiz as the aggregate root, this is simple enough to enforce. If I model the domain with each of these entities as its own aggregate root then I would have to check at the application level, rather than at the domain level, whether a quiz is submitted or not before selecting or deselecting an answer.
This is a simplified version of what I would do with separate aggregates at the application level:
async execute({ quizId, answerId }: Request): Promise<Response> {
const quiz = await this.quizRepository.get(quizId);
if (quiz.submitted) {
throw new AnswerSelectQuizAlreadySubmitted();
}
const answer = await this.answerRepository.get(answerId);
answer.select();
return await this.answerRepository.save(answer);
}
What I would do with a single aggregate at the application level:
async execute({ quizId, questionId, answerId }: Request): Promise<Response> {
const quiz = await this.quizRepository.get(quizId);
// quiz entity enforces the business rule
quiz.selectAnswer(questionId, answerId);
return await this.quizRepository.save(quiz);
}
I prefer the small-aggregates model because the user can update multiple answers simultaneously without database failures due to optimistic locking at the Quiz level.
My concern with it is that a "submit quiz" command and a "select answer" command could be fired in rapid succession, causing an answer to be selected on an already submitted quiz. My intuition is that the application-level validation I showed above won't necessarily prevent this from happening.
TL;DR: Will an application-level check on a separate aggregate work in an asynchronous environment or will I be forced to include all three entities in a single aggregate?
This single statement
Each answer belongs to only one question and each question belongs to only one quiz.
renders the entire rest of the question moot. The answer is that you'd use a single aggregate in your domain model.
How you deal with database contention is a separate, albeit important, concern that could perhaps be remedied by using a document database where the document is the aggregate root and its children.
My answer would be different if your domain was richer.
For example, you could have a Question aggregate with a list of Answer and a ValidAnswer. If you randomly generated a Quiz and selected from a list of Question aggregates, then you'd have a Quiz aggregate with a list of QuizQuestion (or QuesionReference or some such) as children. Thus your Quiz aggregate references (not owned/separate aggregate) Questions through an (owned/value object) QuestionReference. In this scenario, you're safe from some contention because you're still updating the Quiz aggregate, and not the Question aggregates.
Dealing with click-happy 😀 users
Your domain model in either case must check that answer selection can't occur after quiz submission. That's logic on your Quiz aggregate.
Now, that said your concern that a race condition could occur is valid. The simple model is easy; a single aggregate to a single transaction or single document naturally prevents the race condition; just use normal db concurrency options. But, the two-aggregate model does too! Why? You're still updating only the Quiz aggregate. The Question aggregates are referenced, and don't change (well at least in quiz-answering context).
Finally, in all of the above, Answer does not seem like a separate aggregate or entity. How can an Answer mean anything without being tied to a Question? Maybe in Jeopardy!?

Relationships between multiple aggregate roots

In many applications, I deal with users and finance companies (as an example) and I have long been struggling to model the relationship between the two according to Domain Driven Design principles.
In my system I can do the following:
Add a user to an existing finance company.
Add a finance company to an existing user.
I believe both are aggregate roots... Finance Company and User.
How do I model the relationship between the 2? Is it FinanceCompany.Users? or User.FinanceCompanies? Is it neither? Or am I missing knowledge of some key DDD concept(s)? The problem is if I choose one way over the other, the code is more understandable / clear from one aggregate root entry point, but not the other. Sometimes there are cases where it makes more sense to navigate to a Finance Company and add users to it, and other times there are cases where it makes more sense to navigate to a specific user and add finance companies to the user.
Is there some better way to approach this, maybe through repository methods? Is there some key concept I am not getting or understanding here? It doesn't feel right to assume the relationship between Finance Company and User belongs under either of the 2 ARs. When I store the relationship I have to store it in a table named FinanceCompanyUsers or UserFinanceCompanies, but it still doesn't seem clear.
Would I have code such as FinanceCompany.AddUser() and User.AddFinanceCompany()? or is there some completely different approach for relationships such as this?
You have already determined that both User and FinanceCompany are aggregates so each has its own life-cycle.
The problem with many domains is that we don't have a complete understanding of the relationships. As another example we can take an Order and a Product. Both are aggregates but would we have Order.AddProduct() or Product.AddOrder()? In this case it seems pretty obvious in that an Order contains a limited subset of Product entries whereas a Product may very well contain many orders and we are not really too interested in that relationship since it is a rather weak relationship. A Product can exist and be valid without any orders attached but an Order is pretty useless without at least one product entry. This means that the Order has an invariant imposed in terms of its OrderItem entries. In addition to this we have enough knowledge about this hackneyed example that we know we are going to need an associative entity (in relational theory speak) since we need additional information regarding the relationship and entering the fray would be our OrderItem table. Curiously I have not seen it called OrderProduct.
The guidance I would suggest is to pick the most appropriate side.
However, if no side is a true winner and both aggregates can exist without a relationship to the other in terms of an invariant perhaps the relationship itself is an aggregate as you have certainly alluded to. Perhaps it isn't only a UserFinanceCompany aggregate but perhaps there is a concept that is missing from the ubiquitous language that the domain experts refer to. Perhaps something like Auditor or some such that represents that relationship. This is akin to the OrderItem or OrderLine concept as opposed to OrderProduct.

Aggreate Root, Aggregates, Entities, Value Objects

I'm struggling with some implementation details when looking at the terms mentioned in the title above.
Can someone tell me whether my interpretation is right?
For reference I look at a CRM Domain
As a AggregateRoot I could see a Customer.
It may have Entities like Address which contains street, postal code and so on.
Now there is something like Contact and Activity this should be at least aggregates. Right? Now if the Contacts and Activities would have complex business logic. For example, "Every time a contact of the type order is created, the order workflow should be started"
Would then Contact need to be an Aggregate root? What may be implementation implications that could result from this?
Further more when looking and Event Sourcing, Would each Aggregate have its own Stream? In this scenario A Customer could have thousands of activities.
It would be great if someone could guide em in which part my understanding is right and which I differ form the common interpretation.
What do you mean by “at least aggregates”?
An aggregate is a set of one or more connected entities. The aggregate can only be accessed from its root entity, also called the aggregate root. The aggregate defines the transactional boundaries for the entities which must be preserved at all time. Jimmy Bogard has a good explanation of aggregates here.
When using event sourcing each aggregate should have its own stream. The stream is used to construct the aggregates and there is no reason to let several aggregates use the same stream.
You should try to keep your aggregates small. If you expect your customer object to have thousands of activities then you should look at if it is possible to design the activities as a separate aggregate, just as long as its boundaries ensures that you do not leave the system in an invalid state.

How do you handle associations between aggregates in DDD?

I'm still wrapping my head around DDD, and one of the stumbling blocks I've encountered is in how to handle associations between separate aggregates. Say I've got one aggregate encapsulating Customers and another encapsulating Shipments.
For business reasons Shipments are their own aggregates, and yet they need to be explicitly tied to Customers. Should my Customer domain entity have a list of Shipments? If so, how do I populate this list at the repository level - given I'll have a CustomerRepository and a ShipmentRepository (one repo per aggregate)?
I'm saying 'association' rather than 'relationship' because I want to stress that this is a domain decision, not an infrastructure one - I'm designing the system from the model first.
Edit: I know I don't need to model tables directly to objects - that's the reason I'm designing the model first. At this point I don't care about the database at all - just the associations between these two aggregates.
There's no reason your ShipmentRepository can't aggregate customer data into your shipment models. Repositories do not have to have a 1-to-1 mapping with tables.
I have several repositories which combine multiple tables into a single domain model.
I think there's two levels of answering this question. At one level, the question is how do I populate the relationship between customer and shipment. I really like the "fill" semantics where your shipment repository can have a fillOrders( List customers, ....).
The other level is "how do I handle the denormalized domain models that are a part of DDD". And "Customer" is probably the best example of them all, because it simply shows up in such a lot of different contexts; almost all your processes have customer in them and the context of the customer is usually extremely varied. At max half the time you are interested in the "orders". If my understanding of the domain was perfect when starting, I'd never make a customer domain concept. But it's not, so I always end up making the Customer object. I still remember the project where I after 3 years felt that I was able to make the proper "Customer" domain model. I would be looking for the alternate and more detailed concepts that also represent the customer; PotentialCustomer, OrderingCustomer, CustomerWithOrders and probably a few others; sorry the names aren't better. I'll need some more time for that ;)
Shipment has relation many-to-one relationship with Customer.
If your are looking for the shipments of a client, add a query to your shipment repository that takes a client parameter.
In general, I don't create one-to-mane associations between entities when the many side is not limited.

Resources