Что такое Domain-Driven Design (DDD) и как вы его применяли?

«Что такое Domain-Driven Design (DDD) и как вы его применяли?» — вопрос из категории Архитектура, который задают на 10% собеседований Java Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

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

Ключевые строительные блоки DDD, которые я применял:

  1. Агрегат (Aggregate) — кластер связанных объектов (Entity и Value Object), рассматриваемых как единое целое. Доступ к ним идет через корень агрегата (Aggregate Root).
  2. Entity — объект, имеющий уникальный идентификатор и жизненный цикл.
  3. Value Object — иммутабельный объект, идентифицируемый по значениям его полей (например, Money с суммой и валютой).
  4. Репозиторий (Repository) — абстракция для хранения и извлечения агрегатов, скрывающая детали инфраструктуры.
  5. Сервис домена (Domain Service) — операция, которая не естественным образом принадлежит какой-либо Entity или Value Object.

Пример фрагмента доменного слоя на Java:

// Value Object
public record CustomerId(UUID value) {}

// Aggregate Root (Entity)
public class Order {
    private OrderId id;
    private CustomerId customerId;
    private List<OrderLine> lines; // OrderLine — это Entity внутри агрегата
    private OrderStatus status;

    // Доменная логика внутри агрегата
    public void addItem(ProductId productId, Quantity quantity, Price price) {
        // Проверка инвариантов (бизнес-правил)
        Objects.requireNonNull(productId);
        if (quantity.value() <= 0) {
            throw new IllegalArgumentException("Quantity must be positive");
        }
        this.lines.add(new OrderLine(productId, quantity, price));
    }

    public void cancel() {
        if (!status.canBeCancelled()) {
            throw new IllegalStateException("Order cannot be cancelled");
        }
        this.status = OrderStatus.CANCELLED;
    }
}

// Repository интерфейс в доменном слое
public interface OrderRepository {
    Optional<Order> findById(OrderId id);
    void save(Order order);
}

Применял DDD в проектах со сложной и изменчивой бизнес-логикой. Это помогает:

  • Сделать код понятным для экспертов предметной области.
  • Изолировать ядро системы от инфраструктурных деталей (БД, фреймворки).
  • Управлять сложностью через ограниченные контексты (Bounded Contexts).