Что такое Domain-Driven Design (DDD) и каковы его ключевые концепции?

Ответ

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

Ключевые концепции:

  • Домен (Domain): Предметная область, для которой создается приложение. Например, «логистика», «банкинг».
  • Сущность (Entity): Объект, обладающий уникальным идентификатором и жизненным циклом. Например, Пользователь с UserID.
  • Объект-значение (Value Object): Неизменяемый (immutable) объект без уникального идентификатора, характеризуемый своими атрибутами. Например, Адрес или ДенежнаяСумма.
  • Агрегат (Aggregate): Кластер из связанных сущностей и объектов-значений, который рассматривается как единое целое. У агрегата есть корень (Aggregate Root) — единственная сущность, через которую происходит взаимодействие с другими частями агрегата. Это обеспечивает целостность данных и соблюдение бизнес-правил.
  • Репозиторий (Repository): Абстракция, которая предоставляет интерфейс для доступа к агрегатам, имитируя коллекцию объектов в памяти. Скрывает детали хранения данных (БД, файлы и т.д.).

Пример на Go:

// Order является корнем агрегата (Aggregate Root).
// Весь агрегат включает Order и OrderItem. ype Order struct {
    ID          string
    CustomerID  string
    Items       []*OrderItem // Коллекция объектов-значений
    totalPrice  float64
}

// AddItem - метод, инкапсулирующий бизнес-логику.
// Изменения внутри агрегата проходят через его корень.
func (o *Order) AddItem(productID string, quantity int, price float64) {
    item := &OrderItem{
        ProductID: productID,
        Quantity:  quantity,
        Price:     price,
    }
    o.Items = append(o.Items, item)
    o.totalPrice += price * float64(quantity)
}

// OrderItem - объект-значение (Value Object).
// У него нет своего ID, он определяется в контексте заказа.
type OrderItem struct {
    ProductID string
    Quantity  int
    Price     float64
}

// OrderRepository определяет контракт для хранения и извлечения агрегатов Order.
type OrderRepository interface {
    Save(order *Order) error
    FindByID(id string) (*Order, error)
}

DDD наиболее эффективен в больших и сложных проектах, где бизнес-логика является основной сложностью.