DDD

Глава 11. Еволюція Проектних Рішень

Вітаю! Якщо ви читаєте ці рядки, ви пройшли довгий шлях від визначення Єдиної Мови до реалізації складних Саг і Агрегатів.

Глава 11. Еволюція Проектних Рішень

Вітаю! Якщо ви читаєте ці рядки, ви пройшли довгий шлях від визначення Єдиної Мови до реалізації складних Саг і Агрегатів.

Але найважливіший урок DDD ми приберегли на кінець: Всі архітектурні рішення — тимчасові.

Те, що було ідеальним рішенням для стартапу з 3 людей (Моноліт на Laravel/Django), стане смертним вироком для компанії з 500 інженерів. І навпаки: мікросервісна архітектура Netflix вб'є ваш стартап ще до першого релізу.

У цій главі ми поговоримо про Час. Як наша система повинна змінюватися разом з бізнесом.

Від CRUD до DDD

Як еволюціонує код, коли Generic Subdomain стає Core Domain.

Закон Конвея

Чому структура команд визначає архітектуру, і як цим керувати.

Refactoring to Deeper Insight

Як змінювати модель, коли ми дізнаємося щось нове про бізнес.

1. Життєвий Цикл Піддомену

У Главі 2 ми розділили світ на Core, Supporting та Generic domains. Але це не статичний поділ.

Generic -> Core

Уявіть, що ви будуєте інтернет-магазин у 2010 році.

  • Доставка: Це просто поле "Shipping Address". Ви робите це як Generic Subdomain (CRUD).
  • 2015 рік: Ви вирішуєте конкурувати швидкістю доставки. Ви запускаєте власних кур'єрів, дрони, склади.
  • Result: Доставка перетворилася на Core Domain.
  • Дія: Вам потрібно переписати модуль доставки. Виділити його в окремий контекст, застосувати складну логіку маршрутизації (Domain Model), можливо, виділити в мікросервіс.

Core -> Generic

  • Пошук: Ви написали свій геніальний пошуковий двигун. Це ваш Core.
  • 2020 рік: Elasticsearch/Algolia роблять це краще і дешевше.
  • Дія: Ви викидаєте свій код і інтегруєте зовнішнє рішення. Ваш Core став Generic.
Loading diagram...

graph LR GenesisGenesis (Start) -->|Evolution| CustomCustom Built (Core) Custom -->|Standardization| ProductProduct/Rental (Off-the-shelf) Product -->|Ubiquity| UtilityUtility (Commodity/SaaS)

style Custom fill:#ffccbc
style Utility fill:#c8e6c9

"Commoditization" trap

Найбільша помилка — триматися за свій кастомний код, коли світ вже придумав стандартне рішення. Якщо ви пишете свій Authentication Server у 2024 році замість використання Auth0/Keycloak — ви спалюєте гроші компанії. Аутентифікація — це Commodity.


2. Від Моноліту до Мікросервісів (і назад)

Тут ми не будемо холіварити. Ми подивимося на це через призму DDD.

Модульний Моноліт — Золота Середина

Більшість проектів повинні починатися і закінчуватися тут.

  • Єдина база даних (але розділені схеми!).
  • Один деплоймент юніт.
  • Чіткі межі модулів (Context Boundaries).
  • Публічний API модулів (Interfaces).
Loading diagram...

graph TD subgraph Monolith ModASales Module ModBInventory Module ModCShipping Module end

ModA -.->|Direct Call (DTO)| ModB
ModA -.->|Domain Event| ModC

DB[(Database)]
ModA -->|Schema A| DB
ModB -->|Schema B| DB
ModC -->|Schema C| DB

Note right of DB: Modules share THE SAME DB instance,\nbut own separate TABLES/SCHEMAS.

Коли виділяти Мікросервіс?

  1. Незалежне Масштабування: Модуль обробки відео вимагає GPU і 100 інстансів, а адмінка — 1 інстанс і 100мб RAM.
  2. Незалежний Релізний Цикл: Команда "Payment" боїться деплоїти свій код разом з нестабільним кодом "Recommendations".
  3. Технологічна Необхідність: Модуль ML краще писати на Python, а бекенд на C#/Java.
  4. Compliance: Дані кредитних карток (PCI DSS) повинні жити в ізольованому контурі.
Distributed MonolithЯкщо ви розбили моноліт на сервіси, але вони все ще ходять в одну базу даних, або спілкуються синхронно через HTTP при кожному запиті — ви створили Розподілений Моноліт. Це найгірша з усіх архітектур.

Еволюція Context Mapping

Стосунки між командами теж змінюються.

  1. Partnership: На старті 2 команди сидять поруч. Вони домовляються про зміни в API за кавою.
  2. Customer-Supplier: Коли одна команда (Inventory) стає критичною для 5 інших, вона не може задовольняти хотілки кожного. Вона стає Upstream, інші — Downstream.
  3. OHS (Open Host Service): Inventory публікує стабільний API і каже: "Використовуйте це або йдіть лісом".
  4. ACL: Команда Sales не хоче залежати від змін Inventory, тому будує свій ACL.

3. Закон Конвея (Conway's Law)

"Організації, які проектують системи, змушені створювати проекти, які є копіями комунікаційних структур цих організацій." — Мелвін Конвей.

Якщо у вас є Команда Backend, Команда Frontend і Команда DBA — ви отримаєте тришарову архітектуру, де зміни в бізнес-логіці вимагатимуть синхронізації трьох менеджерів.

Inverse Conway Maneuver (Зворотній Маневр Конвея)

Якщо ви хочете мікросервісну (або модульну) архітектуру, сфокусовану на Бізнес-Доменах:

  1. Створіть Крос-функціональні команди (Cross-functional Stream-aligned teams).
  2. Дайте кожній команді володіння одним Обмеженим Контекстом (Catalog Team, Checkout Team).
  3. Архітектура підтягнеться під структуру команд.

4. Case Study: Refactoring The Big Ball of Mud

У вас є моноліт, де User клас має 5000 рядків, і все залежить від усього. З чого почати?

Крок 1: Зупинити кровотечу

Встановіть правило: Новий код пишеться в нових модулях. Не додавайте 5001-й рядок у User.php. Створіть UserPreferenceService збоку.

Крок 2: Визначити межі (Logical Boundaries)

Почніть групувати код у папки за бізнес-змістом (Sales, Catalog), навіть якщо вони фізично знаходяться в одному проекті. Використовуйте інструменти типу Deptrac (PHP) або ArchUnit (Java), щоб заборонити незаконні імпорти між цими папками.

Крок 3: Розв'язати вузли (Decoupling)

Найважча частина.

  • Проблема: Catalog напряму лізе в таблицю users через JOIN.
  • Рішення:
    1. Дублювання даних: Catalog зберігає копію ім'я користувача (якщо це допустимо).
    2. Події: UserUpdated -> Catalog оновлює свій кеш.
    3. API: Catalog запитує UserModule->getName($id).
Database RefactoringРозділення коду — це легко. Розділення даних — це пекло. Почніть з створення VIEW для кожного модуля, щоб вони думали, що володіють своїми таблицями. Потім фізично розділіть таблиці.


5. Refactoring toward Deeper Insight

Ерік Еванс каже: "Справжнє DDD починається тоді, коли ви робите прорив у розумінні моделі".

Приклад: Booking vs Allocation

Спершу у нас була сутність Booking (Бронювання). Ми думали: "Бронювання — це запис, що кімната зайнята".

Проблема: Бізнес каже "Ми хочемо овербукінг (продавати більше місць, ніж є)", "Ми хочемо переселяти людей", "Ми хочемо бронювати тип кімнати, а не конкретний номер".

Прорив (Insight): Ми зрозуміли, що є ДВІ різні концепції:

  1. Reservation: Обіцянка надати послугу (Юридичний контракт). Це про гроші і дати.
  2. Allocation: Прив'язка конкретного ресурсу (Room 101) до клієнта. Це про логістику.

Рефакторинг: Ми розділяємо Booking на Reservation і RoomAllocation. Це фундаментально змінює код, базу даних і API. Але це робить систему набагато гнучкішою. Тепер ми можемо мати Reservation без Allocation (овербукінг).

  • Lesson: Не бійтеся змінювати імена і структуру класів, якщо змінилося ваше розуміння бізнесу. Код — це не відлитий у граніті пам'ятник, це глина.

6. Техніки Knowledge Crunching

Як досягти таких інсайтів? Не сидячи мовчки за клавіатурою.

Event Storming

Зберіть в одній кімнаті (або Miro) розробників, тестувальників, менеджерів і справжніх юзерів.

  • Помаранчеві стікери: Domain Events (Що сталося? "Замовлення Створено").
  • Блакитні стікери: Commands (Хто ініціював? "Клієнт натиснув кнопку").
  • Жовті стікери: Aggregates (Де живе логіка?).

За 2 години Event Storming ви знайдете більше багів і невідповідностей у вимогах, ніж за 2 місяці Jira-переписки.

Whirlpool Process (Вир)

Процес моделювання не лінійний. Це постійний цикл:

  1. Спробували модель.
  2. Написали код.
  3. Знайшли кейс, який модель не покриває ("А що якщо клієнт — це компанія?").
  4. Змінили модель.
  5. Refactor.

Модель, яка не змінюється протягом року — це мертва модель.


7. Висновок

Domain-Driven Design — це не про патерни. Не про Репозиторії, Агрегати чи Value Objects.

Це про Спілкування. Про те, щоб розробники і бізнес-експерти говорили однією мовою і будували модель, яка вирішує реальні проблеми.

Успіхів у ваших проектах! Нехай ваш код буде чистим, а домен — багатим.


Що читати далі?

  1. Eric Evans - Domain-Driven Design (The Blue Book) — філософія.
  2. Vaughn Vernon - Implementing DDD (The Red Book) — практика.
  3. Nick Tune / Kacper Gunia - Architecture Patterns with Python/C# (Modern approach).
  4. Vladik Khononov - Learning Domain-Driven Design (Найкраще для старту).
Copyright © 2026