Тактический дизайн в DDD: Мост между бизнесом и кодом
Когда мы слышим Domain Driven Design, на ум сразу приходят такие понятия, как Ubiquitous Language (Повсеместный/Всеобщий язык), Bounded Contexts (Ограниченные контексты), то есть чаще всего говорят о стратегическом дизайне.
Но между стратегией и кодом лежит большой очень важный слой — тактический дизайн. Это то, как стратегические идеи воплощаются в конкретные и работоспособные программные модели. Тактический дизайн — инструмент моделирования Bounded Context.
Этой части DDD незаслуженно уделяют мало внимания, хотя без тактики любая стратегия терпит поражение.
Разница между стратегическим и тактическим дизайном
Стратегический дизайн — отвечает на вопросы «зачем» и «как» разделять:
🠶 Где границы между контекстами?
🠶 Какие модели и команды за что отвечают?
🠶 Как построено взаимодействие между контекстами?
Тактический дизайн — здесь находим ответы на вопросы «как» реализовать внутри одного ограниченного контекста (Bounded Context):
🠶 Какие сущности находятся внутри контекста?
🠶 Какие инварианты должны соблюдаться?
🠶 Где агрегаты и их границы?
Цели тактического дизайна
Главная цель тактического дизайна — это создать код, который будет отображать ментальную модель бизнес-эксперта.
Основные задачи тактического дизайна:
🠶 Инкапсуляция логики — представление бизнес-логики в коде в максимально явном и читаемом виде.
🠶 Защита инвариантов — правила предметной области должны быть согласованы и непротиворечивы (простым языком, должна быть одна точка входа для изменения данных, которые живут в одной модели).
🠶 Обеспечить целостность данных.
🠶 Сделать код гибким, способным к быстрому изменению вслед за бизнес-логикой.
Важно понимать, что тактический дизайн невозможно спроектировать один раз на старте разработки. Когда мы погружаемся в бизнес-процессы и уточняем требования, хорошо спроектированная программная модель позволит быстро внести изменения в код.
Пример тактического дизайна
В качестве примера рассмотрим «избитый» пример из контекста управления заказами.
Ниже — один из вариантов реализации управления заказом с применением некоторых паттернов тактического дизайна:
Что дает такая реализация:
- Целостность - нельзя изменить OrderItem в обход Order.
- Ясность - все правила управления заказом находятся в одном классе.
- Безопасность - при изменении позиций заказа, инвариант totalAmount всегда будет пересчитан.
Почему не стоит упускать тактический дизайн и как это может повлиять на бизнес
Игнорирование тактического дизайна редко выглядит как проблема на старте. Если пропустить этот этап, то можно легко получить:
✕ "Анемичные" модели без поведения.
✕ Размазанную по всем компонентам (а иногда и сервисам) логику.
✕ Нарушения инвариантов - в разных местах кода могут производиться разные операции над инвариантами, а иногда и по разным правилам.
✕ Сложность в тестировании и поддержке.
В конечном итоге это может ударить по бизнесу:
✗ Потеря доверия клиентов из-за некорректных заказов.
✗ Дополнительные расходы на поддержку и исправление ошибок.
✗ Замедление скорости выхода новых фич.
✗ Невозможность быстро адаптироваться под новые правила ценообразования / акции / возвраты.
Хороший тактический дизайн - это страховка от дорогостоящих ошибок и технического долга.
Подпишись на мой телеграм-канал