4

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?

  • 1
    You (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 Feb 8 '18 at 9:28
  • @Caleth, yes it is. I am trying to understand what the "process" would be. – w0051977 Feb 8 '18 at 9:32
  • 1
    From 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 Feb 8 '18 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). – king-side-slide Nov 5 '19 at 19:02
4

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 Feb 8 '18 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 Feb 8 '18 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 Feb 8 '18 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 Feb 8 '18 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 Feb 9 '18 at 9:55
0

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

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.