DDD: стратегия и тактика
В прошлом уроке мы построили ядро, в которое не протекает инфраструктура. Остался вопрос, который гексагон не отвечает: а что класть внутрь? Domain-Driven Design это самый известный ответ, и это два разных инструмента под одной обложкой. Стратегический, про язык и границы, полезен почти всем и почти бесплатен. Тактический, про агрегаты и репозитории, стоит дорого и окупается только в сложных доменах. Урок даёт обзор обоих и честно показывает цену.
Главный тезис Эванса, из которого выводится всё остальное: сложность большинства систем не техническая, а доменная. Не «как сохранить заказ в базу», а «что вообще значит заказ, когда он считается оплаченным и кто может его отменить». Если модель этих понятий в голове у бизнеса и модель в коде расходятся, каждый разговор и каждая фича превращаются в перевод с ошибками.
Стратегический DDD: язык и границы
Единый язык
Единый язык
это дисциплина: слова домена попадают в код без перевода. Менеджер
говорит «слот сгорает за сутки до события», значит в коде есть Slot и
expiresAt, а не TicketReservationEntity с validityWindowHours.
Звучит тривиально, работает глубоко. Перевод между «языком бизнеса» и
«языком кода» это место, где живут самые дорогие баги: эксперт говорит
«отменить покупку», разработчик слышит «удалить строку», и через месяц
выясняется, что отменённая покупка должна была остаться в отчётах и
вернуть деньги. Если бы в коде была функция cancelPurchase с
бизнес-семантикой, а не delete, вопрос «а что значит отменить» возник
бы на ревью, а не в инциденте.
Практический тест: прочитай вслух имена методов своего domain-слоя владельцу продукта. Если приходится переводить, языка два, и один из них лишний.
Bounded Context
Попытка построить одну модель на всю компанию проваливается всегда, и это не слабость команды, а свойство мира. Bounded Context легализует это: модель действует внутри границы, и в каждой границе своя.
Классический пример: Customer. В биллинге это плательщик с tax ID,
способом оплаты и задолженностью. В маркетинге это лид с историей
кликов и сегментом. В поддержке это человек с тикетами и уровнем
раздражения. Это три разные модели, и попытка слить их в одну
таблицу customers с сорока nullable-колонками даст худшее из всех
миров: каждый контекст тащит чужие поля, любая миграция согласуется
тремя командами, инварианты невозможно сформулировать.
Сильный сигнал, что граница рядом: эксперты разных отделов постоянно уточняют «ты в каком смысле?». Слово, меняющее смысл при переходе через дверь кабинета, меняет смысл и в коде.
Context map: отношения между границами
Контексты не живут изолированно, и отношения между ними тоже паттерны со словарём:
- Shared Kernel: два контекста делят кусок модели и меняют его только вместе. Дёшево и опасно: связывает релизные циклы.
- Customer/Supplier: downstream-контекст заказывает изменения у upstream, как у поставщика. Работает, когда у downstream есть голос.
- Conformist: downstream молча принимает модель upstream как есть (так живут интеграции с гигантами: их API не обсуждается).
- Anti-Corruption Layer: переводчик на границе, чтобы чужая модель не протекла в твою. Тот же адаптер из урока про гексагон, но мотив другой: не «сменить технологию», а «не дать чужому языку заразить мой».
- Open Host Service / Published Language: контекст публикует стабильный API и схему для всех потребителей сразу.
Карта этих отношений (context map) часто оказывается самым полезным артефактом DDD вообще: один рисунок отвечает на вопросы «почему мы не можем просто взять их таблицу» и «кто кому должен при изменении схемы».
Core, supporting, generic
Последний стратегический инструмент отвечает на вопрос «куда вкладывать инженерное время»:
- Core domain: то, чем продукт выигрывает. Здесь оправданы лучшие люди, тщательная модель и тактический DDD.
- Supporting: нужно, но не выигрывает. Простой код, transaction script, без героизма.
- Generic: у всех одинаково (auth, биллинг, почта). Купить или взять готовое.
Самая частая стратегическая ошибка: месяцы на идеальную доменную модель для generic-поддомена. Идеально спроектированная отправка писем не приносит ни одного клиента.
дальше после входа
Урок целиком открыт всем, кто вошёл. Войди по своему email, чтобы читать дальше.
Вход пока по приглашению. Если хочешь учиться, напиши Vassiliy.