Как стать автором
Обновить

Комментарии 14

Такой подход позволяет нам сильно уменьшить связность нашей системы и упростить её поддержку и расширяемость.

Связность не меняется.

Что в REST надо знать, в какое API и в каком виде данные отправляются, что в событийной модели надо знать, в какую очередь и в каком виде данные отправляются.
От изменения способа доставки данных связность не поменяется.

В Event-driven добавляется 3й элемент - очередь сообщений, что наоборот, усложняет схему работы (потому как появляется дополнительная точка отказа).

P.S. а в чем картинки рисовались?

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

P.S. Картинки рисовал от руки на айпаде, в приложении Concepts

А чем это отличается от единой точки входа - API компонента B?
Формат данных согласовывается одинаково, очереди/пути для отправки данных - аналогично, подлежат согласованию между сервисами. Связность остается той же.

Или мы рассматриваем ситуацию, что у компонента B свое API для A и С, но при переходе на событийную модель упрощается протокол взаимодейсвия и появляется общая очередь?
Тогда уменьшение связности - заслуга рефакторинга под более простой протокол, а не перехода на событийную модель.

Я могу согласиться, что в событийной модели связность может быть слабее. Но это только потому, что протокол взаимодействия, как правило, значительно проще. В событийном модели организация сложного протокола взаимодействия требует значительно больших усилий от разработчика (в отличии от REST или RPC подходов).

Но сама по себе событийная модель не уменьшает связность.

P.S. спасибо, Concepts возьму на заметку.

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

Я про это и говорю. Изменился протокол взаимодействия, он стал проще. Проще протокол - меньше связность.

Очередь тут вторична. С тем же успехом можно без очереди жить. Сделать REST API которое все входящие ордера просто обрабатывает.

А если имеется сервис с этим же API, который все входящие ордера из API в очередь добавляет, а из очереди уже другой сервис их обрабатывает?

Для внешнего наблюдателя эти 2 сервиса (что с обработкой сразу, что с очередью) будут полностью идентичны. И связность они будут давать полностью идентичную.
Просто потому, что применение очереди на связность не влияет - это внутренний нюанс реализации сервиса и/или связи между сервисами.

Не совсем так и не в протоколе дело, а в том, что один модуль стал меньше знать о другом модуле.
Самое банальное, как создать класс. Это другая зона ответственности. Да, есть паттерны, которые помогают решить эту проблему: DI или Фабрика.
Но опять же мы навязываем знание о потребителе поставщику данных.

Утрированно: уменьшая связанность, мы уменьшаем у поставщика данных знания, кто эти данные будет использовать.

Да, меньше связность - это про "один модуль стал о другом знать меньше". Это я и называю "упростился протокол взаимодействия модулей".

Но сам процесс "стал знать меньше" - это не потому, что на событийную модель перешли, а потому что рефакторинг/переделки были, которые и уменьшили связность модулей, чтобы взаимодействие лучше на событийную модель "ложилось".

Но такие переделки вполне применимы и при REST API (и любом другом API). И дадут ничуть не худшее уменьшение связности.

упростился протокол взаимодействия модулей

Что может быть проще прямого вызова?

В Event-driven добавляется 3й элемент - очередь сообщений, что наоборот, усложняет схему работы

Так упрощается или усложняется?

Но сам процесс "стал знать меньше" - это не потому, что на событийную модель перешли, а потому что рефакторинг/переделки были, которые и уменьшили связность модулей, чтобы взаимодействие лучше на событийную модель "ложилось".

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

Далее, при реализации требования мы добавляем в А вызов Б. Теперь А зависит от Б - то есть связанность выросла. Точно таким же образом мы поступаем с В, Г, Д и тд - связанность растёт и растет.

Теперь возвращаемся к исходному тезису

Такой подход позволяет нам сильно уменьшить связанность нашей системы и упростить её поддержку и расширяемость.

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

Автор не заявляет что это единственный подход. А то, что для внесения изменений в архитектуру необходим рефакторинг - самоочевидно.

Я исхожу из того, что автор говорит именно про связность, а не про связанность.
Связанность - согласен, уменьшается, потому что остается, в большинстве случаев, только сервис и сервер очереди.

И основной мой посыл был в том, что от перехода на очереди именно связность не поменяется. Сервисы как оперировали согласованными форматами данных в согласованных местах, так и продолжили оперировать согласованными форматами данных в согласованных местах.

P.S. Бизнес требования могут быть по разному реализованы, так что само по себе бизнес-требование может ничего и не увеличивает, а вот его реализация - вполне себе.

Связность - это о внутренних связях модуля, из контекста (и статьи и ваших сообщений) ясно, что речь идёт не об этом. К тому же в отличии от связанности её обычно стараются держать высокой.

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

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

Прошу прощения, невнимательно прочитал.
Я говорю про связность, которую и упоминает автор, а не про связанность.

Идея неплохая, но реализция хромает.

Есть такой прекрасный паттерн как Saga. Бывает она оркестрируемая, а бывает хореографией. Если очень супер-грубо говоря, то мы должны иметь не только точки входа и выполнения какой-то операции, но и алгоритм компенсирующих транзакций. А так же, каждый модуль должен быть полностью автономным по отношению к другим. ( разве что общение через контракты в виде публичных интерфейсов и DTO ).

Но тут, перед началом внедрения подобных подходов, нужно прочитать про принципы DDD.
Тогда будет понятно как реализовать действительно изолированные модули.

Потом можно изучить как работает EventSourcing. Кстати, подробная информауция есть на microservices.io. Жаль, примерчики там какие-себе.

Грег Янг, кстати, неплохую макулатуру написал на эту статью.

Кстати, можно , конечно, реализовывать свой велосипед на 3х вышепересисленных мессаж-брокерах,
А можно заюзать что-то подобное на, скажем, Temporal (начинался с Uber Cadence) в связке с Roadrunner. Попробуйте глянуть, забудете что такое эти все SQS, Rabbit, etc...

P.S. Оценил, что упомянули про идемпотентность. действительно полезная штука, особенно когда случайно от магазина электроники получаешь 100см подряд о том, что пора воспольщоваться скидкой на <N> продукты ))

Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации

Истории