Применение DDD. От моделей до EDM — поиск новых форм и архитектурные излишества

Под катом рассказ о самой авангардной форме архитектуры которую мне с коллегами удалось получить, как ещё больше можно развить этот подход.
DDD не на коленке, а за дорого ;)

В одной из прошлой статей в качестве метафоры я привёл пример архитекторов авангарда, которые открыли, а затем и вдохновили весь мир на смелые подходы, результаты которых вы можете видеть в крупных городах, взглянув на дома культуры, санатории, гаражи, общежития, крупные магазины, аэропорты, небоскрёбы. Вспышка этой новизны, отражавшей всемирные политические изменения, находили отражение в бетоне оказали значительное влияние на дальнейшую архитектуру зданий. Однако, всё не случилось одномоментно — это история становления новых форм от кубизма до конструктивизма.

В одной из прошлых статьей я уже рассказывал о ВХУТЕМАС, БАУХАУС. После их открытия, основным направление в этих художественных мастерских было коллективное взаимное обучение, анализ цвета, пространства, света, материалов. Далее начинался поиск конструкции — базовой составляющей архитектуры. Этот анализ был нужен, так как строительство на тот момент было очень ответственным и дорогим.

Тем же образом должны действовать инженеры и архитекторы в IT — точно понимать нюансы тех или иных архитектур, чтобы искать самые подходящие подходы для будущих решений. Далее представлены результаты моего исследования применимости предметно-ориентированного проектирования.

gceodmwsm1sgig-puhmjdpre9pq.png


Мой лучший монолит

Так получилось, что судьба инженера из глубинки часто связана с переделкой старых систем, на новый лад. Всегда бросалось в глаза, что некоторые подходы ограничивают больше чем другие, и не ясно как правильно. Конечно, абсолютизм спутник молодости. Несмотря на это, наверное я многое познал о разных формах монолитных решений. Был опыт с подключаемыми модулями, с миграцией логики (клиент, сервер приложений, база данных), опыт с сервис-ориентированными приложениями, опыт с системами в одной сети, в облаках, с нестабильными сетями и т.п. Всё это были решения, но наше мастерство ещё можно было оттачивать.

Для меня лично, ситуация поменялась несколько лет назад, когда я попал на интересную работу в компанию промышленного сектора с богатейшей предметкой. Нашей задачей было развить старую ИС, которая интегрирует остальные ИС и играет центральную роль в принятии управленческих решений. Как-то получилось, что мы здорово подначивали с коллегами друг-друга на плодотворную работу, на поиск как можно более лучшего решения — настолько, как казалось мне, прогрессивный проект, и стоит максимально осторожно выбирать решения. Так мы начали много читать, делать R’n'D и ретро, знакомится с предметной областью.

Наш продукт на первых этапах был интеграционной прослойкой между внешними операционным и нашей информационной системой (проприетарным ЭДО, разделённый монолит от которого были надежды отказаться). Это было монолитное приложение, с шаблоном предметной логики модуль таблицы, интеграцией через БД, внешними HTTP-интерфейсами. На самом деле, этот продукт был действительно продуктом, удовлетворял регулярно поступавшие пожелания от бизнеса.

ljwfelu3hhvynkia0umpqquidoy.png

Этот интеграционный продукт мы постарались максимально расслоить: слои сервисов, приложения, доступа к данным, инфраструктурный. Добавили интеграционных тестов, чтобы можно было проводить какое-то тестирование. По пути улучшения этого решения, мне кажется одна из лучших книг, что может попасться разработчикам — Адаптивный код. Мы очень много вынесли из неё, сделали много точек расширения архитектуры приложения.

Следующей вехой для меня стало посещение AgileDays 2019 — прообраза ArchDays. На этой конференции многое сложилось у меня в голове — продуктовая разработка, предметно-ориентированное проектирование, микросервисы. По большому счёту, с этого началась моя дорога евангелиста DDD. С этого же момента мы с коллегами, ознакомившись с темой, начали пытаться отчуждать функционал ЭДО в отдельное приложение. Это стало прообразом первых микросервисов, об устройстве которых я рассказывал ранее в статье о тактических паттернах.

Наши модули были построены на основе доменных моделей и шаблона событие как источник истины. Модели при этом сохранялись в реляционное хранилище.
f2602347b5c2e89cfc0d517b6ceca267.png

К сожалению, микросервисы в том продукте не прижились, не прижилось DDD. Простой как палка монолит, который не требует инфраструктуры вообще, победил. Так я сделал первый хороший продукт, который спустя время, вспоминаю в негативном окрасе.


Авангардная архитектура

После тайм скипа, я оказался архитектором стрима в одной из компаний, и передо мной были поставлены предельно амбициозные задачи. Опущу все перипетии почему у меня возникла возможность и необходимость перекраивать части ландшафта — обязательно ещё это сделаю в другой статье. Важнее, что от бизнеса были ожидания предельных изменений архитектуры с целью поддержки высокой нагрузки и высокой доступности, при этом инфраструктурные ограничения, якобы, можно было проигнорировать.

Также опущу рассказ про бесплодные попытки обойтись рефакторингом имеющихся приложений. По ряду причин, стало важным начать работу над микросервисами, которые будут максимально адаптивны к изменениям. Сформировался костяк команды, какое-то время мы потратили, по сути на то, чтобы получить наработки из прошлой жизни: перенос SeedWorks, библиотеки сквозной функциональности, сделать MVP микросервиса. Подробнее это база была описана в прошлой моей статье «Тактические паттерны»

Первым нашим продуктом оказалась программа лояльности, особенность его была в том, что это не сквозной продукт текущих линеек, а подавался клиентам как новое предложение — к нам могли прийти сотни тысяч, а могли миллионы клиентов — никто не мог точно сформулировать нефункциональные требования.

m9i_gggz5g0lvhf9bbipxzjt3xc.png

Это обстоятельство стало хорошим поводом для изменения первоначальной архитектуры. Мы внедрили CQRS: сделали отдельное хранилище событий и агрегатов в NoSQL, реализовали материализованные представления.

0cawfuij2nudbe4cb94pxn4se70.png

Практика показала, что неприятие такой архитектуры микросервисов очень значительно. Чаще всего используются слова «слишком дорого», но что если организации простой служит дороже? Это очень сложный микросервис, его нельзя написать за 2–3 дня. Но новую пользовательскую историю возможно выполнить за 1–10 дней, имею в виду эволюционный рефакторинг. Выбор сложного решения оправдан, если соблюдается инженерный принцип «усложняя упрощай». Участникам процесса нужно оторваться от конкретных реализаций, перенести фокус своего внимания на действительно важные вещи: бизнес-сценарии, модель, материализованные представления и UI, UX, API.

Все сомнения начали быстро рассеиваться, когда вместо расчётных пиковых 40 транзакций в секунду, мы начали получать минимально. Рост клиентской базы продукта не только оправдал выбранный подход, но создал запрос на дальнейшее развитие типового микросервиса, инфраструктуры. Так мы открыли для себя новую конструкцию.


CEQRS

По ряду причин, был соблазн декомпозировать обработчики на отдельные деплойменты в кубере, чтобы лучше понять где может быть проблема с перфомансом. Наблюдаемость сервисов только начинала развиваться и первые метрики были весьма бедные. В общем, было решено попробовать сделать третий деплоймент, который бы отвечал за исполнение событий.

4evuumvb8n9r7mzabaxw31mgtb8.png

Первое нагрузочное тестирование такой конфигурации с новой библиотекой батчевого чтения меня шокировало. Наш стенд состоял из двух экземпляров для исполнения команд и событий соответственно, каждом отмерили по 4 CPU.

u8ocj0iu52du2tkc5u-hoctmrko.png

В пересчёте удельной нагрузки на одно ядро, получаются следующие результаты. На вход из HTTP-интерфейса команды принимаются со скоростью около 3 Ktps. На второй диаграмме отражены события, которые сохраняются в базы данных, запускаются связанные обработчики, на скорости более 1 Ktps. Это результат без задействования горизонтального масштабирования. Этот результат был получен на основе JSON-сериализации событий при отправке сообщений доменных событий. Если применить MessagePack или Protobuf, результаты будут ещё лучше.

К сожалению, в клиентской реализации нашего продукта имелся фундаментальный изъян пользовательского опыта — возможность очень быстро в интерфейсе выполнить команду дважды. Когда количество пользователей начало исчисляться миллионами, мы на практике познакомились со следствиями одной из теорем распределённых систем.


Теорема PACELC

PACELC теорема — это расширение CAP теоремы, из которой следует, что в случае разделения сети мы выбираем между доступностью и согласованностью, но даже в отсутствии разделения нужно выбирать между низки задержками и согласованностью.

cffb1920546c77bd43a1b97fdd7a6cd4.jpg

Как я уже писал выше, для бизнеса была очень важна устойчивая работа сервисов. Возможность делить микросервисы на деплойменты, событие как источник истины, зоны доступности — всё это должно было нам помогать с тем, чтобы выдержать любую нагрузку горизонтальным масштабированием.

Новая деталь тут связана с тем, что точкой согласованности в распределённой топологии микрослужбы (CEQRS) становится агрегат, состояние которого перестало быть строго согласованным в рамках экземпляра. Это порождает то следствие, что две команды могут одновременно изменить агрегат, породив два доменных события, пока тот не обновился в базе данных. Пока речь идёт о миллисекундах, конфликт крайне маловероятен, однако под нагрузкой, когда речь идёт о секундах лага, конфликты неизбежны.

Решений тут много, но самое лучшее — координация распределённой транзакции. Т.е. накладывать на агрегат блокировку пока порождённое событие не изменит состояние агрегата. Такой способ оправдан, ведь правильно смоделированный агрегат отражает действия реального мира, и, зачастую, они почти всегда происходят не быстро. Есть и минус — миграция данных в этом случае затягивается, поэтому для миграции данных (например мажорное обновление, переиспользование событий другой микрослужбой), не следует разделять исполнение команд и событий в разные ноды.

s8nmzzichyl4njpmldxm4ptdzvu.png

В целом, применять такой подход нужно очень избирательно, там где речь заходит о деньгах клиентов. Во всех остальных случаях, следует просто следить за тем, чтобы данные как можно скорее обрабатывались, ресурсы не использовались на 100%. Так например, проблема в UX всплыла когда в пике нагрузок БД материализованных представлений была загружена на 100%, и, как оказалось, было недостаточно индексов. Если правильно выстроить UX, хорошо настроить наблюдаемость, следить за инфраструктурной частью, думаю такое решение излишне. В таком случае разумная альтернатива — периодическая регидротация доменных событий.


Балансировка нагрузки

Сочетание предметно-ориентированных микросервисов и EventSourcing шаблона ради возможности горизонтального масштабирования. Как известно, есть 3 оси горизонтального масштабирования: шардирование, зеркаллирование, функционально разделение.

36fb383a490993cf9720fe06389fd2c2.png

К сожалению, чтобы достичь управляемости микросервиса, нужно прорабатывать инфраструктуру. API Gateway должен позволять по правилу распределять входящий трафик, а IaaC облака предоставлять возможность управлять БД.

Чтобы правильно управлять микрослужбами, было принято решение привести их работу максимально к схематике бессервисных приложений.

55d62929a80667aae8ba256faf7ea605.png

Чтобы по свойствам масштабируемости приближаться к бессервисным приложениям без FaaS, наш типовой микросервис должен был несколько обрасти дополнительной инфраструктурной составляющей, что не совсем правильно с точки зрения CloudNative, но решало стоящие задачи. Формируемые инструменты, с помощью которых команда, SRE-инженер или ML-механизмы должны наиболее оптимально запустить конфигурацию микросервисов, динамически поправить их, оптимально распределить нагрузку.

dsm7alzzzxmvqfvzgkghk9xh3kc.png


EDM

Событийно-управляемые микросервисы — это по сути предметные микросервисы, поддерживающие шаблон Источник событий, реализующие принципы событийно-управляемых микросервисов. Всем предварительным условиям наши микрослужбы удовлетворяли, что открывает возможности к использованию столько мощного инструмента.

Проблемы обычных структур обмена данными
Предположим, команде нужно реализовать новый функционал, который касается данных, располагающихся в двух системах. Есть два способа реализовать функционал с помощью стандартных структур данных.

DDD MSA + EDA
Как бы поменялась интеграция, в случае если бы системы были построены на основе микросервисной архитектуры, с порождением доменных события?
xhcl53rson5j26pqtnx9hba895s.png

Потоковые механизмы передачи информации:


  • помогли бы команде продукта С собрать события предметной области, обработать их в — соответствии с потребностями продукта С.
  • Не возлагали бы нагрузку побочную на микросервисы;
  • Протестировать новый сервис до релиза, в случае ошибки переиграть поток событий.

Событийно-ориентированные микросервисы предполагают:


  • Использование событий как основное средство обмена информации;
  • Потоки событий обеспечивают единственный источник истины;
  • Потребители занимаются своим моделированием и выполняют свои запросы;
  • Обмен данными улучшается по всей организации;
  • Доступные данные поддерживают изменения в обмене информацией;

Выгоды от асинхронных EDM
ql18qzspx7m4dtns8fbxb4rqbny.png

Первичные выгоды:


  • Гранулярность;
  • Масштабируемость;
  • Технологическая гибкость;
  • Гибкость бизнес-требований;
  • Слабая сцепленность;
  • Поддержка непрерывной поставки;
  • Высокая тестопригодность.

Самый большой плюс


  • Для архитектуры предприятия и решений — горизонтальное развитие ландшафта, а значит снижение связанности, гибкость развития
  • Для бизнеса — снижение срости выхода решений, апробации гипотез, анализа данных

Сложности EDM


  1. Смена парадигмы. Вместо политики закрытости информации и ресурсов, нужна максимальная открытость, возможность быстро создавать новые решения.
  2. Инфраструктура. Должны быть возможности по настройке инфраструктуры микросервисов, брокеров событий, причём таким образом, чтобы это делали команду напрямую.
  3. Архитектура. Все команды должны заниматься микросервисами, другие арх.стили — техдолг. Это накладывает требования на квалификацию команд.
  4. Процессы. Процессы существенно меняются. Снижается роль аналитиков, архитекторов, повышается роль разработки. Процессы при этом должны выстроиться в продуктово-сервисную модель.


Самая перспективная форма

Мы для себя определились, что хотим двигаться в сторону EDM, заполнили свой бэклог нужными задачами, дополнили бэклог облака нужными задачами (зоны доступности, маршрутизация по правлам, брокер событий). Итогом измышлений стала такая схема:

iopvizlfx8cnd0mxvsx7riivfw8.png

В результате агрегаты становятся «точкой согласованности», чтобы все инварианты корректно проверялись, а обновление материализованных представлений и функции подписанные на доменные события, обновляются с гарантиями конечной согласованности. Такой подход открывает дополнительные возможности по миграции, по переносу функций обновления материализованных представлений в специализированные механизмы, есть возможность часть функциональности попробовать в FaaS. Таким образом, микрослужба существует в репозитории как цельное решение описывающее ограниченный контекст, но топология микрослужбы может меняться под конкретные требования.

Только представте себе, CN EDM ландшафт огромной организации — это завораживающая красота очень кое-что напоминающая.

8ddf0080279311c8ab36e971666eded0.jpg

Для чего вообще архитекторы авангарда экспериментировали с новыми формами и конструкциями? Кроме основного посыла качественного изменения политики и экономики у данного подхода были и другие причины. Такой архитектор — это не тот что сейчас (дизайнер) — он должен в архитектуру включить функцию, получить новые качества, как с точки зрения жителя, посетителя, строителя, эксплуатирующего здание. Так, например, началось применение каркасных зданий в не промышленной архитектуре, которые сейчас везде и всюду.

Применяя подходы DDD, CN я ставил себе целью получить обратную связь о возможностях такого способа декомпозиции, на практике увидеть границы применимости. Как у Николая Ладовского была лаборатория света, у меня была моя лаборатория DDD, CQRS, CloudNative, а самое главное есть последователи, которые будут и дальше развивать эти знания, нести в массы. И она дала свои результаты


Итоги применения


  1. Предметно-ориентированное проектирование наилучшим способом подходит для развивающихся продуктовых компаний. Эволюционный рефакторинг и гибкая разработка помогают формулировать продукт, менять процесс. С другой стороны, для таких модулей не работает догма про несколько дней разработки микросервиса. Качественный микросервис в первой версии требует достаточно много времени — 3–5 человеко-недель для среднего размера модели (3–7 бизнес-методов).
  2. Микрослужбы (а тем более облачные функции) требуют продуманной инфраструктуры. В идеале начинать работу над такими моделями только если есть планы на CN-облако, в котором есть доступные ИТ-услуги, автоматизации и т.п. Худший вариант, который можно видеть в банках — отдельная инфраструктура на «информационную систему». Надо отметитить, что в компании CN-ландшафт не может быть сопоставлен с понятием информационной системы. Если организация не разделяет подобного взгляда на определения, с высокой вероятностью, есть проблемы: с теорией и практикой, с перерасходованием бюджетов, с ветряными мельницами.
  3. Микросервисы с использованием DDD имеют органичную архитектуру только тогда, когда есть CQRS. При этом порождение доменных событий может не быть отчуждено в отдельное хранилище, но материализованные представления должны быть. Получается, что для ряда решений это очень мощный механизм, что может у разработчиков, аналитиков вызывать вопросы оправданности. В свою очередь это вызывает необходимость постоянно объяснять что это работа на перспективу, на снижение стоимости.
  4. Очень высокая податливость к масштабированию. Можно не только принять очень большую нагрузку, но и оптимизировать расход ресурсов под колебания нагрузки.
  5. Над подобными решениями должны работать квалифицированные профессионалы. Результаты такой работы — выдающиеся, а иначе всё может быть очень сложно. Очень помогает в данной работе митапы, читальные клубы (писал об этом ранее).
  6. Enterptise архитектура может похоронить эти подходы, насаждая, например, TOGAF, карты бизнес-возможностей. На этот комментарий многие триггернуться, но прошу вас не гневаться — об этом будет отдельная большая и аргументированная статья. Этот пункт я закончу тем, что если в организации не O-AA, сложности вы обязательно встретите.
  7. Дороговизна DDD — следствие неправильного применения. Подготовив облако, доработав процесс разработки, внедрив единое шасси можно свести расходы к сопоставимым с любыми другими решениями.


Архитектурные излишества

Глядя на схемы выше, описанные выводы, нетрудно видеть, что такие микросервисы — многолетний труд многих людей. Проходить этот путь в небольшой компании — это как строить метро в небольшом городе. Именно по этой причине DDD, CQRS, MSA чаще становятся не логичным архитектурным решением, а показателем развития команд, которые как умелые мастера своего дела, расширили круг своего мастерства. Это часто и становится причиной неуспеха и договизны подобных решений — по сути решения часто не завершённые, подход не масштабировать среди команд. Очень важно не заниматься ремесленничеством, а применять предметно-ориентированные микрослужбы когда есть или развиваются объективные обстоятельства к этому: сложная предметка, или высокие нагрузки и CloudNative в вашей организации. Т.е. ландшафт организации должен развиваться согласно модели зрелость CN:

1ef909e28e3fe87ead53f4af40c273ba.png

Чтобы подход стал массовым, он должен стать индустриальным — т.е. использование должно состоять из простых технологических операций, а для этого DDD+MSA должен получить форму технологии. И как авангардный архитектор, я бы хотел сделать такую технологию общедоступной. Это и станет завершающей стадией исследования этого подхода. Надеюсь через время вернуться с результатами нашей работы.

Спасибо вам за чтение! Огромное спасибо всем, кто в данном материале узнал совместную работу! Отдельное спасибо тем, кто делом помогал последние 5 лет прийти к таким результатам: Вячеслав С., Антон З., Родион Б. Алёна М., Святослав К. — именно благодаря вам получилось зайти так далеко! Спасибо всем кто применял предложенные архитектурные решения, итерацию за итерацией прорабатывал SeedWorks, RnD, продукты: Андрей С., Александр С., Семён К., Алексей П., Владимир К., Александр А. Никита Ч., Дмирий К., Александр В., Александр О., Александр А., Николай К., Василий С., Максим Ш., Анастасия В., Александр Д. Максим О., Алина К., Евгений М., Марина Г., Дмитрий К., Егор Г., Элина Б., Константин Т., Вадим Н., Максим М., Павел К., Владимир Б., Сергей К., Николай Т. Спасибо вам всем!


© Habrahabr.ru