The basics of the reactive

Posted:

Reactive manifesto

Начать изучение reactive programming как подхода к программированию, конечно же, стоит с reactive manifesto. Этот документ объясняет базовые концепции, которые лежат в основе реактивного программирования. Или даже лучше сказать, свойства системы, которые хочется достичь.

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

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

Мы хотим, как утверждается в манифесте, строить системы, обладающие свойствами Отзывчивости (Responsive), Упругости (Resilient), Эластичности (Elastic) и Управления с помощью сообщений (Message Driven). Собственно, такие системы и есть Reactive systems.

Рассмотрим вкратце каждое свойство:

  • Responsive: система отвечает очень быстро, и это время ответа, находясь в определенных границах, не выходит за верхний предел. Тем самым достигается постоянное качество обслуживания (quality of service)

  • Resilient: система отвечает даже в момент сбоя. Это достигается за счет репликации, локальности, изоляции и делегирования. Сбои локализуются внутри компонента, тем самым он может быть восстановлен отдельно, не влияя на систему в целом. Восстановлением занимается отдельный компонент

  • Elastic: система отвечает под изменяющейся нагрузкой. Реактивные системы могут увеличивать или уменьшать свои ресурсы. Дизайн системы построен так, чтобы не допускать неоднозначного поведения или центральных узлов-bottleneck-ов, что позволяет распределять входящую нагрузку. Реактивные системы поддерживают алгоритмы масштабирования, измеряя производительность в реальном времени

  • Message Driven: все основано на асинхронной (неблокирующей) передаче сообщений, позволяя тем самым прочертить границы между компонентами и достичь слабой связанности, изоляции, независимости от расположения компонентов (location transparency), а также воспринимать ошибки тоже как сообщения

Вот как эти свойства связаны:

reactive-traits

Далее, небольшие системы складываются в большие, которые также сохраняют эти Реактивные свойства на всех уровнях масштабирования.

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

Observer pattern

Плавно переходя к библиотеке для .NET, созданной для построения систем на перечисленных принципах, - Reactive Extensions, важно заметить, какие концепции там использованы. Всё базируется на паттерне Observer. Кратко пробежимся по нему.

Итак, observer, он же наблюдатель, он же publisher/subriber, “создает механизм у класса, который позволяет получать экземпляру объекта этого класса оповещения от других объектов об изменении их состояния, тем самым наблюдая за ними”. Вот диаграмма классов с википедии:

Observer

Также приведу код на C#, тоже с википедии, но с пояснениями.

Пусть у нас есть абстракция IObserver (он же subcriber), которая выполняет некоторое действие Update - обновление своего состояния.

interface IObserver 
{
    void Update(string state);
}

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

Дальше, пусть есть еще одна абстракция IObservable (он же publisher), которая позволяет что-то делать с IObserver, а именно - добавлять/удалять и нотифицировать.

interface IObservable
{
    void AddObserver(IObserver observer);
    void RemoveObserver(IObserver observer);
    void NotifyObservers(string s);
}

Имея эти абстракции, можем написать такой псевдокод:

IObserver observer1;
IObserver observer2;

IObservable observable;

observable.AddObserver(observer1);
observable.AddObserver(observer2);

observable.NotifyObservers("some event");

Тут мы имеем публикатора observable и двух его подписчиков (наблюдателей) observer1 и observer2. Публикатор для нотификации подписчиков вызывает у них метод Update. Опять же все просто.

Как гласит википедия, “шаблон «наблюдатель» применяется в тех случаях, когда система обладает следующими свойствами:

  • существует, как минимум, один объект, рассылающий сообщения;
  • имеется не менее одного получателя сообщений, причём их количество и состав могут изменяться во время работы приложения;
  • нет надобности очень сильно связывать взаимодействующие объекты, что полезно для повторного использования.

Данный шаблон часто применяют в ситуациях, в которых отправителя сообщений не интересует, что делают получатели с предоставленной им информацией.”

Таким образом, паттерн позволяет чётко выделить отвественности и достичь слабой связанности. Причем топология системы может меняться в рантайме.

Summary

Подводя здесь черту, стоит еще раз обратить внимание на тот факт, что

  • Реактивные системы обладают свойствами Отзывчивости (Responsive), Упругости (Resilient), Эластичности (Elastic) и Управления с помощью сообщений (Message Driven)

  • Существует библиотека Rx для множетва языков программирования, которая призвана помогать делать системы с такими свойствами, то есть Реактивные системы

  • В основе Rx лежит шаблон проектирования Observer

В следующем посте разберёмся с основными артефактами Reactive Extensions. Stay tuned!

P.S. Сколько не пытался добавить риббон, так и не смог подружить его с общим дизайном. Вместо этого вот: we are reactive!

P.P.S. Aren’t we?

Subscribe via RSS