17. В общем про DDD
10
Domain-driven Design
(Предметно-ориентированное проектирование)
2003, теория 2013, практика
Эрик Эванс Вон Вернон
18. В общем про DDD
11
Единый язык
(Ubiquitous language)
19. В общем про DDD
12
Домен, поддомены, контексты
20. В общем про DDD
13
Гексагональная архитектура
(Архитектура портов и адаптеров)
MQ Service
Aggregate
Root
RESTPort
MQ
Port
Application
Service
Command
Transport
Business Method
23. CQRS
15
Command Query Responsibility Segregation
Command
• Контейнер для данных,
представляющих изменения
• Неизменяемая (Immutable)
• Не возвращает данных
• Может быть версионирована
24. CQRS
15
Command Query Responsibility Segregation
Command
• Контейнер для данных,
представляющих изменения
• Неизменяемая (Immutable)
• Не возвращает данных
• Может быть версионирована
Query
• Возвращает подготовленные
данные
• Без побочных эффектов
• Может быть версионирован
25. CQRS
15
Command Query Responsibility Segregation
Command
• Контейнер для данных,
представляющих изменения
• Неизменяемая (Immutable)
• Не возвращает данных
• Может быть версионирована
Query
• Возвращает подготовленные
данные
• Без побочных эффектов
• Может быть версионирован
Message
29. CQRS
17
CQRS vs CRUD
CQRS CRUD
Бизнес логика сервер клиент
Команды ∞ 3
Запросы
оптимизированный
результат
подготовка каждого
результат
Делимость «из коробки» проблематично
33. Event Sourcing
19
Сущность
id Состояние Состояние Состояние Состояние Состояние
…
…
Реляционная
таблица
id Состояние
…
…
Документ
id
v1 Изменение
v2 Изменение
v3 Изменение
…
…
Event store
Eventstream
}
50. Как это всё работает вместе
33
Пример:
Регистрация пользователя:
• Пользователь должен иметь возможность
зарегистрироваться на сайте
• Пользователь должен иметь возможность
сменить контактные данные (email)
• Оператор должен активировать пользователя
после проверки его документов
52. Как это всё работает вместе
35
Event stream
CustomerWasRegisteredV1
CustomerEmailWasChangedV1
CustomerWasActivatedV1
CustomerEmailWasChangedV1
Время
53. Как это всё работает вместе
35
Event stream
CustomerWasRegisteredV1
CustomerEmailWasChangedV1
CustomerWasActivatedV1
CustomerEmailWasChangedV1
…
CustomerEmailWasChangedV2
Время
00:03:00
С:
ТЕМА: Применение CQRS и EventSourcing в DDD-проекте
Опишем ключевые концепции DDD, CQRS, ES
Роскажем как это все работает у нас
И поделимся теми выводами к которым мы пришли применяя эти подходы в течении пары лет
И: вначале пару слов о нашей компании и нашем проекте
И: 6-Системс существует в У с 2012
(КЛИК)
она являеться доч компанией Немецкой корпорации Сикст
которая занимаеться бизнесом проката авто с 1912 г
(КЛИК)
В 2011 они договорились с другой большой Немецкой BMW
о том что выходят на рынок с инновационным продуктом
(КЛИК)
С: этот продукт получил название DriveNow, бизнес модель Кар Шаринг
(КЛИК)
С: В теч 3х лет с нескольких городов Герм до нескольких стран в
Зап.Европе (Англия, Дания, Швеция, Австрия, Италия)
Реклама старта Копенгаген, 400 еле ктромобилей BMW i3
И:
(КЛИК)
Сроки - полгода, и в течении 3х мес + 2 конкурента
(КЛИК)
С: напомню продукт писался быстро
пытались выкатить больше фич и функционала
Качественное Армирование монолита было произведено сквозными связями через все слои системы.
И взаимозависимостью между модулями и компонетами системы.
00:08:00
С: в один из дней настал решающий момент когда мы сказали «Хватит»
новые подходы, методики и инструменты
И: (КЛИК)
в качестве целевой архитектуры был выбран СОА, код и рание писался на PHP
Асинхронного обмена сообще RMQ, облачном Сервере
С: Наверняка многие из вас знают что обозначает эта аббревиатура.
(NEXT)
С: очень интересно кто пробовал DDD в своих проектах?
—
Для тех кто захочет ознакомиться с этим вопросом поближе рекомендуем книги
2 книги Синяя и Красная книга
Эрик Эванс - изобретателя DDD
Вон Вернона - человека широко известного в сообществе DDD
И:
Предметная ориентрованность в ДДД ставит своей целью приблизить розработчиков к бизнесу
добиться чтобы и Бизнес аналитик и Программист разговаривали на одном языке
Пример: простой пример в коде нашего продукта сущность как Резервирование
Бизнес: поездка, сервисный ордер и перепарковка
И нам всегда приходилось переводить
Приводило к сложному коду кучи проверок и драматически увеличивало регрисионные тесты
C: Домен - та предметная область где работает наш бизнес
Поддомены - система автомобилей, поездок, управления пользователями, потщета и выставления счетов
Домен и Поддомены по ДДД это проблематик спейс
Но для решения этих проблем существует Солюшен спейс
Ограниченные Контекст - для СОА являються сервисами, для микро-серв арх - набор микросервисов
Юбикутис ленгвич - являеться ограничением этого контекста
Пример: Пользователь в системе ЦРМ и Пользователе/Водитель в Системе учета поездок
Мы приняли для себя СОА, где каждый ограниченный контекст реализуеться одним сервисом
00:16:00
И: что из себя представляет архитектура нашего сервиса.
В ДДД широко роспространено использование Хекс Архитектуры, иногда называют Луковой или Арх Порт и Адапт
Внешний слой этой арх образует Порты.
Порты и Адаптеры образуют Анти корапшин леер.
Переводит с языка внешних сервисов в язык нашего сервиса.
В результате перевода появляеться Команда которая обабатываеться АппСервисом
Портов может быть много а Команда может быть таже
Есть авторы которые щитаю БД такой же Порт но Фавлер так не щитает и Мы с ним согластны
И:
Бизнес метод Агрегата вызываеться на Основании какой-то Команды.
Команда плавно подводит нас к следующему паттерну который широко используеться в ДДД проектах CQRS
С: все операции в нашей системе деляться на 2 типа в зависимости от направления потока данных
(КЛИК)
Команды - глаголы в императивной форме
WriteModel
(КЛИК)
2й тип это Запросы - возвращают данные, с ними могут передаваться фильтры НО они не изменяют состояние системмы
Результаты, которые возвращаються запросом отдельно подготовлены и храняться в хранилище называемом ReadModel
(КЛИК)
Message
При этом очевидно что неотемлимою частю такого подхода являеться Синхронизация данных из WriteModel -> ReadModel
И: Немного о сообщениях
Передача сообщений
Любые изменения Врайт Модели продуцируют сообщения которые
через Шину Сообщений попадают в Рид Модель и актуализируют ее.
Обратите внимание на несколко Рид Моделей которые могут изменяться по изменения одной Врайт Модели
Достоинством Асинхронной связи - никак не тормозит обновление ВрайтМодели и мы можем даже поместить РидМодель в другой сервис
Внутри РидМодели - данные преобразовываються, производяться нужные росчеты и храняться в подготовленном для чтения виде
——————————
С: Как что-то назвать и инвалидация кэша.
1 -юбикутис ланг, 2 - обновление РидМод ОТЛИЧНЫЙ мех решения 2й проблемы
00:22:00
И: CQRS против CRUD
В этой табличке мы попробовали справнить эти две альтернативы.
по табличке
Делимость - CQRS возможность розделить розличные процессы: выполнение бизнес логики и чтение
На следующих выборах голосуйте ЗА CQRS!
C:
С:
При Event Sourcing мы храним события/измения. У нас нет хранения Состояния.
Для того чтобы определить состояние объекта нам нужно последовательно применить все изменения которые с ним произошли.
На кажудю сущности существует EventStore.
В котором храняться истории изменений для каждого объекта - EventStream-ы
EventStream - представляет хронологически упорядоченный набор изменений нашего объекта.
В результате у нас есть Машина Времени
00:28:00
С: такую историю можно представить себе в виде цепочки изменений или ревизий.
Эту картинку мы взяли из другой книги и там была Такая картинка.
(КЛИК)
И эту книгу вы тоже наверняка все читали.
(КЛИК)
Хранение событий в Ивент Стриме напоминает мне то как Гит хранит у себя историю изменений файлов, без бранчей но идея та же.
И: Степа, давай попробуем обяснить как это работает вместе =)
И: это всем знакомая картина есть REST Api и Controller
И: на наш Controller приходит запрос из которого формируеться Command-а
И: и тут начинается жизненный цикл обработки Команды
Она попадает в Команд Хендлер который в нашем случае и в терминах ДДД являеться Апликейшин Сервисом
И инкапсулирует взаимодействие с Агригейт Рутом
И: АС Восстанавливает актуальное состояние АР по Ивент стриму
И: по этой Команде АС вызывает соответствующий бизнес метод АР
В результате чего изменяеться его состояние
И: в результате этих изменений у мы получаем набор Домейн Ивенто/Сообщений
которые АС дополняет до существующего ИвентСтрима и сохраняет в ИвентСторе
И: На этом жизненный цикл команды заканчивается
Хочу обратить внимание что мы не вовращаем никаких данных.
В случае ошибки выбрасываеться Ексепшин и котролер возвращает соответствующий HTTP статус
С:
из очереди Сообщений события попадают Подписчикам
С:
эти Подписчики превращают Сообщения
обратно в Домен Ивент
и передают Прожекторам
Внутри Прожектора
происходит весь подсчет, вся обработка данных
для того чтобы подготовить Рид Модель
Рид Модель становится актуальной
С:
Вернемся к нашему REST API
внутри есть контроллеры которые обрабатывают GET запросы
С:
В ответ на эти запросы данные из Рид Модели попадают в АС
И в виде DataTransferObject возвращаются в Контроллер
Пару моментов на которые хочеться обратить внимание
На каждый запрос есть своя Рид Модель
NO ORM
Фактически DTO = [ {}, {} ]
И:
Если взять стандартную комбинацию RESTFull - CRUD
то первые 2 пункта хорошо вкладывають в эту комбинацию
то для реализации последнее люди придумывают розличные варианты которые нарушают чистоту решения
Например договариваються добавлять команду после ресурса в ссылках
Для CQRS команда это естественное поведение.
С ES мы навсегда сохраним знание о том изменении которое произошло
С:
Мы надеемся все любят читать Сиквенс Диаграммы
Здесь представлен кейс «Регистрация пользоватиля»
ВОСТАНАВЛИВАЕТ
С:
(КЛИК) SOA сильно помогла нам увеличить скорость подключения новых Городов и Стран
(КЛИК) Рид Модели и Асинхронные процессы
(КЛИК) разнесение бизнес логики на разные сервера
(КЛИК) с помощью Машины Времени. Кто что делал и Кто в этом виноват
(КЛИК) BDD в сочитании с Мутационным тестирование позволили нам покрыть 94% бизнес логики
И:
а вот чем нам пришлось заплатить за такое счастье
(КЛИК) ValueObject, ReadModel дополнительные обертки в виде Command. Код получаеться чистый но его много. Решаеться Фреймворками и Библиотеками
(КЛИК) Хранение событий и их обработки