← Назад к вопросам

Из чего состоит DDD

2.3 Middle🔥 241 комментариев
#Архитектура и паттерны#Базы данных (NoSQL)

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

# DDD: архитектурный подход к разработке ПО

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

Стратегические паттерны DDD

1. Bounded Context

Bounded Context — это логическая граница, в пределах которой существует единое понимание того или иного концепта. Это отделение ответственности между различными частями системы.

# Пример: Bounded Context для системы заказов и доставки
class OrderContext:
    """Контекст управления заказами"""
    def create_order(self, items: List[Item]) -> Order:
        pass

class DeliveryContext:
    """Контекст управления доставкой"""
    def schedule_delivery(self, order_id: str, address: str) -> Delivery:
        pass

2. Ubiquitous Language

Это общий язык, который понимают как разработчики, так и бизнес-аналитики. Все термины в коде должны соответствовать словарю предметной области.

# Правильно: используем терминологию предметной области
class Customer:
    def place_order(self, items: List[Product]) -> Order:
        pass

# Неправильно: абстрактные имена
class User:
    def create(self, data: dict) -> Entity:
        pass

Тактические паттерны DDD

3. Entities (Сущности)

Объекты, которые имеют уникальный идентификатор и изменяемое состояние. Их идентичность сохраняется на протяжении всего жизненного цикла.

class Order:
    def __init__(self, order_id: str, customer_id: str):
        self.id = order_id
        self.customer_id = customer_id
        self.status = OrderStatus.PENDING
        self.created_at = datetime.now(UTC)
    
    def confirm(self) -> None:
        if self.status != OrderStatus.PENDING:
            raise InvalidOrderStateError()
        self.status = OrderStatus.CONFIRMED

4. Value Objects

Объекты без собственной идентичности, определяемые своими атрибутами. Они неизменяемы и сравниваются по значению.

from dataclasses import dataclass

@dataclass(frozen=True)
class Money:
    amount: Decimal
    currency: str
    
    def add(self, other: 'Money') -> 'Money':
        if self.currency != other.currency:
            raise CurrencyMismatchError()
        return Money(self.amount + other.amount, self.currency)

@dataclass(frozen=True)
class EmailAddress:
    value: str
    
    def __post_init__(self):
        if not self._is_valid_email(self.value):
            raise InvalidEmailError()

5. Aggregates

Группировки Entity и Value Objects вокруг корневого Aggregate Root. Aggregate Root отвечает за обеспечение консистентности данных внутри Aggregate.

class OrderAggregate:
    """Root Aggregate для заказов"""
    def __init__(self, order_id: str, customer_id: str):
        self.id = order_id
        self.customer_id = customer_id
        self.items: List[OrderItem] = []
        self.status = OrderStatus.PENDING
    
    def add_item(self, product: Product, quantity: int) -> None:
        if self.status != OrderStatus.PENDING:
            raise CannotModifyConfirmedOrder()
        item = OrderItem(product, quantity)
        self.items.append(item)
    
    def get_total_price(self) -> Money:
        return sum(
            (item.price * item.quantity for item in self.items),
            Money(Decimal(0), 'USD')
        )

6. Repositories

Абстракции для доступа к Aggregates. Они скрывают детали персистентности и работают на уровне бизнес-объектов.

from abc import ABC, abstractmethod

class OrderRepository(ABC):
    @abstractmethod
    def save(self, order: OrderAggregate) -> None:
        pass
    
    @abstractmethod
    def find_by_id(self, order_id: str) -> Optional[OrderAggregate]:
        pass
    
    @abstractmethod
    def find_by_customer(self, customer_id: str) -> List[OrderAggregate]:
        pass

class SQLOrderRepository(OrderRepository):
    def __init__(self, db_session):
        self.db = db_session
    
    def save(self, order: OrderAggregate) -> None:
        orm_order = OrderORM(
            id=order.id,
            customer_id=order.customer_id,
            status=order.status.value
        )
        self.db.add(orm_order)
        self.db.commit()

7. Domain Services

Сервисы для бизнес-логики, которая не принадлежит ни одному конкретному Entity или Aggregate.

class PricingService:
    """Domain Service для расчёта цен"""
    def calculate_discount(self, order: OrderAggregate, customer: Customer) -> Money:
        if customer.loyalty_level >= LoyaltyLevel.GOLD:
            return order.get_total_price() * Decimal('0.1')
        return Money(Decimal(0), order.get_total_price().currency)

8. Domain Events

События, которые сигнализируют об изменениях в domain.

@dataclass
class OrderConfirmedEvent:
    order_id: str
    customer_id: str
    timestamp: datetime
    total_price: Money

class OrderAggregate:
    def confirm(self) -> None:
        if self.status == OrderStatus.PENDING:
            self.status = OrderStatus.CONFIRMED
            event = OrderConfirmedEvent(
                order_id=self.id,
                customer_id=self.customer_id,
                timestamp=datetime.now(UTC),
                total_price=self.get_total_price()
            )
            self.events.append(event)

Взаимосвязь компонентов

DDD создаёт архитектуру, где каждый компонент имеет чёткую ответственность. Entities и Value Objects — основа, Aggregates обеспечивают целостность, Repositories скрывают детали хранения, Domain Services реализуют сложную логику, а Domain Events связывают независимые контексты.