I was reading this question recently: ID properties on Domain objects in DDD
The question talks about having an surrogate key in the infrastructure layer, which is a database ID. I use a Guid for this:
Guid id = Guid.NewId();
The answers then talk about having a natural key in the domain layer that identifies the entities. A great example of this in my mind is a bank account i.e. the Guid identifies the bank account in the database (and Data Model) and the account number and sort code identify the bank account in the domain layer i.e. there is no database id in the domain layer.
Say I have a product entity and I want to generate a product code in the domain layer. How would I do this? The question I have linked to talks about using algorithms. What algorithms are there?
-
1You (singular, the programmer) can't magic a "natural" key where there is none. You (plural, the business) may be able to define some process that assigns unique identifiers of some sort to entities in the domain, and then use that as a "natural" key of the software representation of those domain entities. Is that sort of process what you are asking about?Caleth– Caleth02/08/2018 09:28:46Commented Feb 8, 2018 at 9:28
-
@Caleth, yes it is. I am trying to understand what the "process" would be.w0051977– w005197702/08/2018 09:32:57Commented Feb 8, 2018 at 9:32
-
1From the linked question: "following a pattern defined by regulation, or human-friendly notions, following your company best practice (it is common to include the year and the month in invoice numbers, or an alphanumeric identifier of the department in charge of the process for instance)." If there is a single authority that can handle the volume of issuing all the identifiers it can just increment a counter.Caleth– Caleth02/08/2018 09:53:13Commented Feb 8, 2018 at 9:53
-
For what purpose should a domain layer require any identifiers? I don't mean that in the sense that an entity shouldn't contain an identifier, rather, in what way is it relevant to the domain? Your question seems to imply that the value of an identifier is material to the domain. Bare in mind the above is food for thought only loosely related to your question about how to generate identifiers within a domain (which is a totally valid question).user3347715– user334771511/05/2019 19:02:11Commented Nov 5, 2019 at 19:02
2 Answers 2
Lets stick to your example:
Say I have a product entity and I want to generate a product code in the domain layer. How would I do this?
First, you ask your domain experts about their requirements for a product code. They might come up with things like
must be printable on paper, using only numbers, or using alpha-numerics, but without using numbers and letters together which can be easily mixed up (like 0 and O, 1 and l)
must be bar-code "friendly"
must be unique for every product expected to be produced within the next 10 years by our company
must encode the product category in some part of the number
must encode the year of production
must not collide with all the already assigned 123456 product numbers from the past which were generated in an older system following a different logic
must prevent duplicates even when your system runs offline in a distributed fashion
So it will become your task to analyse these requirements, find a solution in form of an algorithm for this and implement the required code in the domain layer.
Or, if you are lucky, your domain experts tell you
- we don't need something like a product code for our business, we never had one in the past, never missed it
In this case, don't invent a "natural key". Instead use the surrogate key exclusively whereever you need to implement modeled relationships.
-
Thanks for the clear and concise answer. Before I accept - can I confirm that by surrogate key (referenced in the last paragraph); you mean the GUID, which is the primary key in the database table? +1 for reference to domain experts.w0051977– w005197702/08/2018 12:28:33Commented Feb 8, 2018 at 12:28
-
@w0051977: sure, since that is what you wrote in your question: the surrogate key, which is also the PK, which in your case is apparently a GUID.Doc Brown– Doc Brown02/08/2018 14:41:55Commented Feb 8, 2018 at 14:41
-
One more thing. Say I have a DataModel with: ID, Address, DateOfBirth, Name etc. Say my Domain Model only needs the ID and DateOfBirth. Is it normal to pass these parameters only to the domain model? All the examples I look at online (GitHub) seem to show the Domain Model just repliating the data model.w0051977– w005197702/08/2018 15:28:49Commented Feb 8, 2018 at 15:28
-
@w0051977: this is a question which deserves a far bigger answer than one I can give here in a comment. It depends heavily on the size of the system and the details of the methodology how the mapping between data model and domain model is achieved. I think you could do some research if someone has asked a similar question before here on SE.SE, and if you cannot find one, ask a new question.Doc Brown– Doc Brown02/08/2018 19:14:59Commented Feb 8, 2018 at 19:14
-
Thanks. I have spent about an hour or so Googling this, however I am still not clear. Therefore I have asked another question here if you are interested in answering?: softwareengineering.stackexchange.com/questions/365643/…w0051977– w005197702/09/2018 09:55:19Commented Feb 9, 2018 at 9:55
You might want to read up on International Article Number (also known as European Article Number or EAN). EAN-13 is 13 digits. You might also want to read up on Global Trade Item Number (GTIN) and part number.
An invoice order number commonly includes the data and/or the customer number. A ticket number may include the date. A product code may include series/version/revision and attributes such as size and color.
So you can form your own naming convention. You can look up naming conventions that other companies use, such as how Intel and AMD name their processors (generation, low/mid/high-end), or how Nvidia and AMD name their graphics cards, or how phone companies name their phones. How companies name their shoes (men/women, indoor/outdoor, walking/running, size, color).
You can create a function which generates such as a name from its input parameters.
/// <summary>
/// Generate a product code from the specified parameters.
/// </summary>
/// <param name="series">The series that the product belongs to.</param>
/// <param name="size">The size of the product.</param>
/// <param name="color">The primary color of the product.</param>
/// <returns>A product code.</returns>
/// <remarks>Adheres to our naming convention.</remarks>
private string GenerateProductCode(string series, Size size, Color color)
{
return $"{series}{size}{color}";
}
Then you call it:
var productCode = GenerateProductCode("300", Size.Small, Color.Green); // -> 300SG