Часть 1. Принципы и приемы предметно ориентированного проектирования.
1. Что такое предметно ориентированное проектирование?
Предметно ориентированный подход это философия проектирования программного обеспечения (ПО). Это набор приемов и хороших
практик которые позволят получить поддерживаемый продукт с наименьшей сложностью на выходе. Это не набор шаблонов и не фреймворк.
Предметная область это деятельность для которой создаётся ПО (ecom, банковская деятельность, медицина).
Важно чтобы разработчики хорошо понимали предметную область. Для обуздания
сложности DDD использует некоторые стратегические и тактические шаблоны.
В DDD выделяются два вида шаблонов:
-
Стратегические шаблоны: дистилляция предметной области, создание модели для решения задач предметной области,
использование языка для совместной работы над моделями, изоляция модели, понимание отношений между контекстами.
-
Тактические шаблоны DDD - это приемы позволяющие создавать эффективные модели внутри контекста. По сути сюда относятся
паттерны проектирования описанные у Фаулера.
Суть DDD в стратегических шаблонах. Все они разобраны в следующих главах.
2. Дистилляция предметной области задачи
Понять предметную область это одна из важнейших задач. Эти знания можно получить только через совместную работу с людьми
знающими ее от и то.
Сложные предметные области содержат очень много информации. Переработка знаний это процессы выделения важной информации
которая связана с сутью задачи.
Единый язык (ubiquitous language) это результат переработки знаний. Этот язык должен фигурировать в программном коде.
Бизнес аналитики помогают в процессе переработки знаний и описывают то,
что должно быть на входе и выходе продукта. Но должно быть прямое общение между командой разработки
и людьми разбирающимися в предметной области, экспертами экспертов.
В главе описаны разные шаблоны переработки знаний и советы, перечислю лишь некоторые,
остальные либо требуют достаточного сильного погружения или очевидны. Для получения
полной информации лучше обратится к источнику.
- Сосредоточьтесь на интересных темах. Начинайте проработку с тех тем что всех волнуют.
- Начните изучение новой предметной области с вариантов использования. Поработайте с бизнесом, поймите
какие шаги они предпринимают для получения результата.
- Продуктивные вопросы: в чем польза для бизнеса, что будет если система не будет создана?
- Не спешите именовать понятия в модели. Пока нет точного понимания роли модели дайте ей абстрактное имя, например
BlueModel, явное имя направляет мысли в определенное русло. Избегайте моделей вида XXXService, XXXManager.
- Разработка через реализацию поведения (BDD). Сценарии в BDD описываются при помощи вопросов: дано, если, тогда.
- Быстрое прототипирование. Начните с прототипов экранов — это понятно пользователям.
3. Концентрация на смысловом ядре
Некоторые части системы важнее других. На более важные части следует тратить больше сил.
Предметную область следует разделить на подобласти:
- Смысловое ядро (core domain) - то, что служит причиной создания софта, а не его покупки, главное на чем должно быть
сосредоточено внимание команды, ключевая область для успеха приложения.
- Поддерживающие области (supporting domains)- обеспечивают поддержку смыслового ядра, должно работать, но не требовать особого внимания.
- Неспециализированные области (generic domains)- типовые подобласти, которые есть в любых системах, например,
сервис отправки SMS. Для этих областей лучше использовать готовое ПО.
Еще два важные идеи озвученные в этой главе:
- Следует выделять больше внимания ясности границ, а не совершенству модели.
- Подобласти должны создаваться с прицелом не на повторное использование, а на замену.
4. Проектирование на основе модели
Проектирование на основе модели (Model Driven Design) это подход, который отличается от традиционного подхода, когда
на основании выявленных требований
бизнес-аналитики создают аналитическую модель, часто представленную в виде UML диаграммы, а затем на основании данной
модели программисты создают код. Этот подход плох тем, что при практической реализации
часто обнаруживаются нестыковки между аналитической моделью и реальностью. Это, в свою очередь, приводит к
рассинхронизации аналитической
модели программного кода.
MDD предполагает одновременное создание аналитической модели и программной модели. Программная модель это по сути отражение
аналитической модели в коде.
Предметная модель = аналитическая модель + программная модель.
Создание эффективной предметной модели это основа DDD. Для того чтобы успешно создать программную модель
следуют держать в голове некоторые ключевые пункты:
- не забывать единый язык — термины используемые в бизнесе, аналитической модели и программной модели должны совпадать
- избегать абстракций
- воплощать модель в коде раньше и чаще
- жертвуйте точностью, если она стоит на пути удобной модели
- сосредоточьтесь на важных аспектах бизнеса, игнорируйте в модели рутину типа CRUD операций.
5. Шаблоны реализации предметной области
Здесь рассматриваются паттерны ООП которые подходят для разработки MDD. Я не буду описывать
каждый шаблоны, просто перечислю названия паттернов:
- Domain Model (Предметная модель)
- Transaction script (Сценарий транзакции)
- Table Module (Модуль таблицы)
- Active Record (Активная модель)
- Anemic Domain Model (Анемичная предметная область)
6. Обеспечение целостности предметной области при помощи ограниченных контекстов.
Важно защитить целостность каждой модели, и обозначить границы ответственности в коде. Это делается путем связывания
модели с ограниченным контекстом (bounded context). Часто похожие понятия из одной области ошибочно связываются
с похожими понятиями в другой области, что ведет к запутанности и увеличению сложности модели.
Например, понятие продукт представляет собой несколько предметных понятий, но часто моделируется как единое понятие.
Лучше создать для каждого контекста (закупки, продажа, логистика) отдельную модель продукта. Да, программный код может
дублироваться в этом случае, но плюсов у такого подхода гораздо больше.
Ограниченный контекст ограничивает ответственность модели. Важно изолировать модель в границах своего контекста.
Не нужно путать ограниченный контекст (bounded context) с областями (domains). Области часто отражают организационную
структуру предприятия, а ограниченный контекст относится к технической реализации и устанавливает границы между
моделями в коде.
7. Карты контекстов.
В больших и сложных приложениях границы контекстов над которыми трудятся разные группы разработчиков могут быть
размыты по ряду причин: плохая коммуникация между группами, легаси, не четкое определение предметных областей.
Для того чтобы не допустить смешения контекстов можно составить карту контекстов — диаграмму на которой отображены
контексты задействованные в разработке. Карта контекстов должна отражать реальное состояние, а не идеализированное
будущее.
В этой же главе авторы определяют шаблоны отношений между контекстами:
- Предохранительный слой
- Общее ядро
- Служба с открытым протоколом
- Отдельное существование
И между командами:
- вышестоящий/нижестоящий
- заказчик/поставщик
- конформист
Данные связи отображаются на диаграмме контекстов. Карта контекста выявляет области хаоса и неразберихи и
помогает в поисках смыслового ядра
8. Архитектура приложения.
Архитектура DDD приложения это многоуровневая архитектура состоящая из:
- предметного уровня — абстракция предметной области и основа приложения.
- прикладного уровня — сценарии использования приложения, фасад для предметного уровня.
- других уровней — решение чисто технических задач (инфраструктурный, UI итд)
Само приложение можно разделить на контексты. В идеале каждый контекст должен иметь свою базу данных.
Привет микросервисам.
9. Типичные проблемы команд, начинающих применять предметно ориентированное проектирование
Группы не до конца понимающие философию DDD часто сталкиваются в своей работе со следующими проблемами:
- Сосредоточенность на тактических шаблонах вместо стратегических. Код не является узким местом, гораздо важнее
изучать и осваивать предметную область вдали от клавиатуры.
- Использование одинаковой архитектуры для разных контекстов. Для разных контекстов можно применять разные архитектуры,
единственное требование предметная логика должна отделяться от технического кода.
- Идеализация тактических шаблонов.
- Ошибочное принятие тактических шаблонов за ценность DDD, гораздо важнее сотрудничество, единый язык, ограниченные контексты.
- Сосредоточенность на коде, а не на принципах. Воплощение принципов ДДД происходит за чашкой кофе, за доской
- Недопонимание важности контекста.
- Большие затраты времени на то, что не представляется важным. Нужно уметь признавать что не все системы являются важными.
Не нужно применять DDD к тому, что является не важным. DDD подходит не всегда, для получения выгоды нужно чтобы система
имела сложное смысловое ядро. Если система не отличается сложностью и не подвержена частым изменениям, то DDD тут не место.
- Получение запутанного кода из-за недопонимания важности контекста. Одна модель не может решить все задачи, модели следует
разделять по контекстам.
- Неудачи в создании общего языка. Без него модели конструируются на основе абстракций и технического языка. В этом случае
возникает мискоммуникация между бизнесом и разработкой.
- Большие затраты времени на то, что не важно. Разработчики должны понимать основную причину создания
нового ПО, вместо сборки решения из существующих компонентов.
10. Применение принципов, приемов и шаблонов DDD
DDD Подходит не везде, вот условия при которых можно примерять DDD:
- Есть команда опытных и мотивированных разработчиков
- Есть нетривиальная предметная область
- Есть возможность общения со специалистами разделяющими веру в проект
- Вы следуете методологии итерационной разработки.
Этапы подготовки проекта:
- Понимание замысла: зачем новый продукт, какое значение для предприятия имеет этот продукт,
критерии успеха, чем отличается от старого?
- Определение требуемой функциональности: BDD, разбитие на контексты.
- Понимание действительной картины, создание карту контекстов.
- Моделирование решения: все задачи имеют разную сложность поэтому выбирайте подходящий подход, привлекайте экспертов, для реализации
используйте конкретные (реальные) сценарии, отбросьте первую модель и создайте вторую, сохраняйте решение простым, а код скучным.
- Исследования и эксперименты: не привязывайтесь к модели первой итерации, реорганизуйте модель с появлением новых знаний.
- Превращение явного в неявное: не оставляйте в коде неявную логику, выносите ее в код с явным названием класса/функции,
внимательно подходите к наименованию сущностей в коде.