---
title: "Предметно-ориентированное проектирование"
type: "architectural-pattern"
slug: "domain-driven-design"
url: "http://localhost:3000/ru/architectural-patterns/domain-driven-design.md"
also_known_as: "DDD"
description: "Подход к разработке ПО, ставящий в центр проектирования богатую модель бизнес-домена, выраженную на языке, общем для инженеров и экспертов предметной области."
languages: ["typescript"]
---
# Предметно-ориентированное проектирование

_Also known as: DDD_

> Подход к разработке ПО, ставящий в центр проектирования богатую модель бизнес-домена, выраженную на языке, общем для инженеров и экспертов предметной области.

## Intent

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

## Problem

По мере роста системы бизнес-правила склонны рассеиваться по контроллерам, сервисам и запросам к базе данных. Код отдаляется от того, как бизнес на самом деле говорит о своей работе, поэтому каждый разговор нуждается в переводе, а каждое изменение рискует нарушить правило, о котором никто не помнил.

Проектирование, центрированное на данных, усугубляет это: модели становятся анемичными мешками геттеров и сеттеров, инварианты не живут нигде конкретно, и система медленно превращается в "большой ком грязи", к которому осмеливаются прикасаться лишь немногие.

## Solution

Предметно-ориентированное проектирование атакует проблему на двух уровнях.

**Стратегическое проектирование** делит большой домен на _ограниченные контексты_ — явные границы, внутри которых модель и её язык согласованы, — и отображает связи между ними. Каждый контекст волен моделировать одно и то же понятие по-разному там, где бизнес действительно видит его по-разному.

**Тактическое проектирование** строит богатую модель внутри контекста из небольшого набора строительных блоков и настаивает на _едином языке_: одни и те же термины появляются в разговорах, в модели и в коде.

## Structure

Тактические строительные блоки:

* **Сущности** — объекты, определяемые идентичностью, которая сохраняется во времени (`Customer`, `Order`).
* **Объекты-значения** — неизменяемые объекты, определяемые своими атрибутами (`Money`, `Address`).
* **Агрегаты** — кластеры сущностей и объектов-значений с единственным _корнем агрегата_, который охраняет инварианты кластера и является единственной точкой входа для изменений.
* **Репозитории** — коллекциеподобные интерфейсы, загружающие и сохраняющие целые агрегаты, скрывая детали хранения.
* **Доменные сервисы** — операции без состояния, которые естественно не принадлежат одной сущности.
* **Доменные события** — записи о чём-то значимом, что произошло в домене.

Стратегические блоки — **ограниченный контекст** и **карта контекстов** — организуют эти модели по командам и подсистемам.

## Applicability

* Применяйте его, когда **основная сложность в бизнес-правилах**, а не в технологии — логистика, финансы, страхование, планирование.
* Применяйте его, когда нескольким командам нужно прийти к согласию об общем, развивающемся понимании домена.
* **Избегайте его** для простых CRUD-приложений или приложений ввода данных, где накладные расходы на моделирование дают мало.

## How to Implement

1. Беседуйте с экспертами предметной области и **выделяйте единый язык**; записывайте термины и их значения.
2. Определите **ядро домена** — часть, дающую конкурентное преимущество, — и сосредоточьте усилия моделирования там.
3. Разделите домен на **ограниченные контексты** и нарисуйте карту контекстов с их взаимосвязями.
4. Внутри контекста моделируйте **агрегаты** так, чтобы каждый обеспечивал свои инварианты в одной транзакции.
5. Загружайте и сохраняйте агрегаты через **репозитории**; публикуйте **доменные события** о том, что важно другим контекстам.
6. Постоянно совершенствуйте — модель никогда не «готова», она развивается по мере углубления понимания.

## Pros

* Удерживает код в согласии с бизнесом, поэтому изменения чисто отображаются на требования.
* Изолирует сложность за ограниченными контекстами.
* Общий язык снижает недопонимание между инженерами и экспертами.
* Богатая доменная логика отвязана от инфраструктуры и легко покрывается модульными тестами.

## Cons

* Крутая кривая обучения и реальные вложения в моделирование домена.
* Избыточно для простых или преимущественно CRUD-приложений.
* Требует постоянного доступа к экспертам предметной области.
* При неправильном применении строительные блоки превращаются в церемонию без пользы.
## Relations

**Related patterns**

- [CQRS](/ru/architectural-patterns/cqrs.md)

## Code Examples

### typescript

```typescript
class Money {
  constructor(readonly amount: number, readonly currency: string) {
    if (amount < 0) throw new Error('amount must be non-negative')
  }
}

// Корень агрегата: единственное место, где обеспечиваются инварианты Order.
class Order {
  private lines: { sku: string; qty: number }[] = []
  constructor(readonly id: string) {}

  addLine(sku: string, qty: number) {
    if (qty <= 0) throw new Error('quantity must be positive')
    this.lines.push({ sku, qty })
  }
}
```

