Skip to content

Instantly share code, notes, and snippets.

@xpepper
Last active January 26, 2025 15:14
Show Gist options
  • Save xpepper/cd1105740bbee35d43c7cd560abdaedf to your computer and use it in GitHub Desktop.
Save xpepper/cd1105740bbee35d43c7cd560abdaedf to your computer and use it in GitHub Desktop.
Given that entities need to have a stable identity over time, they require a unique identifier or key. Who is responsible for creating these identifiers? Where do these identifiers come from?

So, given that entities need to have a stable identity over time, they require a unique identifier or key. Who is responsible for creating these identifiers? Where do these identifiers come from?

The responsibility for creating unique identifiers (keys) for entities in a domain-driven design (DDD) system depends on the context and requirements of the application. There are several common approaches to generating these identifiers, each suited to specific use cases. Let’s explore these approaches and who is responsible for generating the identifiers in each case.

The Domain

In some domains, the identifier is inherent to the entity itself and comes from the real-world domain.

Examples:

  • Serial numbers for banknotes: In the state mint context, the identifier (serial number) is usually assigned during the manufacturing process. The mint’s production system generates the serial number and ensures uniqueness.
  • National Identification Numbers (e.g., Social Security Numbers): These identifiers are issued by a governing body.

Responsibility: the domain process itself is responsible for assigning the identifier. In software, this may translate to:

  • A domain service or factory generating the identifier as part of creating the entity.
  • Using a predefined identifier already available from the real-world process.

The Application Layer

In many systems, identifiers are created at the application level when new entities are instantiated. The application ensures uniqueness and can coordinate this process with other parts of the system.

Examples:

  • Database-Generated IDs: When a new entity is created, the application relies on the database to generate a unique ID (e.g., auto-incremented primary keys or UUIDs).
  • Distributed Systems: The application may use globally unique identifiers (UUIDs) to ensure uniqueness across systems.

Responsibility: The application layer (often through a service or repository) is responsible for generating or requesting the identifier.

Infrastructure or External Systems

Sometimes identifiers are generated by external systems that the application integrates with. This often happens when the system interacts with third-party services or systems that manage identifiers.

Examples:

  • Third-Party Systems: A payment processor might assign a transaction ID.
  • Cloud Services: An external API or cloud service might return a unique identifier for created resources.

Responsibility: The external system generates the identifier, and the application stores and uses it as needed.

Domain Factories or Aggregate Roots

In DDD, the factory pattern or an aggregate root is often responsible for creating new entities and assigning their identifiers. This approach ensures that all entities created by the factory or aggregate are initialized with a valid, unique identifier.

Example:

A factory in F# might look like this:

type BanknoteFactory() =
    member this.CreateBanknote(denomination: decimal, serialNumber: string) =
        let id = SerialNumber.create serialNumber
        { BanknoteId = id; Denomination = denomination }

Responsibility: The factory or aggregate root centralizes responsibility for assigning identifiers, ensuring uniqueness and encapsulating logic for generating valid identifiers.

How Are Identifiers Generated?

  1. Database-Generated IDs (e.g., Auto-Increment, Sequences):
  • Best for simple systems where identifiers are only needed after persistence.
  1. UUIDs (Globally Unique Identifiers):
  • Best for distributed systems or systems requiring globally unique IDs without relying on a central authority.
  1. Domain-Specific Algorithms:
  • Best when the domain has specific requirements for identifiers (e.g., serial numbers for banknotes, VINs for cars).
  1. Combining Context Information:
  • Some identifiers are composite, combining context-specific information (e.g., a customer number + a timestamp).

When Should Identifiers Be Assigned?

The timing of identifier creation depends on the domain and requirements:

  • At Creation: Some entities require an identifier immediately upon instantiation. For example, a banknote needs a serial number as soon as it’s created.
  • At Persistence: If the identifier is generated by the database or another system, it will only be assigned when the entity is saved.

Summary

The responsibility for creating unique identifiers lies with:

  1. The domain, if the identifier is a natural part of the entity (e.g., serial numbers for banknotes).
  2. The application layer, if the identifier is an internal system concern (e.g., UUIDs or database-generated IDs).
  3. External systems, if the identifier is provided by an integrated service (e.g., transaction IDs from a payment processor).
  4. A domain factory or aggregate root, if entity creation and ID assignment need to be centralized for consistency.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment