[Entity и Value Object в DDD]
Привет! В DDD сразу встречаешь два ключевых понятия — Entity и Value Object. Оба вроде как про данные, но ведут себя по-разному.
Что такое `Entity`?
Что такое `Value Object`?
Когда что использовать?
- Если объект уникален сам по себе — это
- Если важны только его значения — это
Фишка DDD:
Хорошая практика — делать
#DDD #Python #Entity #ValueObject #Программирование
Привет! В DDD сразу встречаешь два ключевых понятия — Entity и Value Object. Оба вроде как про данные, но ведут себя по-разному.
Что такое `Entity`?
Entity
— это объект, который имеет уникальный идентификатор и жизненный цикл. Его идентичность важна, и она сохраняется на протяжении всего времени существования объекта. Например, пользователь в системе (User) — это Entity
, потому что у него есть уникальный ID, и даже если его имя или email изменятся, это все равно будет тот же самый пользователь.from dataclasses import dataclass, field
import uuid
@dataclass
class User:
name: str
email: str
id: uuid.UUID = field(default_factory=uuid.uuid4, init=False)
def __eq__(self, other):
if isinstance(other, User):
return self.id == other.id
return False
# Пример использования:
user1 = User("Иван", "ivan@example.com")
user2 = User("Иван", "ivan@example.com")
print(user1) # User(name='Иван', email='ivan@example.com', id=...)
print(user2) # User(name='Иван', email='ivan@example.com', id=...)
print(user1 == user2) # False, потому что ID разные
Что такое `Value Object`?
Value Object
, в отличие от Entity
, не имеет идентичности. Он определяется своими атрибутами, и если все атрибуты одинаковы, то два Value Object
считаются равными. Value Object
обычно неизменяемы (immutable), что делает их более предсказуемыми и безопасными в использовании.from dataclasses import dataclass
import re
@dataclass(frozen=True)
class EmailAddress:
value: str
def __post_init__(self):
if not self._is_valid_email(self.value):
raise ValueError(f"Некорректный email: {self.value}")
@staticmethod
def _is_valid_email(email: str) -> bool:
pattern = r"^[\w\.-]+@[\w\.-]+\.\w+$"
return re.match(pattern, email) is not None
# Пример использования:
try:
email1 = EmailAddress("valid.email@example.com")
print(email1) # EmailAddress(value='valid.email@example.com')
email2 = EmailAddress("invalid-email") # Ошибка валидации!
except ValueError as e:
print(e)
Когда что использовать?
- Если объект уникален сам по себе — это
Entity
.- Если важны только его значения — это
Value Object
.Фишка DDD:
Хорошая практика — делать
Value Objects
иммутабельными и использовать их для инкапсуляции логики. Например, не просто string
для email
, а EmailAddress
, который сразу валидирует значение.Entity
и Value Object
— это мощные концепции, которые помогают структурировать код и делать его более предсказуемым. В Python их реализация может быть элегантной с использованием dataclasses
.#DDD #Python #Entity #ValueObject #Программирование
[Агрегаты в DDD: Организация сложности через границы]
В Domain-Driven Design (DDD) работа с сложными доменными моделями требует четкой структуры, чтобы избежать хаоса.
Агрегат (Aggregate) — один из ключевых паттернов DDD, который помогает управлять целостностью данных и упрощает взаимодействие с моделью.
Что такое Aggregate?
Агрегат — это кластер связанных объектов, рассматриваемых как единое целое.
Он объединяет:
1) Корень агрегата (Aggregate Root) — единственная точка входа для внешних взаимодействий.
2) Внутренние сущности (Entity) и value-объекты (ValueObject) — элементы, которые могут изменяться только через корень.
По своей сути агрегат - это тоже Entity.
Зачем нужны агрегаты?
- Консистентность данных
Агрегат гарантирует, что изменения внутри него соответствуют бизнес-правилам. Например, нельзя добавить OrderItem с отрицательной ценой — корень проверяет это.
- Границы транзакций
Изменения в рамках одного агрегата обычно выполняются в одной транзакции. Это упрощает управление конкурентным доступом.
- Сокрытие сложности
Внешние системы не знают о внутренней структуре агрегата — они работают только с корнем.
Ключевые принципы проектирования:
- Единый корень
Все внешние запросы идут через корень. Если нужно изменить дочерний объект — делайте это через методы корня.
- Инварианты внутри границ
Правила целостности (например, «максимум 10 товаров в заказе») должны соблюдаться внутри агрегата.
- Ссылки только на корни других агрегатов
Агрегаты не должны хранить ссылки на внутренние объекты чужих агрегатов — только на их корни (через идентификаторы).
Пример:
Агрегат Заказ (корень) включает элементы заказа (OrderItem), адрес доставки и методы для добавления/удаления товаров. Внешние системы обращаются только к Order, а не к OrderItem напрямую.
Ошибки при работе с агрегатами:
- Слишком большие агрегаты
Если агрегат включает десятки сущностей, это усложняет транзакции и повышает риск конфликтов.
Решение: Дробите агрегаты, ориентируясь на бизнес-контекст.
- Нарушение инкапсуляции
Прямое изменение дочерних объектов в обход корня ломает целостность.
Решение: Скрывайте внутренние структуры (private поля, методы только для корня).
Как определить границы агрегата?
- Ищите транзакционные границы — что должно изменяться атомарно?
- Анализируйте бизнес-инварианты — какие правила связывают объекты?
- Избегайте «анаемичных» агрегатов — они должны содержать логику, а не быть просто набором данных.
———
Итого
Агрегаты в DDD — это не просто группировка классов, а способ защитить целостность домена и управлять сложностью.
Правильно выбранные границы агрегатов делают код:
- Более понятным,
- Устойчивым к ошибкам,
- Легким для масштабирования.
Главное правило:
Если сомневаетесь — делайте агрегаты меньше. Четкие границы спасут в долгосрочной перспективе!
P.s.
Полезная ссылка про агрегаты: https://dddinpython.hashnode.dev/mastering-aggregates-in-domain-driven-design
#DDD #Python #Aggregate #Entity #ValueObject #Программирование
В Domain-Driven Design (DDD) работа с сложными доменными моделями требует четкой структуры, чтобы избежать хаоса.
Агрегат (Aggregate) — один из ключевых паттернов DDD, который помогает управлять целостностью данных и упрощает взаимодействие с моделью.
Что такое Aggregate?
Агрегат — это кластер связанных объектов, рассматриваемых как единое целое.
Он объединяет:
1) Корень агрегата (Aggregate Root) — единственная точка входа для внешних взаимодействий.
2) Внутренние сущности (Entity) и value-объекты (ValueObject) — элементы, которые могут изменяться только через корень.
По своей сути агрегат - это тоже Entity.
Зачем нужны агрегаты?
- Консистентность данных
Агрегат гарантирует, что изменения внутри него соответствуют бизнес-правилам. Например, нельзя добавить OrderItem с отрицательной ценой — корень проверяет это.
- Границы транзакций
Изменения в рамках одного агрегата обычно выполняются в одной транзакции. Это упрощает управление конкурентным доступом.
- Сокрытие сложности
Внешние системы не знают о внутренней структуре агрегата — они работают только с корнем.
Ключевые принципы проектирования:
- Единый корень
Все внешние запросы идут через корень. Если нужно изменить дочерний объект — делайте это через методы корня.
- Инварианты внутри границ
Правила целостности (например, «максимум 10 товаров в заказе») должны соблюдаться внутри агрегата.
- Ссылки только на корни других агрегатов
Агрегаты не должны хранить ссылки на внутренние объекты чужих агрегатов — только на их корни (через идентификаторы).
Пример:
Агрегат Заказ (корень) включает элементы заказа (OrderItem), адрес доставки и методы для добавления/удаления товаров. Внешние системы обращаются только к Order, а не к OrderItem напрямую.
Ошибки при работе с агрегатами:
- Слишком большие агрегаты
Если агрегат включает десятки сущностей, это усложняет транзакции и повышает риск конфликтов.
Решение: Дробите агрегаты, ориентируясь на бизнес-контекст.
- Нарушение инкапсуляции
Прямое изменение дочерних объектов в обход корня ломает целостность.
Решение: Скрывайте внутренние структуры (private поля, методы только для корня).
Как определить границы агрегата?
- Ищите транзакционные границы — что должно изменяться атомарно?
- Анализируйте бизнес-инварианты — какие правила связывают объекты?
- Избегайте «анаемичных» агрегатов — они должны содержать логику, а не быть просто набором данных.
———
Итого
Агрегаты в DDD — это не просто группировка классов, а способ защитить целостность домена и управлять сложностью.
Правильно выбранные границы агрегатов делают код:
- Более понятным,
- Устойчивым к ошибкам,
- Легким для масштабирования.
Главное правило:
Если сомневаетесь — делайте агрегаты меньше. Четкие границы спасут в долгосрочной перспективе!
P.s.
Полезная ссылка про агрегаты: https://dddinpython.hashnode.dev/mastering-aggregates-in-domain-driven-design
#DDD #Python #Aggregate #Entity #ValueObject #Программирование