Увійти Реєстрація
Блог Серії
Кар'єра
Вакансії Компанії
Навчання
Документація Співбесіди Тестування Відео
Екосистема
Пакети Ресурси Проєкти Інструменти Події
Інше
Про нас Реклама

Що таке агрегат у DDD і як він захищає інваріанти?

Агрегат - група пов'язаних об'єктів, яку розглядають як одне ціле для змін. Один з об'єктів - корінь агрегату: лише через нього зовнішній код змінює агрегат.

Приклад: замовлення (Order - корінь) з позиціями (OrderLine). Позицію не змінюють напряму - лише через замовлення:

$order->addLine($product, quantity: 2);
$order->changeQuantity($lineId, 5);
$order->removeLine($lineId);

Навіщо - інваріанти. Інваріант - бізнес-правило, яке має виконуватися завжди:

  • сума замовлення дорівнює сумі позицій;
  • у замовленні не більше 50 позицій;
  • оплачене замовлення не можна змінювати;
  • загальна знижка не перевищує 30%.

Якщо позиції можна змінювати напряму (OrderLine::find($id)->update(...)), правила перевіряються в кількох місцях - або не перевіряються. Корінь агрегату - єдине місце, де їх контролюють:

public function addLine(Product $product, int $quantity): void
{
    if ($this->isPaid()) {
        throw new OrderIsLocked($this);
    }
    if ($this->lines->count() >= 50) {
        throw new TooManyLines($this);
    }

    $this->lines->push(new OrderLine(...));
    $this->recalculateTotal();
}

Межа агрегату - межа транзакції. Агрегат зберігається й змінюється атомарно, в одній транзакції. Зміна двох агрегатів в одній транзакції - сигнал перевірити межі.

Правила проєктування (Вон Вернон):

  • маленькі агрегати: лише те, що потрібно для інваріантів. «Клієнт з усіма замовленнями» - поганий агрегат: зміна одного замовлення блокує всі;
  • посилання на інші агрегати - за ідентифікатором, а не об'єктом: замовлення зберігає customer_id, а не тримає Customer;
  • узгодженість між агрегатами - кінцева: через доменні події й окремі транзакції.

Конкурентність: два користувачі змінюють одне замовлення - потрібне оптимістичне блокування (версія агрегату) чи блокування рядка кореня.

У Laravel з Eloquent межі агрегату - домовленість, а не обмеження мови: моделі позицій усе одно можна змінити напряму. Допомагають код-рев'ю, методи на корені й те, що контролери працюють лише з коренем.

Докладніше в документації: Martin Fowler: DDD Aggregate

Перевір себе

20 випадкових питань за спробу, після завершення - розбір кожної помилки

Схожі питання