Skip to main content

Welcome to a Grasp lesson

Create a free account to keep studying and create your own study path.

Lesson 5

Entities vs. Value Objects

Recommended resources

Hello! Welcome to your first lesson in the "Tactical Patterns" module of our Domain-Driven Design course.

Introduction

In the previous module, we explored the "big picture" of DDD, focusing on strategic concepts like Bounded Contexts and the Ubiquitous Language. These ideas help us manage complexity at a high level by breaking down large systems.

Now, we're diving into Tactical DDD. This is where we get closer to the code and look at the specific building blocks we use to construct a rich, expressive domain model.

Today's learning outcome is to distinguish between Entities and Value Objects. These are two of the most fundamental building blocks in any domain model. By the end of this lesson, you will understand:

  • What defines an Entity and what defines a Value Object.
  • The critical role of identity and equality.
  • The key characteristics of each, such as mutability and lifespan.
  • Why making this distinction is crucial for building robust and maintainable software.

Let's begin by getting a clear visual and conceptual overview of these building blocks.


1. The Core Distinction: Identity vs. Attributes

At its heart, the difference between an Entity and a Value Object comes down to a single question: "What makes it unique?"

  • For some objects, uniqueness is tied to a continuous history and a specific identity that doesn't change, even if its properties do.
  • For other objects, uniqueness is simply a matter of the values they hold. If the values are the same, the objects are the same.

To see this in action, please watch the following short video. It provides an excellent introduction to these concepts.

DDD Building Blocks

This video from the Drawing Boxes channel provides a concise introduction to the main DDD building blocks. We'll focus on the sections defining Value Objects and Entities.

Please watch from the beginning until 02:23. Pay close attention to the examples of 'Colour' (for a Value Object) and 'Tyre' (for an Entity) and how their equality is determined.

As the video explained:

  • An Entity has a thread of continuity and identity. Think of a Customer in an e-commerce system. We can change their shipping address or phone number, but they remain the same customer. Their identity (e.g., a customer ID) is the key. Two customers with the same name and address are still two different people.
  • A Value Object is defined by its attributes. It describes a characteristic of something. The video's example of Colour is perfect. A specific shade of purple is defined by its RGB values. Any object with those same RGB values represents the exact same color. It has no identity beyond its constituent values.

This fundamental difference in how we determine equality is the most important distinction. To explore this further, let's look at a more formal definition of equality types.

Entity vs Value Object: the ultimate list of differences

This article, 'Entity vs Value Object: the ultimate list of differences' by Vladimir Khorikov, provides a very clear breakdown. We will start with the section on equality.

Read the first section, '1. Entity vs Value Object: types of equality'. Focus on understanding the difference between 'Identifier equality' (for Entities) and 'Structural equality' (for Value Objects).

To summarize the key point from the reading:

  • Entities use Identifier Equality: Two entity objects are considered equal only if their unique identifiers are the same.
  • Value Objects use Structural Equality: Two value objects are considered equal if all their attributes have the same values.

2. Key Characteristics and Why They Matter

Understanding identity is the first step. Now let's explore the practical characteristics that stem from this core difference and why this distinction is so valuable in software design.

The main characteristics to consider are immutability and lifespan.

Entity vs Value Object: the ultimate list of differences

Let's return to the 'Entity vs Value Object' article to explore the concepts of lifespan and immutability.

Read sections '2. Entity vs Value Object: lifespan' and '3. Entity vs Value Object: immutability'. Note the connection between a Value Object's lack of identity and its immutability.

Let's break down what you just read:

  • Immutability: Value Objects must be immutable. Since a Value Object is defined by its values, changing one of its values would conceptually make it a different object. For example, if you change a Money object from "$10" to "$20", you don't mutate the original object; you create a new one. This makes the system safer and more predictable, as Value Objects can be passed around without fear of them being changed unexpectedly. Entities, on the other hand, are almost always mutable, as their purpose is to track state changes over their lifecycle.

  • Lifespan: Entities have a lifecycle. They are created, modified over time, and eventually may be archived or deleted. Their history matters. Value Objects have what the article calls a "zero lifespan." They are created to represent a value and can be discarded and recreated without any loss of information.

Making this distinction helps us create a more expressive, simpler, and safer domain model. The following video explains these benefits well.

Entities vs Value Objects: Which one is BETTER?

This video from Marco Lenzo's channel clearly articulates why we bother making this distinction in the first place.

Watch the segment from 02:13 to 03:39. Focus on the three main benefits discussed: making the model more expressive, simpler, and safer.

As the video highlights, by using Value Objects where appropriate, we reduce complexity. We don't need to manage IDs or track changes, which simplifies development, testing, and reasoning about the system's behavior.


3. Context is King

Is an Address an Entity or a Value Object? The answer, frustratingly and beautifully, is: it depends on the Bounded Context.

  • In an e-commerce context, an address is likely a Value Object. It's just a set of attributes (street, city, zip code) describing where to ship an order. If two customers happen to live at the same address, we can represent that with two identical but separate Address value objects. We don't need to track the history of the address itself.
  • In a logistics or government context, an address might be an Entity. The system may need to track how many people reside at that address, its history of occupants, or its zoning classification. In this case, the address has a persistent identity that matters to the domain.

This is a critical insight in DDD: the nature of an object is determined by the business requirements of its specific context.

Entities vs Value Objects: Which one is BETTER?

Let's watch another short clip from the same video by Marco Lenzo, which explains this contextual nature perfectly.

Watch the clip from 05:14 to 05:44, which uses the 'address' example to illustrate how business requirements determine whether something is an Entity or a Value Object.


4. A Practical Look in Python

Let's see how these concepts translate into Python code. Your background in software engineering will make this straightforward.

Entities vs Value Objects in Domain Driven Design

The article 'Entities vs Value Objects in Domain Driven Design' from Kenyan Programmer offers simple, clear Python examples.

Read the section starting from the line 'In Python we can represent value objects...' to the end of the code blocks. Observe how namedtuple is used for an immutable Value Object and how a class with a custom __eq__ method is used for an Entity.

Let's review the code patterns from the article:

Value Object (Name)
The example uses namedtuple, which is a good choice because its instances are immutable and its default equality check is structural (it compares the values of the fields).

from collections import namedtuple

# A Value Object: immutable and compared by its values
Name = namedtuple('Name', ['first_name', 'last_name'])

name1 = Name('Jack', 'Ma')
name2 = Name('Jack', 'Ma')

print(name1 == name2) # Output: True

Entity (Transaction)
The example uses a class and explicitly defines equality based on a unique identifier (uid). This is the standard pattern for an Entity.

# An Entity: has a unique ID and equality is based on that ID
class Transaction:
    def __init__(self, uid: int, amount: float):
        self.uid = uid
        self.amount = amount # This can change over time

    def __eq__(self, other):
        if not isinstance(other, Transaction):
            return NotImplemented
        return self.uid == other.uid

    def __hash__(self):
        return hash(self.uid)

t1 = Transaction(uid=1, amount=100.0)
t2 = Transaction(uid=2, amount=100.0)
t1_clone = Transaction(uid=1, amount=150.0) # Amount changed, but ID is the same

print(t1 == t2)       # Output: False (different IDs)
print(t1 == t1_clone) # Output: True (same ID, despite different amount)

(Note: I've added __hash__ to the example, as it's good practice to define it when you override __eq__.)

This clear separation in code makes the intent of your domain model explicit. When another developer sees a namedtuple or a frozen dataclass (which we'll cover next lesson), they immediately know it's a Value Object. When they see a class with an ID and a custom equality check, they know it's an Entity.


Conclusion

Let's summarize the key distinctions we've covered today. The article "Entity vs Value Object: the ultimate list of differences" provides a great summary.

Key Takeaways:

  • Entities are defined by a unique, persistent identity. They are typically mutable, have a continuous lifespan, and equality is checked via an ID.
  • Value Objects are defined by their attributes. They must be immutable, have no independent lifespan, and equality is checked via the values of their attributes (structural equality).
  • The choice between an Entity and a Value Object is not technical but is driven by the business requirements within a specific Bounded Context.
  • As a general design principle, prefer Value Objects over Entities whenever possible to reduce complexity and increase system safety.

You now have a solid conceptual foundation for these two essential DDD building blocks.

Preview of the Next Lesson:

In our next lesson, we will put this theory directly into practice. We will focus on implementing immutable Value Objects in Python, exploring modern techniques like dataclasses(frozen=True) to create robust and expressive domain models.