Назовите ключевые строительные блоки в Domain-Driven Design (DDD)

Ответ

Domain-Driven Design (DDD) предлагает набор концепций и паттернов (строительных блоков) для проектирования сложных программных систем, ориентированных на предметную область бизнеса.

Ключевые строительные блоки:

  1. Entity (Сущность) Объект, обладающий уникальным идентификатором и жизненным циклом. Его идентичность важна, даже если атрибуты меняются. Пример: Пользователь с userId.

  2. Value Object (Объект-значение) Неизменяемый (immutable) объект, который определяется своими атрибутами, а не идентификатором. Два Value Object с одинаковыми атрибутами считаются равными. Пример: Адрес (улица, город), Деньги (сумма, валюта).

  3. Aggregate (Агрегат) Кластер связанных объектов (сущностей и объектов-значений), который рассматривается как единое целое для изменения данных. У агрегата есть Aggregate Root (корень) — сущность, которая является единственной точкой входа для всех операций с агрегатом и следит за соблюдением бизнес-правил (инвариантов).

  4. Repository (Репозиторий) Абстракция, имитирующая коллекцию объектов в памяти. Скрывает детали хранения (база данных, API) и предоставляет интерфейс для получения и сохранения агрегатов.

  5. Domain Service (Сервис домена) Содержит доменную логику, которую сложно отнести к какой-либо конкретной сущности или объекту-значению. Часто координирует работу нескольких агрегатов.

  6. Domain Event (Событие домена) Объект, который представляет собой что-то значимое, произошедшее в предметной области. Пример: ЗаказОформлен, ПользовательЗарегистрирован.

Пример Агрегата Order:

# Value Object
class OrderItem:
    def __init__(self, product_id: str, quantity: int, price: float):
        if quantity <= 0:
            raise ValueError("Quantity must be positive")
        self.product_id = product_id
        self.quantity = quantity
        self.price = price

# Aggregate Root
class Order:
    def __init__(self, order_id: str, customer_id: str):
        self.id = order_id
        self.customer_id = customer_id
        self._items: list[OrderItem] = []
        self.status = "created"

    # Метод корня агрегата контролирует добавление элементов
    # и защищает инвариант (например, нельзя добавить товар в оплаченный заказ)
    def add_item(self, item: OrderItem):
        if self.status != "created":
            raise Exception("Cannot add items to a completed order")
        self._items.append(item)

    def complete_order(self):
        self.status = "completed"