Gymterview
middle

Что такое DDD (Domain-Driven Design), назовите основные понятия

Domain-Driven Design (DDD) — подход к разработке программного обеспечения, при котором в центре проектирования находится предметная область (домен) бизнеса. Предложен Эриком Эвансом в книге «Domain-Driven Design: Tackling Complexity in the Heart of Software» (2003).

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

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

Ubiquitous Language (Единый язык)

Общий язык, разделяемый разработчиками и бизнес-экспертами. Термины из этого языка используются в коде, документации и разговорах. Например, в банковском контексте: «Платёжное поручение», «Корреспондентский счёт», «Операционный день».

Пример
// Единый язык в коде: не "processItem()", а "executePaymentOrder()"
public class PaymentOrder {          // Платёжное поручение
    private Money amount;            // Сумма
    private Account payerAccount;    // Счёт плательщика
    private Account payeeAccount;    // Счёт получателя

    public void execute() { ... }    // Исполнить
    public void reject(String reason) { ... }  // Отклонить
}

Bounded Context (Ограниченный контекст)

Явная граница, внутри которой определённая модель однозначна и согласована. Один и тот же термин может означать разные вещи в разных контекстах.

Пример
┌──────────────────┐     ┌──────────────────┐     ┌──────────────────┐
│   Контекст       │     │   Контекст       │     │   Контекст       │
│   «Платежи»      │     │   «Клиенты»      │     │   «Риски»        │
│                  │     │                  │     │                  │
│  Account =       │     │  Account =       │     │  Account =       │
│  расчётный счёт  │     │  учётная запись   │     │  объект скоринга │
│  с балансом      │     │  клиента в ЛК     │     │                  │
└──────────────────┘     └──────────────────┘     └──────────────────┘

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

Entity (Сущность)

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

Пример кода
public class Account {
    private final AccountId id;  // идентичность
    private Money balance;
    private AccountStatus status;

    // Бизнес-поведение внутри сущности (Rich Domain Model)
    public void withdraw(Money amount) {
        if (status != AccountStatus.ACTIVE)
            throw new AccountNotActiveException(id);
        if (balance.isLessThan(amount))
            throw new InsufficientFundsException(id, amount);
        balance = balance.minus(amount);
    }
}

Value Object (Объект-значение)

Объект, определяемый своими атрибутами, а не идентичностью. Два Value Object с одинаковыми полями — это один и тот же объект. Неизменяем (immutable).

Пример кода
public final class Money {
    private final BigDecimal amount;
    private final Currency currency;

    public Money(BigDecimal amount, Currency currency) {
        this.amount = amount;
        this.currency = currency;
    }

    public Money plus(Money other) {
        if (!currency.equals(other.currency))
            throw new CurrencyMismatchException();
        return new Money(amount.add(other.amount), currency);
    }

    // equals() и hashCode() по всем полям
}

Aggregate (Агрегат)

Кластер связанных сущностей и Value Objects, объединённых под одним корнем (Aggregate Root). Внешний мир взаимодействует с агрегатом только через корень. Агрегат гарантирует согласованность инвариантов.

Пример кода
// Aggregate Root
public class Order {
    private OrderId id;
    private List<OrderItem> items;  // часть агрегата
    private Money totalAmount;

    public void addItem(Product product, int quantity) {
        items.add(new OrderItem(product, quantity));
        recalculateTotal();
    }

    private void recalculateTotal() {
        totalAmount = items.stream()
            .map(OrderItem::getSubtotal)
            .reduce(Money.ZERO, Money::plus);
    }
}

Другие тактические паттерны

  • Repository (Репозиторий) — абстракция для доступа к агрегатам. Создаёт иллюзию коллекции в памяти. Интерфейс определяется в домене, реализация — в инфраструктуре.
  • Domain Event (Доменное событие) — событие, значимое для бизнеса, которое произошло в домене: PaymentExecuted, AccountBlocked, LimitExceeded.
  • Domain Service (Доменный сервис) — бизнес-логика, которая не принадлежит ни одной конкретной сущности (например, конвертация валют между двумя счетами).

На собеседовании: Интервьюер хочет услышать разницу между стратегическими (Bounded Context, Ubiquitous Language) и тактическими (Entity, Value Object, Aggregate) паттернами. Частая ошибка — знать только тактические паттерны и не понимать, зачем нужен Bounded Context.