Всем привет!
Этим постом завершается серия по паттерну Сага.
В предыдущем посте забыл упомянуть 3-й и 4-й способ реализации Саги.
Третий - если вы используете BPMN движок, например, Camunda, то он отлично подходит для оркестратора Саги. Более того, использовать BPMN как оркестратор - лучшая идея, чем использовать его как среду для low-code разработки. Ну не верю я в low-code, не сталкивался с работающими кейсами) Главные плюсы BPMN в данном - случае готовая state machine и визуализация Саги. К слову сама Camunda поставила этот use case на первое место в списке https://camunda.com/solutions/microservices-orchestration/ что как бы намекает. На всякий случай: Camunda - это самый распространенный BPMN движок, собственно движок - opensource, платить нужно только за UI консоль.
Аналогично - если вы уже используете Apache Camel - он тоже умеет в сагу, https://camel.apache.org/components/4.4.x/eips/saga-eip.html
Тут встает вопрос - стоит ли внедрять данные инструменты только ради Саги? Базовый ответ нет, идеальный кейс: если какой-то из этих компонент уже у вас используется - логично реализовать оркестрацию с его помощью. Я бы внедрял, если бы были какие-то еще плюсы от использования, кроме собственно реализации паттерна.
Еще важный момент при реализации оркестратора - stateless или statefull? Да, любая бизнес операция имеет как минимум ID и состояние, которые нужно хранить. Но необязательно это делать в классе Саги. Особенно используя event driven подход, можно просто передавать все не необходимые данные в событиях\командах. Напомню, при этом сохранение состояния операции в БД - это тоже событие. Плюс такого подхода - не нужно думать о букве D из ACID, т.е. персистентности, для данных, хранимых в оркестраторе. А где персистентность, там и кэширование, т.к. обращение к БД - дорого. И восстановление данных из БД при сбоях. Поэтому если вы все же решили хранить состояние операции в коде - я бы рекомендовал не изобретать велосипед, а воспользоваться готовым фреймворком. Два из них я уже упомянул выше, но они достаточно "тяжелые". Вот еще несколько, заточенных собственно под паттерн Сага и под DDD, который в общем-то тесно связан с сагой. Ведь если мы делим систему на ограниченный контексты, Bounded Context, то их данные лежат в разных БД, а следовательно возникает распределенная транзакция...
1) Axios https://docs.axoniq.io/reference-guide/v/3.1/part-ii-domain-logic/sagas
2) Eventuate Tram Saga https://eventuate.io/docs/manual/eventuate-tram/latest/getting-started-eventuate-tram-sagas.html
3) Seata https://www.seata.io/docs/user/mode/saga
Фреймворк помогает нам с:
а) персистентностью
б) кэшированием
в) созданием экземпляра саги для конкретной бизнес-операции
г) удобной работой с параметрами операции
При этом он не отменяет написания кода оркестрации и компенсирующих действий.
На этом пожалуй все.
Хотя нет. Остается вопрос - как же лучше реализовать Сагу? Ответ - лучше сделать свой ограниченный контекст = микросервис таким, чтобы Сага была не нужна)
А если серьезно.
1) постарайтесь использовать только локальные транзакции
2) если это не возможно, и у вас 2-4 шага - используйте хореографию
3) если шагов от 4+ и сервис создаётся с нуля - используйте оркестратор, для начала самописный, stateless event driven
4) у вас уже используется Camunda или Camel - делайте оркестратор на их основе
5) если вас нужен state - используйте фреймворки из последнего списка, например, Axios
6) если нужна сага и state machine - Camunda или Seata
#saga #microservices #ddd #patterns
Этим постом завершается серия по паттерну Сага.
В предыдущем посте забыл упомянуть 3-й и 4-й способ реализации Саги.
Третий - если вы используете BPMN движок, например, Camunda, то он отлично подходит для оркестратора Саги. Более того, использовать BPMN как оркестратор - лучшая идея, чем использовать его как среду для low-code разработки. Ну не верю я в low-code, не сталкивался с работающими кейсами) Главные плюсы BPMN в данном - случае готовая state machine и визуализация Саги. К слову сама Camunda поставила этот use case на первое место в списке https://camunda.com/solutions/microservices-orchestration/ что как бы намекает. На всякий случай: Camunda - это самый распространенный BPMN движок, собственно движок - opensource, платить нужно только за UI консоль.
Аналогично - если вы уже используете Apache Camel - он тоже умеет в сагу, https://camel.apache.org/components/4.4.x/eips/saga-eip.html
Тут встает вопрос - стоит ли внедрять данные инструменты только ради Саги? Базовый ответ нет, идеальный кейс: если какой-то из этих компонент уже у вас используется - логично реализовать оркестрацию с его помощью. Я бы внедрял, если бы были какие-то еще плюсы от использования, кроме собственно реализации паттерна.
Еще важный момент при реализации оркестратора - stateless или statefull? Да, любая бизнес операция имеет как минимум ID и состояние, которые нужно хранить. Но необязательно это делать в классе Саги. Особенно используя event driven подход, можно просто передавать все не необходимые данные в событиях\командах. Напомню, при этом сохранение состояния операции в БД - это тоже событие. Плюс такого подхода - не нужно думать о букве D из ACID, т.е. персистентности, для данных, хранимых в оркестраторе. А где персистентность, там и кэширование, т.к. обращение к БД - дорого. И восстановление данных из БД при сбоях. Поэтому если вы все же решили хранить состояние операции в коде - я бы рекомендовал не изобретать велосипед, а воспользоваться готовым фреймворком. Два из них я уже упомянул выше, но они достаточно "тяжелые". Вот еще несколько, заточенных собственно под паттерн Сага и под DDD, который в общем-то тесно связан с сагой. Ведь если мы делим систему на ограниченный контексты, Bounded Context, то их данные лежат в разных БД, а следовательно возникает распределенная транзакция...
1) Axios https://docs.axoniq.io/reference-guide/v/3.1/part-ii-domain-logic/sagas
2) Eventuate Tram Saga https://eventuate.io/docs/manual/eventuate-tram/latest/getting-started-eventuate-tram-sagas.html
3) Seata https://www.seata.io/docs/user/mode/saga
Фреймворк помогает нам с:
а) персистентностью
б) кэшированием
в) созданием экземпляра саги для конкретной бизнес-операции
г) удобной работой с параметрами операции
При этом он не отменяет написания кода оркестрации и компенсирующих действий.
На этом пожалуй все.
Хотя нет. Остается вопрос - как же лучше реализовать Сагу? Ответ - лучше сделать свой ограниченный контекст = микросервис таким, чтобы Сага была не нужна)
А если серьезно.
1) постарайтесь использовать только локальные транзакции
2) если это не возможно, и у вас 2-4 шага - используйте хореографию
3) если шагов от 4+ и сервис создаётся с нуля - используйте оркестратор, для начала самописный, stateless event driven
4) у вас уже используется Camunda или Camel - делайте оркестратор на их основе
5) если вас нужен state - используйте фреймворки из последнего списка, например, Axios
6) если нужна сага и state machine - Camunda или Seata
#saga #microservices #ddd #patterns
Camunda
Orchestrate Microservices | Camunda
Overcome challenges of microservices orchestration with Camunda. Get speed, scale, and resiliency without compromising microservice autonomy. Learn how.
🔥2
Всем привет!
Одна из моих любимых тем, вторая после читаемости кода, это скажем так "разработка - искусство компромиссов".
Редко встречаются ситуации, когда какой-то паттерн или принцип можно применять по формальным критериям всегда и везде. Более того, часто паттерны и принципы противоречат друг другу. Рассмотрим пример.
Есть такой паттерн, по моему опыту проведения интервью самый известный после синлетона - фабрика. А точнее абстрактная фабрика, именно такой паттерн описан в классике - Design Patterns: Elements of Reusable Object-Oriented Software. Суть его в том, что функция создания новых объектов выносится в отдельный класс. Создаваемые объекты являются наследниками какого-то базового класса или интерфейса. Классов фабрик может быть несколько, при этом каждая фабрика создает все (!) необходимые для проведения некой операции совместимые (!) между собой объекты. Вот более подробное описание с примером https://habr.com/ru/articles/465835/
Т.е. на первый взгляд паттерн работает четко в соответствии с принципом единственной ответственности (Single Responsibility) - создание отделено от доменного объекта, более того, для разных потребителей процесс создания объектов разнесен по разным фабрикам - ToyotaFactory и FordFactory из статьи выше.
А теперь изменим пример из статьи - будем создавать не разные типы кузовов автомобилей, а детали автомобиля. А деталей в авто подозреваю несколько тысяч... И список их более изменчивый, чем список типов кузовов. Т.е. по сути объединив в одном классе создание нескольких объектов мы уже заложили мину замедленного действия. Где находится грань между работой по Single Responsibility и его нарушением?
Базовый ответ был в первом абзаце - все зависит от бизнес-процесса. Но попробуем добавить конкретики.
Для начала можно вспомнить про лайфхак - можно оставить в фабрике один метод и передавать ему на вход Enum с типом создаваемого объекта.
class Factory {
SomeItem createSomeItem();
OtherItem createOtherItem();
}
vs
class Factory {
Item createItem(ItemType type);
}
Он немного упрощает добавление новых классов, т.к. не надо менять API фабрики, но в итоге приводит к тому же результату. Но дает нам подсказку: когда в Enum становится слишком много элементов - значит с фабрикой надо что-то делать.
Еще вариант - посмотреть, что скажет SonarQube. Он предлагает ограничиться 35 методами и 750 строками кода для одного класса. Как по мне - это много, я бы начинал делить фабрику на части раньше, при появлении 10-15 методов или по мере появления логических сущностей, позволяющих взять группу связанных методов из большой фабрики и вынести их в отдельную фабрику.
#patterns #solid #dev_compromises
Одна из моих любимых тем, вторая после читаемости кода, это скажем так "разработка - искусство компромиссов".
Редко встречаются ситуации, когда какой-то паттерн или принцип можно применять по формальным критериям всегда и везде. Более того, часто паттерны и принципы противоречат друг другу. Рассмотрим пример.
Есть такой паттерн, по моему опыту проведения интервью самый известный после синлетона - фабрика. А точнее абстрактная фабрика, именно такой паттерн описан в классике - Design Patterns: Elements of Reusable Object-Oriented Software. Суть его в том, что функция создания новых объектов выносится в отдельный класс. Создаваемые объекты являются наследниками какого-то базового класса или интерфейса. Классов фабрик может быть несколько, при этом каждая фабрика создает все (!) необходимые для проведения некой операции совместимые (!) между собой объекты. Вот более подробное описание с примером https://habr.com/ru/articles/465835/
Т.е. на первый взгляд паттерн работает четко в соответствии с принципом единственной ответственности (Single Responsibility) - создание отделено от доменного объекта, более того, для разных потребителей процесс создания объектов разнесен по разным фабрикам - ToyotaFactory и FordFactory из статьи выше.
А теперь изменим пример из статьи - будем создавать не разные типы кузовов автомобилей, а детали автомобиля. А деталей в авто подозреваю несколько тысяч... И список их более изменчивый, чем список типов кузовов. Т.е. по сути объединив в одном классе создание нескольких объектов мы уже заложили мину замедленного действия. Где находится грань между работой по Single Responsibility и его нарушением?
Базовый ответ был в первом абзаце - все зависит от бизнес-процесса. Но попробуем добавить конкретики.
Для начала можно вспомнить про лайфхак - можно оставить в фабрике один метод и передавать ему на вход Enum с типом создаваемого объекта.
class Factory {
SomeItem createSomeItem();
OtherItem createOtherItem();
}
vs
class Factory {
Item createItem(ItemType type);
}
Он немного упрощает добавление новых классов, т.к. не надо менять API фабрики, но в итоге приводит к тому же результату. Но дает нам подсказку: когда в Enum становится слишком много элементов - значит с фабрикой надо что-то делать.
Еще вариант - посмотреть, что скажет SonarQube. Он предлагает ограничиться 35 методами и 750 строками кода для одного класса. Как по мне - это много, я бы начинал делить фабрику на части раньше, при появлении 10-15 методов или по мере появления логических сущностей, позволяющих взять группу связанных методов из большой фабрики и вынести их в отдельную фабрику.
#patterns #solid #dev_compromises
Enterprise Craftsmanship
Domain model purity vs. domain model completeness (DDD Trilemma)
I’ve been meaning to write this article for a long time and, finally, here it is: the topic of domain model purity versus domain model completeness.
🔥1
Всем привет!
AI быстро развивается, интегрируется с традиционным ПО и было бы странно, если бы и для AI не появились ... свои паттерны)
Встречаем, от одного из лучших специалистов по паттернам: https://martinfowler.com/articles/gen-ai-patterns/
Маленький комментарий: да, AI паттерны могут показаться элементарными, но свою роль они выполняют - это некий язык, кубики, из которых строится архитектура приложения/корпоративная архитектура.
Еще хорошо написано про такую важную штуку как оценка (eval). Ведь модели не идемпотентны - могут менять свой ответ на одних и тех же входных данных. А значит традиционные практики тестирования не подходят. Модель тестирующая сама себя - прямой путь к скайнету) А вот если взять другую модель, а для страховки отдать результат на проверку человеком...
#llm #ai #testing #patterns
AI быстро развивается, интегрируется с традиционным ПО и было бы странно, если бы и для AI не появились ... свои паттерны)
Встречаем, от одного из лучших специалистов по паттернам: https://martinfowler.com/articles/gen-ai-patterns/
Маленький комментарий: да, AI паттерны могут показаться элементарными, но свою роль они выполняют - это некий язык, кубики, из которых строится архитектура приложения/корпоративная архитектура.
Еще хорошо написано про такую важную штуку как оценка (eval). Ведь модели не идемпотентны - могут менять свой ответ на одних и тех же входных данных. А значит традиционные практики тестирования не подходят. Модель тестирующая сама себя - прямой путь к скайнету) А вот если взять другую модель, а для страховки отдать результат на проверку человеком...
#llm #ai #testing #patterns
martinfowler.com
Emerging Patterns in Building GenAI Products
Patterns from our colleagues' work building with Generative AI
👍2
Всем привет!
Я уже подымал тему готовых архитектурных решений, а точнее их отсутствия в большинстве случаев https://t.me/javaKotlinDevOps/134
Хочу развернуть тему с другой стороны.
Стоит ли тратить силы на поиск целевого архитектурного решения?
Написал эту фразу, и понял, что не всем она может быть понятна) Расшифрую. В больших компаниях ака "кровавый enterprise" есть некий список разрешенных технологий и архитектурных принципов. Оформленный в виде техрадара, карты технологических стеков и сборника архитектурных стандартов. Это и есть целевая архитектура.
Так вот, беда с этим стандартами одна - со временем их становится слишком много, понять - как сделать правильно, чтобы работало годами без переделки - сложно. Нужно на это тратить время: для того, чтобы обойти всех заинтересованных архитекторов, смежные команды, и выработать целевое решение.
Так вот - а надо ли его искать? Несмотря на то, что ответ вроде бы очевиден, хотел бы подсветить несколько потенциальных проблем.
Затрачивая время на поиск и согласование целевого решения мы взамен хотим получить уверенность, что решение с нами останется "на века". Так ли это? Нет, не так. Во-первых мир меняется очень сильно, бизнес задачи меняются вместе с ним. Во-вторых технологии меняются еще сильнее. В-третьих - "кассандр" среди нас мало, и если есть несколько разрешенных технологий - угадать правильную сложно.
К чему это приводит? Мы потратили время на выбор и реализацию "целевки", а через год нам говорят - переделывайте. Отрицание, гнев, фрустрация. Обида на архитекторов. Причем даже если архитектор признает ошибку (и вообще эта ошибка была) - вряд ли он поможет переписать код. Обида на менеджеров - да они издеваются что ли, вечно меняют правила игры, вечная миграция... Желание сменить компанию...
Поэтому видится, что есть более надежный подход.
1) смириться с тем, что все течет, все меняется, и миграции будут всегда
2) искать целевые решение, но всегда держать в уме, что это целевое решение на данный момент
3) разделить весь код на ядро и инфраструктурный код. Ядро стараться писать на чистой Java \ Kotlin, с минимальным использованием фреймворков. Особенно, внутренних, которые еще не доказали свою стабильность. Внешние интеграции закрывать - предохранительный слой (anticorruption layer), шлюзы (gateway), адаптеры.
4) очень важно - уметь и хотеть быстро выпускать релизы, разбивать любые доработки на небольшие инкременты. Это можно сделать как улучшением качества проектирования, увеличением покрытия тестами и автотестами, так и различного рода договоренностями со смежниками, (не забываем, что мы в "кровавом enterprise")
Если вам показывался знакомым последний пункт - то да, это Agile. Или то самое снижение Lead Time (LT), о котором любят говорить менеджеры. И не только говорить) Но в данном случае они правы.
Еще пример - фондовый рынок и диверсификация. Диверсификация считается основным принципом разумного инвестора, и означает, что нельзя "класть все яйца в одну корзину". Т.е. нужно покупать разные классы активов: акции, облигации, вклады, кэш, золото, недвижимость. Причина - сложно угадать, что именно "выстрелит". В случае кода сложно конечно реализовать диверсификацию прямолинейно: часть данных хранить в PostgreSQL, а часть - в Oracle. Да и не нужно. Но предусмотреть возможность замены поставщика - нужно.
#agile #arch #arch_compromisses
Я уже подымал тему готовых архитектурных решений, а точнее их отсутствия в большинстве случаев https://t.me/javaKotlinDevOps/134
Хочу развернуть тему с другой стороны.
Стоит ли тратить силы на поиск целевого архитектурного решения?
Написал эту фразу, и понял, что не всем она может быть понятна) Расшифрую. В больших компаниях ака "кровавый enterprise" есть некий список разрешенных технологий и архитектурных принципов. Оформленный в виде техрадара, карты технологических стеков и сборника архитектурных стандартов. Это и есть целевая архитектура.
Так вот, беда с этим стандартами одна - со временем их становится слишком много, понять - как сделать правильно, чтобы работало годами без переделки - сложно. Нужно на это тратить время: для того, чтобы обойти всех заинтересованных архитекторов, смежные команды, и выработать целевое решение.
Так вот - а надо ли его искать? Несмотря на то, что ответ вроде бы очевиден, хотел бы подсветить несколько потенциальных проблем.
Затрачивая время на поиск и согласование целевого решения мы взамен хотим получить уверенность, что решение с нами останется "на века". Так ли это? Нет, не так. Во-первых мир меняется очень сильно, бизнес задачи меняются вместе с ним. Во-вторых технологии меняются еще сильнее. В-третьих - "кассандр" среди нас мало, и если есть несколько разрешенных технологий - угадать правильную сложно.
К чему это приводит? Мы потратили время на выбор и реализацию "целевки", а через год нам говорят - переделывайте. Отрицание, гнев, фрустрация. Обида на архитекторов. Причем даже если архитектор признает ошибку (и вообще эта ошибка была) - вряд ли он поможет переписать код. Обида на менеджеров - да они издеваются что ли, вечно меняют правила игры, вечная миграция... Желание сменить компанию...
Поэтому видится, что есть более надежный подход.
1) смириться с тем, что все течет, все меняется, и миграции будут всегда
2) искать целевые решение, но всегда держать в уме, что это целевое решение на данный момент
3) разделить весь код на ядро и инфраструктурный код. Ядро стараться писать на чистой Java \ Kotlin, с минимальным использованием фреймворков. Особенно, внутренних, которые еще не доказали свою стабильность. Внешние интеграции закрывать - предохранительный слой (anticorruption layer), шлюзы (gateway), адаптеры.
4) очень важно - уметь и хотеть быстро выпускать релизы, разбивать любые доработки на небольшие инкременты. Это можно сделать как улучшением качества проектирования, увеличением покрытия тестами и автотестами, так и различного рода договоренностями со смежниками, (не забываем, что мы в "кровавом enterprise")
Если вам показывался знакомым последний пункт - то да, это Agile. Или то самое снижение Lead Time (LT), о котором любят говорить менеджеры. И не только говорить) Но в данном случае они правы.
Еще пример - фондовый рынок и диверсификация. Диверсификация считается основным принципом разумного инвестора, и означает, что нельзя "класть все яйца в одну корзину". Т.е. нужно покупать разные классы активов: акции, облигации, вклады, кэш, золото, недвижимость. Причина - сложно угадать, что именно "выстрелит". В случае кода сложно конечно реализовать диверсификацию прямолинейно: часть данных хранить в PostgreSQL, а часть - в Oracle. Да и не нужно. Но предусмотреть возможность замены поставщика - нужно.
#agile #arch #arch_compromisses
Telegram
(java || kotlin) && devOps
Всем привет!
Выпил бокал пива и захотелось немного пофилософствовать)
У меня часть просят готовое решение какой-то проблемы. Это может быть способ интеграции, выбор места для хранения данных, языка программирования, способ разбиения проекта на микросервисы…
Выпил бокал пива и захотелось немного пофилософствовать)
У меня часть просят готовое решение какой-то проблемы. Это может быть способ интеграции, выбор места для хранения данных, языка программирования, способ разбиения проекта на микросервисы…
👍2