'Reference between aggregates with write model constraint
I know there are lots of questions talking about aggregates references here. But after reading some of them I still do not get an answer.
First I will describe my business logic.
I have two Entities:
Resource which describe the resource of a computation unit, including cpu, gpu, memory, disk. Resource can be used by users.
class Resource {
CPU cpu;
GPU gpu;
Memory memory;
Disk disk;
int totalCount; // The number of resource if limited
boolean isAvailable; // Resource can be unavailable
List<UserId> whiteLists; // Resource can give a white list where only limited users can use
}
Plan is a merchandise. It has a price and bind with a Resource and time.
class Plan {
String resourceId;
Money price;
int hours;
}
Right now I just save resourceId in Plan to follow the DDD principle: Aggregates should reference other aggregates by Id. But here is some business logic which make it quite difficult:
Planshould also follow theResource.whiteList, it means that when aResourceis only accessful by some users then thePlanusing thisResourceshould also follow thiswhiteList.Planshould not be availabe if itsResourceis not available.Planwith the sameResource(but have different time) should follow some variants. For example,Planwith more time should always be expensive than thePlanwith less time.
This three logic all means that Plan should always access Plan.Resource. And I think this is not just the CQRS read model's logic which only show the Plan and Resource together. It is necessary even in some Plan creation workflow.
So right now I think use Resource in Plan is quite necessary. But how to solve the conflict with the DDD principle, I just do not know how to explain this situation. Am I wrong to make them two separate aggregates? But the Plan and Resource do need to be editable separately.
Update
There are some details I did not describe well.
- The
Planwill not be more than 100 during a very long lifecycle. - The
PlanandResourcecan only be edited by the administrator. There is no concurrency issue there. ThePlanbe bought buy users but users never edit it. - The
Planshould always follow thewhiteListinResource, it is not acceptable that one user buy aPlanwhich he / she even have no rights to use theResource.
Solution 1:[1]
The principle is used to hint the boundaries of the aggregate.
You can achieve the same effect by querying for the Resource before creating the Plan.
Reading at your validation rules that doesn't solve them, how do you know if the Resource is free in a given time?
You need to check all the Plans associated to that Resource to understand it.
Now there are 2 ways to solve for those invariants:
1.
Have a single aggregate Resource that has in in it a List<Plan>, and it takes care of creating them and can guarantee 100% consistencies of invariants.
2.
Have them separated, you create a Plan through some service that does some queries to check the status of the Resource and other Plans to ensure the invariants, and then create the new aggregate.
Solution 1 is hard to scale, the more Plan associated to a single Resource, more optimization you will need to have good performance.
Solution 2 allows for inconsistencies, it can happen that concurrent operations allow for two Plan to be created at the same time, or creating a Plan for a user that is concurrently removed from the whitelist.
Solution 1, what "good performance" means? How many plans will be there?
Solution 2 how much is the probability for concurrent writes to happen? Is that error rate acceptable? Can these issues being managed after it happens?
No general right answer, it depends on your specific use case.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | rascio |
