'In a DDD architecture, where does a unique ID generation belong to?
Let's say I have a "Project" entity in my domain, that has a to have a unique ID generated (on top of the normal numeric ID) that is 2 letters + 4 digits for every Project. This id has to be unique among all the Projects.
I am having a difficult time placing this functionality, it feels like It should almost only just be placed in the repository when the Project is being saved the first time.
I am sure it doesn't belong to Application services, I am not sure if it is any of the business layers concern to be a domain service, and it feels weird to put it as infrastructure service, but it does need to check if any other Projects exist with a randomly generated [LL]-[DDDD] like code or not.
Even if I place this code around the repository.save it still has to call something from somewhere, so the question is, where should I put a service that gives me a free random Id like that?
Solution 1:[1]
Ids which are part of the domain should be generated by the domain.
If the domain do not define any ids you should not expose them in the domain either (strictly speaking, but it's probably easier to include them either way).
Solution 2:[2]
Your question mentions a 'normal ID'. I'm assuming that this is your DB's primary key and that the ID you want to generate here is for humans (although why humans would use a 2-letter+4-digit identifier is beyond me, but I've seen worse). In this case, the generation of the key is a business function and ensuring it is unique is a business rule. Both of these things are properly the responsibility of the domain objects. Given your object name, Project, and the language you use in your question, I'd suggest that maybe the Projects object should provide this service. The reason for this is that only the Projects object would have a view over all project objects you've created to check for uniqueness.
Of course, you could have an algorithm to generate this field that ensures uniqueness without having to check all projects (a good idea, btw). In which case you'd probably allow a project to generate its own ID at an appropriate time in its lifecycle (probably when it is created).
Solution 3:[3]
The "free random id" or ID generation is part of the infrastructure rather than the business domain so I would add that logic to a persistence layer and call that from within my repositories. e.g ProjectRepository. Assume that the Project entity would have an 'id' field in any case. You can enforce validation in the Project entity so that the id format is 2 letters and 4 digits but only do that if Project ids are different to other entity ids in your application
Solution 4:[4]
The first question you need to ask yourself is - why is this constraint on Project ID necessary? Does the user need to know about Project IDs?
If it's informative to the user or if you are implying a form of catalogue of projects, this is a business rule that belongs to the domain. It might require updating your domain model, and therefore refactoring your code in accordance with the new model. Actual id generation will be done by the infrastructure layer, as a new Project is added to the system, but it will use a STRATEGY that expresses the business rule and is defined in the domain layer.
If it's merely a technological requirement, but has no semantic meaning in the domain, either remove the constraint, or place it in the infrastructure layer.
In any case, the infrastructure layer can provide an infrastructure service for id generation of new project entities, which the class responsible for Project entity creation may use (for example, a Project Factory). Project Factories belong to the domain layer, even though they may use an infrastructure service.
Solution 5:[5]
Unique identifier generation would normally be an application concern -- these identifiers are analogous to random numbers, or time. They are an input to the deterministic parts of the system.
If you don't consider time an input value, think about it until you do - it is an important concept -- John Carmack, 1998
Ensuring that an identifier (however it was generated) satisfies some uniqueness constraint would be a domain concern, and falls into the general category of set validation.
Note Greg Young's observation:
What is the business impact of having a failure?
If the cost of a failure is small, if failures are easily detected and remedied, then it may be most practical to lean into a "best effort" design. UUID's aren't unique (finite number of bits, we're going to use them all up eventually), but at the scales we are working at the probability of collision is really small. So often, we can just live with it.
But when the impact of a failure is high....
Ensuring that some policy applies to the entire set requires being able to lock the entire set against concurrent modification.
In the easy case - each unique identifier has its own set. One way of framing how repositories work is that they give you the set of all aggregates that match the provided key, and your domain logic is responsibly for ensuring that set has at most one element in it.
In harder cases, the set itself becomes an aggregate, with its own lock, and the domain logic ensures that the each change maintains the invariant of the set. Often, this requires doing a deep analysis of the model to understand which information is actually under the authority of the set, rather than under the authority of other aggregates.
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 | jgauffin |
| Solution 2 | |
| Solution 3 | kevin mcdonnell |
| Solution 4 | |
| Solution 5 |
