До этого момента мы рассматривали реактивные архитектуры на уровне системы. Реализация таких систем основана на обмене сообщениями или событиями. Средой для распространения событий или сообщений, как правило, выступают очереди, реже встречаются простые шины сообщений.
Разницу между шиной и очередью мы рассмотрели на предыдущем стриме, сегодня мы поговорим о том как реактивная архитектура реализуется на базе кода. Основной реализации реактивной архитектуры на уровне кода все так же являются сообщения, однако способы распространения сообщений не обязательно базируются на очередях.
Реактивные шаблоны, которые используются на уровне кода обычно реализуют подход на основе "потока данных", это позволяет создать независимую модульную или микромодульную реализацию. Наиболее удачно данный подход реализуется в системах "без состояния", где порядок обработки данных не имеет значения, но так же может использоваться в ситуации где порядок важен (например, используя шаблон SAGA).
Сегодня мы поговорим о стратегиях обработки ошибок на уровне кода, посмотрим что из себя представляют события и сообщения, поговорим про два конкретных шаблона Observer и Pub/Sub
Стратегия обработки ошибок строится на основе четырех допущений, которые должны быть обработаны в приложении:
Первые три пункта очевидны - при обработке ошибок необходимо обеспечить логическую изоляцию кода, который работает на разных уровнях абстракции. Отсюда же появляются архитектурные границы и распределение обязанностей. Во многом эти уровни обрабатываются используемыми библиотеками и фреймворками.
Четвертый пункт определяет требование к проектированию кода и по возможности контролируется тестами.
Основа стратегии - "устойчивость к сбоям" вместо "недопущение сбоев". Это значит, что мы проектируя код должны рассмотреть отдельную "не тупиковую" ветку поведения для сбойной ситуации. Здесь можно активно использовать null-object, а так же "пустые события", либо "откат транзакции".
Стратегия обработки ошибок на уровне кода должна дополнять стратегию обеспечения работоспособности системы в целом. Т.е. учитывая возможности мониторинга, дублирование (для обеспечения работоспособности при частичном отключении узлов системы).
Отдельные аспекты проектирования в целях обеспечения мониторинга и поиска корневой причины:
Программные:
Формальные:
В зависимости от того где выполняется код возможно использовать одну из двух моделей поведения программы:
Если программа функционирует в рамках одного процесса, то поведение программы может рассматриваться как набор событий, каждое из которых имеет связанный обработчик события. Таким образом программа может запускать обработчик события при наступлении события (обычно действий пользователя или результатов обработки других событий).
Событие характеризуется:
Данный подход легко реализуется в рамках модульного монолита, что позволяет добавить реактивность в уже готовые приложения.
В случае распределенных систем взаимодействие осуществляется на основе механизмов обмена сообщениями, при этом "события" преобразуются в соответствующие сообщения.
Сообщения характеризуются:
Взаимодействие на базе событий и сообщений может носить как синхронный (явно ожидаем подтверждения), так и асинхронный характер. Но события - это всегда жесткое зацепление.
Сообщения - универсальный способ организации взаимодействия между двумя элементами как на уровне кода, так и на уровне системы. Существует три варианта взаимодействия:
Вариант "точка - точка" создает сильное зацепление и препятствует масштабированию системы, поэтому более интересной является работа программы на основе потока данных.
Основные элементы потока данных:
Основные способы передачи:
Реактивное поведение - это поведение которое характеризуется наличием двух свойств системы:
В связи с большим количеством реализаций реактивной архитектуры на базе функционального программирования, возникает вопрос - как реализовать реактивную архитектуру на базе классических объектно ориентированных паттернов.
Рассмтрим три шаблона, которые могут быть доработаны до реактивной парадигмы:
Observer не может реализовать реактивное поведение через поток данных, однако может использоваться в случаях, когда реактивность достигается в системе с "жесткими" связями.
Часто задают вопрос в чем разница между Pub/Sub и Observer. Разница есть как между двумя этими шаблона в принципе, так и в реализации для реактивных приложений.
В контексте реактивной архитектуры нужно отметить, что Pub/Sub и Observer - работают с событийной архитектурой, а реактивное поведение достигается с помощью "сообщений", которые берутся из "потока данных".
Различия: