Entities vs. Value Objects

Identity, equality, and immutability — the difference matters.

0/3 done

Theory

  • An Entity has identity that persists across changes. Two Customers with the same name but different IDs are not equal.
  • A Value Object has no identity. Two Money(10, EUR) instances are interchangeable and should be immutable.

Confusing the two is the most common modelling mistake in junior DDD code.

Analogy

Your passport is an entity — it identifies you, and replacing it issues a new one. A €10 note is a value object — any €10 note will do.

Worked example — frozen value object & identity-based entity

Worked example — value object and entity, side by side in Python.

Python's dataclasses module gives us almost everything we need. The single keyword that flips a class into a true value object is frozen=True:

from dataclasses import dataclass, field
from decimal import Decimal
from uuid import UUID, uuid4

# Value object — immutable, compared by value.
@dataclass(frozen=True)
class Money:
    amount: Decimal
    currency: str

# Entity — identity persists across changes, compared by id.
@dataclass
class Customer:
    id: UUID = field(default_factory=uuid4)
    name: str = ""

    def __eq__(self, other: object) -> bool:
        return isinstance(other, Customer) and self.id == other.id

    def __hash__(self) -> int:
        return hash(self.id)

Why each line is there:

  • @dataclass(frozen=True) makes Money immutable — Money(10, 'EUR').amount = 20 raises.
  • frozen=True also makes Money hashable and gives free value-equality: Money(10, 'EUR') == Money(10, 'EUR') is True.
  • Customer is left mutable but adds an id field with a UUID default.
  • The explicit __eq__/__hash__ make two Customer instances with the same id equal even if their name differs — that's identity-based equality.

Use this snippet as your template for the playground below.

Reading in progress · 0 of 3 activities done