I have been struggling to design aggregate roots for meeting domain.
Domain:
Meeting has one or more agenda items.
Each AgendaItem has a note section also each AgendaItem has one or more tasks.
Design
Now based on guidelines, I am trying to keep smaller aggregate roots within meeting bounded context. so I have MeetingAggregateRoot and AgendaItemAgreegateRoot.
Business rule:
Each meeting will have multiple agenda items (each agenda item may have one or more sub-agenda items). But they should be ordered by sequence and they should not have duplicate sequence.
If I keep single AR as MeetingAR with AgendaItem as Entity then MeetingAR may take responsibility for keeping AgendaItem Sequence in order. But then I have multiple tasks as well per AgendaItem so I decide to keep two separate AR as MeetingAR and AgendaItem AR (AgendaItemAR will have task entity).
Now question is...
How should I design ARs so that MeetingAR is only "responsible" for meeting related actions. AgendaItemAR is only responsible for its own actions and still Sequence is maintained for all agendaitems within meeting.
Any help is appriciated on this.
I think that it isn't a decision. If agenda items lifecycle depends on meeting, agenda would be a child entity of meeting. It would be a composition, an agenda item couldn't exist on his own.
Related
I'm developing a budgeting app using Domain Driven Design. I'm new to DDD and therefore need a validation of my design.
Here are the concepts I came up with:
Transaction - which is either income or expense, on annual or monthly or one-off etc. basis.
Budget - which is the calculated income, expenses and balance projection, divided into occurrences (say e.g. 12 months over the next year, based on the Transactions).
I made the Transaction the Entity and Aggregate Root. In my mind it has identity, it's a concrete planned expense or income that I know I'll receive, for a concrete thing, and I also need to persist it, so I can calculate the budget based on all my transactions.
Now, I have an issue with the Budget. It depends on my concrete list of Transactions. If one of the Transactions gets deleted, the budget will need to be re-calculated (seems like a good candidate for a domain event?). It's a function of my identifiable transactions at any given time.
Nothing outside the Aggregate boundary can hold a reference to anything inside, except to the root Entity. Which makes me think the budget is the Aggregate Root as it cannot be a ValueObject or Entity within the Transaction.
What's confusing is that I don't necessarily need to persist the budget (unless I want to cache it). I could calculate it from scratch on request, and send it over to the client app. 2 different budgets could have the same number of occurrences, incomes, expenses and balances (but not Transactions). Perhaps an argument for making it a ValueObject?
So, my questions is - what is the Budget?
Domain context vs Aggregate
First element you get wrong is a point of details about DDD semantics. If there is only one object in your "aggregate", then it is not an aggregate. An aggregate is a structure made of multiple (2+) objects, with at least one being an entity and called the aggregate root. If a TransactionRpository returns a Transaction object that has no value object or entity, then Transaction is an entity but not an aggregate nor an aggregate root. If a BudgetRepository returns a Budget entity that includes a Transaction object, then Budget and Transaction form an aggregate, Budget being the aggregate root. If Budget and Transaction are returned from different repositories, then they form different contexts.
Context being the generic concept that can either be an aggregate or an entity.
Contexts are linked to use cases
Second element you get wrong is that you are trying to design your domain model outside of your use cases context. Your application clearly manipulates both concepts of Budget and Transactions, but does your application handles uses cases for both (budget management and transaction management) ? If yes, are these uses case different in a way that implies different domain constraints ?
If your application only handles Budget management, or both but they share their business constraints, then you only need a single context, that manipulates both concepts in a single aggregate. In that situation, Budget is probably your root aggregate, and it's up to your mode and use cases to tell whether the Transaction is a value object or you need to access them by Id.
If your application handles uses cases for both, with different business constraints, then you should split your domain in two contexts, with two different models, one for the Budget management use cases, the other for the Transaction management use cases.
Polysemic domain model
The third element you get wrong, is that you are trying to build a single, unified, normalized domain model. This is wrong because it introduces very complex structures, and a lot of business rules that are irrelevant to your business cases. Why would you need to manipulate the Budget domain model when the use case does not need knowledge of the Budget concept or linked business rules ?
If your application has use cases for both concepts, you need two models. The Budget management model should not use the Transaction management model. However, that does not implies that the Budget model is not allowed to manipulate the Transaction concept and vice versa. It only means you must write another model for that. You could have a Budget context that manipulates Budget and BudgetTransaction models, and Transaction context that manipulates Transaction and TransactionBudget models. These models can map to the same RDBMS tables with different columns, relevant to their use cases, implementing relevant business rules.
This is called writing a polysemic domain model.
Conclusion
So, my questions is - what is the Budget?
It is not possible to answer definitely your last question, as the answer depends on the use cases your application handles. However, you mention the following constraint:
If one of the Transactions gets deleted, the budget will need to be re-calculated
This seems a very good argument in favor of making your application as a single context application, based on an aggregate with Budget being the aggregate root and Transaction being an entity in the aggregate.
If you don't need to, try to refrain from splitting these two concepts in different contexts, unless you have very good reasons to do so: they manipulate excluding columns, they manipulate excluding business rules, you are interested in deploying these two in different bounded contexts, different services, as they would scale differently, etc ...
Having business constraints that span accross multiple contexts implies a complex implementation based on domain events, 2-phase commits, saga pattern, etc ... It's a lot of work, you should balance that work with the benefits you expect in return.
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.
I know in DDD that deleting the Aggregate Root must remove everything within the Aggregate boundary all at once.
But in the Agile example that vaughn vernon gave it here https://vaughnvernon.co/?p=838 the BackLogItem and Product Aggregates are exist in separate Aggregates and the BackLogItem Aggregate Root is referencing Product Aggregate Root by Id.So, If I want to delete the Product Aggregate Root wouldn't mean that I should delete its BackLogItems?
So, my question how to delete multiple Aggregates in DDD and if so would be that possible using Domain Services , Domain Event or whatever?
P.S
Depending on vaughn vernon that we should not modify more than one
aggregate in the same transaction(in some cases we are forced to use
eventual consistency).
The usual mechanism for behavior distributed across multiple aggregates is to use a process manager.
I recommend starting from Rinat's writeup, because it really does get to the core of the matter; a process manager is just a stand in for a human being that reacts to events by sending commands to other aggregates.
Oh look, the Product was removed
I should load a list of the BackLogItems that reference that Product
And remove each of them in turn
If your modeling of the back log items as belonging to a distinct aggregate from the product is correct, then it follows that the changes to the back log items can be separated in time from the changes to the product.
Also, see Udi Dahan: Don't Delete -- Just Don't.
Use Saga Pattern. It executes a scenario in the transaction and imitates clients work. Saga sends multiple commands just as client does.
I would argue that your problem is not only how to delete multiple aggregates, but also which aggregates you should delete. In your question, you mention that when you delete the Product Aggregate you should delete its Backlog Items, but is that all? What about the Kanban Board and its custom columns and workflow, and N other features associated with that Product Aggregate?
The point of having the BacklogItems knowing about the Product, but not the other way around is to avoid having a God object, which knows about everything because dozens of features can be attached to the Product Aggregate over time.
When deleting the Product Aggregate, there's not a single place that knows everything that needs to be deleted, but everything that needs to be deleted will know. Therefore, leave the responsibility to delete (or something else) to every other aggregate: From the ProductAggregate, publish a ProductDeletedEvent and subscribe to it from all the other aggregates that care about it.
In DDD, a repository loads an entire aggregate - we either load all of it or none of it. This also means that should avoid lazy loading.
My concern is performance-wise. What if this results in loading into memory thousands of objects? For example, an aggregate for Customer comes back with ten thousand Orders.
In this sort of cases, could it mean that I need to redesign and re-think my aggregates? Does DDD offer suggestions regarding this issue?
Take a look at this Effective Aggregate Design series of three articles from Vernon. I found them quite useful to understand when and how you can design smaller aggregates rather than a large-cluster aggregate.
EDIT
I would like to give a couple of examples to improve my previous answer, feel free to share your thoughts about them.
First, a quick definition about an Aggregate (took from Patterns, Principles and Practices of Domain Driven Design book by Scott Millet)
Entities and Value Objects collaborate to form complex relationships that meet invariants within the domain model. When dealing with large interconnected associations of objects, it is often difficult to ensure consistency and concurrency when performing actions against domain objects. Domain-Driven Design has the Aggregate pattern to ensure consistency and to define transactional concurrency boundaries for object graphs. Large models are split by invariants and grouped into aggregates of entities and value objects that are treated as conceptual whole.
Let's go with an example to see the definition in practice.
Simple Example
The first example shows how defining an Aggregate Root helps to ensure consistency when performing actions against domain objects.
Given the next business rule:
Winning auction bids must always be placed before the auction ends. If a winning bid is placed after an auction ends, the domain is in an invalid state because an invariant has been broken and the model has failed to correctly apply domain rules.
Here there is an aggregate consisting of Auction and Bids where the Auction is the Aggregate Root.
If we say that Bid is also a separated Aggregate Root you would have have a BidsRepository, and you could easily do:
var newBid = new Bid(money);
BidsRepository->save(auctionId, newBid);
And you were saving a Bid without passing the defined business rule. However, having the Auction as the only Aggregate Root you are enforcing your design because you need to do something like:
var newBid = new Bid(money);
auction.placeBid(newBid);
auctionRepository.save(auction);
Therefore, you can check your invariant within the method placeBid and nobody can skip it if they want to place a new Bid.
Here it is pretty clear that the state of a Bid depends on the state of an Auction.
Complex Example
Back to your example of Orders being associated to a Customer, looks like there are not invariants that make us define a huge aggregate consisting of a Customer and all her Orders, we can just keep the relation between both entities thru an identifier reference. By doing this, we avoid loading all the Orders when fetching a Customer as well as we mitigate concurrency problems.
But, say that now business defines the next invariant:
We want to provide Customers with a pocket so they can charge it with money to buy products. Therefore, if a Customer now wants to buy a product, it needs to have enough money to do it.
Said so, pocket is a VO inside the Customer Aggregate Root. It seems now that having two separated Aggregate Roots, one for Customer and another one for Order is not the best to satisfy the new invariant because we could save a new order without checking the rule. Looks like we are forced to consider Customer as the root. That is going to affect our performance, scalaibility and concurrency issues, etc.
Solution? Eventual Consistency. What if we allow the customer to buy the product? that is, having an Aggregate Root for Orders so we create the order and save it:
var newOrder = new Order(customerId, ...);
orderRepository.save(newOrder);
we publish an event when the order is created and then we check asynchronously if the customer has enough funds:
class OrderWasCreatedListener:
var customer = customerRepository.findOfId(event.customerId);
var order = orderRepository.findOfId(event.orderId);
customer.placeOrder(order); //Check business rules
customerRepository.save(customer);
If everything was good, we have satisfied our invariants while keeping our design as we wanted at the beginning modifying just one Aggregate Root per request. Otherwise, we will send an email to the customer telling her about the insufficient funds issue. We can take advance of it by adding to the email alternatives options she can purchase with her current budget as well as encourage her to charge the pocket.
Take into account that the UI can help us to avoid having customers paying without enough money, but we cannot blindly trust on the UI.
Hope you find both examples useful, and let me know if you find better solutions for the exposed scenarios :-)
In this sort of cases, could it mean that I need to redesign and re-think my aggregates?
Almost certainly.
The driver for aggregate design isn't structure, but behavior. We don't care that "a user has thousands of orders". What we care about are what pieces of state need to be checked when you try to process a change - what data do you need to load to know if a change is valid.
Typically, you'll come to realize that changing an order doesn't (or shouldn't) depend on the state of other orders in the system, which is a good indication that two different orders should not be part of the same aggregate.
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.