DDD - Modelling the Domain - Entities

Entities are objects of the domain model with a distinct identity and a life cycle (Evans, 2003). Moreover, the key defining characteristic is not the values of their properties which could change over time (Evans, 2003). The uniqueness of an Entity's identity is defined by the model and does not change during its lifetime (Evans, 2003).

For example, consider modelling the concept of a Person with a first/last name, a birth date and genre. Obviously, using the combination of the first and last name as the unique identity is problematic. If the Person is a woman which got married, the last name could change leading to data corruption.

Entities are not mere data structures and emphasis is given to their methods providing rich behaviour (Evans, 2003). As an example, consider modelling a SecureDoor as an entity with a unique identity that can be opened, closed, locked an unlocked. In order to unlock the door we need a Key (i.e. a Value Object):

key, lock = lock_factory.create(pin=123456)
door = SecureDoor(identity=321, secured_by=lock)
door.lock(key)

As shown above, a Key and a Lock are created by a LockFactory, then a SecureDoor is created protected by a specific Lock instance and finally we lock the door using the lock's key. The Key does not know how to unlock the door or the locking mechanism hidden inside the door. If the key does not fit within the locking mechanism the door will refuse to change its state from locked to unlocked.

The identity of entities should be unique and Vernon (2013) suggests four different ways to introduce it:

  • The user of the application: when a user creates an entity he/she is asked for a unique identifier. For example, a user creates a Project titled “my first project for customer X” and chooses the string “PRJ1-X” as the unique identifier.

  • The application itself: a Universally Unique Identifier (UUID) is generated and associated with the instance of a new Entity.
  • The persistence mechanism: this is the most common case where an identity is created only after the entity is persisted. The database maintains a sequence for each table and each time a new row is added, the sequence is increased and a new integer ID is generated.
  • Third party system: the application relies to a third-party remote system to provide and guarantee a unique identity. For example, an online shopping system has to register a new user but needs to send a remote request to the customer relationship management (CRM) system to retrieve the identity.

References

  • Evans, E. (2003) Domain-Driven Design: Tacking Complexity In the Heart of Software. Boston: Addison-Wesley.
  • Vernon, V. (2013) Implementing Domain-Driven Design. Boston: Addison-Wesley.

This post is an excerpt of my MSc Thesis titled "Applying Domain-Driven Design in Python - designing a self-hosted Read-it-Later service" (January 2014).

This article was updated on

Related post

DDD - Modelling the Domain - Modules

Software systems could become very complex with a large domain model which makes it overwhelming to see the whole picture. The concept of a Module is a design element in many programming languages (in Java they are called Packages and in C# Namespaces) to divide code for managing complexity and assisting in code reuse. Typically, programming language textbooks promote modules mainly as a code organization tool.

DDD - Modelling the Domain - Services

When designing a Domain Model the prominent modelling paradigm is objects and as a result we are mapping concepts i.e. nouns to DDD building blocks such as Entities and Value Objects. The behaviour associated to those concepts is mapped to methods using verbs. However, there are domain specific functions that we would like to define in the model but cannot be attached into an existing Entity or Value Object (Evans, 2003). Instead of forcing foreign operations into domain objects, Evans (2003) introduced the concept of Domain Services.