TGViewer
Beer::Code🍺 Beer::Code🍺 @beerphp · 3.64K subscribers
Post #122 3.16K
Aggregate

Що робити, коли нам все таки потрібні різні частинки, бо вони приймають участь в одній операції? Наприкад, створення Invoice для того самого Order (продовжуємо думку попереднього поста) може вимагати як особистих даних користувача, так і повного списку товарів (щоб їх там відобразити), а також загальної суми для транзакції. Тут на поміч приходить агрегат.

👉 Агрегат — група пов’язаних об’єктів домену. Він складається з однієї або декількох сутностей (а інколи й об’єктів-значень), які логічно пов’язані між собою.

У нашому випадку, коли для створення інвойсу потрібні дані користувача, список товарів і сума, агрегат має зібрати все це разом і гарантувати, що зміни відбуватимуться транзакційно. Наприклад, якщо додати новий товар, то загальна сума автоматично оновиться.

❗️ Агрегат має корінь (aggregate root), через який відбуваються всі операції. Він відповідає за забезпечення інваріантів (бізнес-правил), надання методів для доступу та зміни стану, щоб зовнішні виклики не могли порушити ту саму узгодженість. Це означає, що замість того, щоб окремо взаємодіяти з обʼєктами даних користувача, товарами й сумою, ви працюєте з одним об’єктом, який уже все це тримає в узгодженому стані.

[golang] [php] [python] [nodejs]
// Клас для даних користувача
final class UserData {
public function __construct(
public string $name,
public Address $address
) {}
}

/**
* @param Product[] $items
*/
final class Invoice {
public function __construct(
public OrderId $orderId,
public UserData $user,
public array $items,
public Money $total
) {}
}

// Агрегат для замовлення
final class OrderAggregate {
private OrderId $orderId;
private UserData $user;
private array $items;
private Money $total;

public function __construct(OrderId $orderId, UserData $user, array $items) {
$this->orderId = $orderId;
$this->user = $user;
$this->items = $items;
$this->calculateTotal();
}

// Розрахунок загальної суми
private function calculateTotal(): void {
$this->total = array_sum(array_map(fn($item) => $item->price * $item->amount, $this->items));
}

// Додавання нового товару
public function addItem(string $name, Money $price, int $quantity): void {
$this->items[] = new Product($name, $price, $quantity);
$this->calculateTotal();
}

// Створення інвойсу
public function createInvoice(): Invoice {
return new Invoice($this->orderId, $this->user, $this->items, $this->total);
}
}

// Використання
$user = new UserData('Іван Петренко', new Address('Київ', 'вул. Шевченка', '1'));

$order = new OrderAggregate('123', $user, [new Product('Ноутбук', 20000, 1)]);
$order->addItem('Мишка', 500, 2);
$invoice = $order->createInvoice();
echo \sprintf(‘Інвойс для замовлення %s, користувач: %s, сума: %s грн\n’, $invoice->orderId, $invoice->user->name, $invoice->total);


👉 Коли вам потрібно створити інвойс, ви викликаєте createInvoice(), і агрегат повертає об’єкт Invoice із усіма потрібними даними. Вам не доводиться вручну збирати ці частинки з різних джерел чи турбуватися про їхню узгодженість — агрегат це робить за вас.

Підсумуємо:
– Всі зміни в агрегаті виконуються узгоджено. Після завершення транзакції стан усіх сутностей агрегата має бути консистентним.
– Агрегати визначають область транзакції – операції над ними мають виконуватися атомарно. Наприклад, якщо ми щось зберігаємо, або дістаємо зі storage, то ми маємо це робити з усім агрегатом. Дані не можуть бути оновлені частково.
– Зовнішні об’єкти можуть взаємодіяти лише з агрегатним коренем, що дозволяє зберігати внутрішню цілісність агрегата.

❗️Агрегат не повинен містити інших агрегатів. Кожен агрегат має свою власну область відповідальності. Якщо вам потрібно з якоїсь причини повʼязати агрегати — використовуйте ідентифікатори для того щоб зробити посилання на інший агрегат.

#backend #architecture #middle #source
  • 👍 29
  • 🔥 3
  • 🗿 2
  • 🙊 1
More from @beerphp
  1. Sep 22, 2026Anthropic випустила Opus 5.5 За словами Anthropic, на більшості задач вона працює на рівні…
  2. Sep 21, 2026Доречі, цього тижня буду проводити НОВИЙ воркшоп Harness Engineering - 24 і 26 вересня. Од…
  3. Sep 21, 2026Хочу поділитись своєю мотивацією На тому тижні був воркшоп Agentic Engineering Workflow Ко…
  4. Sep 20, 2026Post #198
  5. Sep 14, 2026Не можу не поділитись, вчора отримав такий відгук Це прям паливо заради якого хочеться про…
  6. Sep 13, 2026І знову я зі своїм воркшопом 🙂 Але перед цим - попереджаю і кажу чесно, канал і соцмережі…
Threads Profile ViewerView any public Threads profile without an account.Open ThreadLook →Writing with AI? Make it sound human.Metric37 rewrites AI drafts so they read naturally. Free AI detector, 1,500 words free.Try Metric37 →