Реализация бизнес-логики: от стикеров Event Storming к реальному коду
Итак, мы приняли решение использовать подход Domain Driven Design для реализации нашего приложения. Мы собрали экспертов доменной области. Провели несколько сессий Event Storming. Выделили основные события, агрегаты, нарисовали карты контекстов и приступили к реализации.
Теперь перед нами возникают вопросы:
➤ Как реализовать код и логику наших модели?
➤ Какие есть варианты и подходы к имплементации бизнес-логики?
➤ Всегда ли надо использовать паттерн Domain Model?
Давайте разберемся...
Какие паттерны существуют для реализации бизнес-логики
В своей книге "Patterns of Enterprise Application Architecture" Мартин Фаулер выделил несколько подходов к организации бизнес-логики. Со временем наибольшую популярность среди разработчиков и архитекторов приобрели следующие паттерны:
✦ Transactional Script
✦ Active Record
✦ Domain Model
Каждый из них решает определенную задачу. Каждый из них может быть применен для реализации логики модели. Выбор зависит от сложности бизнес-логики, зрелости команды и требований к эволюции системы.
Рассмотрим более подробно, что из себя представляет каждый из них.
Transactional Script
Наиболее распространенный паттерн для реализации организации бизнес-логики. Большинство разработчиков так или иначе использовали его.
Суть паттерна: Каждый use-case/пользовательская операция — это одна процедура (метод), в котором последовательно выполняются основные действия, такие как валидация данных, загрузка и сохранение, вызов внешних систем и бизнес-правила (if-ы или более сложная логика, реализованная, например, через стратегию).
Плюсы:
✚ Просто понять и написать.
✚ Минимум абстракций.
✚ Легко отлаживать
Минусы:
━ При росте логики превращается в огромные методы на 300–500 строк.
━ Логика может дублироваться между похожими сценариями.
━ Трудно тестировать — часто приходится использовать только интеграционные тесты вместо unit-тестирования.
━ Анемичная модель (модель — просто DTO / запись из БД).
Active Record
Этот паттерн обрел популярность с появлением ORM-фреймворков.
Суть паттерна: Каждый объект объединяет в себе данные и поведение. Каждая сущность знает, как отображать содержимое хранилища на внутреннюю структуру. Часто поведение таких объектов ограничивают проверкой целостности и другими небольшими бизнес-правилами вроде валидации.
Плюсы:
✚ Быстрый старт разработки.
✚ Меньше boilerplate-кода по сравнению с Transactional Script.
✚ Логика находится близко к данным.
Минусы:
━ Смешивание отвественности — Domain-логика + логика сохранения/загрузки.
━ Трудно тестировать без хранилища данных.
━ Легко нарушить инварианты.
━ Сложно эволюционирует, так как завязана на данные.
Domain Model
Сердце DDD. Бизнес-логика инкапсулируется внутри объектов-моделей, которые отражают понятия предметной области. Сущности, объекты-значения — все работает совместно, чтобы отразить суть бизнеса в коде.
Суть паттерна: Абстрактная модель, которую обычно представляют в виде графа взаимосвязанных объектов. Данные и поведение неразрывно связаны, при изменении данных вызывается проверка бизнес-инвариантов, чтобы обеспечить целостность логики.
Плюсы:
✚ Высокая выразительность модели.
✚ Хорошая поддержка изменений.
✚ Защита бизнес-правил.
Минусы:
━ Высокий порог входа.
━ Требует высоких расходов на проектирование.
━ Избыточна для простых задач.
Какой паттерн и когда выбрать
Здесь нет серебряной пули. Ответ зависит от сложности домена и субдомена, с которым работаем в данный момент.
✔ Transactional Script → простые домены, CRUD, интеграционные сервисы.
✔ Active Record → умеренная сложность, быстрый time-to-market, стандартные правила.
✔ Domain Model → сложный бизнес, долгоживущая система, активная эволюция требований.
Важно понимать:
- DDD не обязывает вас всегда использовать Domain Model.
- Необходимо осознанно выбирать паттерн реализации модели, чтобы он соответствовал сложности домена и целям бизнеса.
Мой канал в telegram