Реактивный трубопровод: начальный этап (часть 1)


Реактивный трубопровод: начинающий (часть 1)

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

Этот пост — введение. Оно нужно мне, чтобы объяснить мои мотивы и убедить вас в актуальности тех моментов, которые я буду упоминать. Объяснения по поводу самого приложения будут в следующем посте, который я сейчас активно пишу.

Прежде чем начать, вы должны знать следующее:

  • эта технология появилась совсем недавно в мире Java. Спенгеры Spring упорно работают над ней. То, что вы узнаете сегодня, может измениться.
  • Эта технология только начинает использоваться на предприятиях. Люди почти ничего о ней не знают.
  • у этой технологии трудная кривая обучения

Вы можете найти приложение в моем репозитории на Github.

Почему это приложение.

ReactivePipeline — это моя простая библиотека, созданная на основе проекта TaskPipeline.

Ее цель состоит в том, чтобы предоставить ясный один класс, названный ReactiveContext, с несколькими статическими методами, предоставляющими все необходимые объекты для создания простого, но работающего реактивного приложения. Под капотом находится проект Spring’s Reactor, очень маленькая часть, если быть честным.

Почему я это сделал? Чтобы получить удовольствие от изучения реактивного программирования и поделиться этими небольшими знаниями с теми, кто интересуется этим, с теми, кто хотел бы узнать больше, но не имеет достаточно времени, и, возможно, с теми, кто, как и я, остается голодным после прочтения доступных учебников.

Если вы когда-нибудь читали учебники по реактивному программированию, возможно, вы говорили себе, что создание Flux — не самая сложная часть.

Возьмем простой пример из поста Baeldung, связанный с ядром Reactor:

С таким кодом :

List<Integer> elements = new ArrayList<>();

Flux.just(1, 2, 3, 4)
  .log()
  .subscribe(elements::add);

assertThat(elements).containsExactly(1, 2, 3, 4);
Войти в полноэкранный режим Выход из полноэкранного режима

вы получите такой результат в консоли, благодаря оператору .log() :

20:25:19.550 [main] INFO  reactor.Flux.Array.1 - | onSubscribe([Synchronous Fuseable] FluxArray.ArraySubscription)
20:25:19.553 [main] INFO  reactor.Flux.Array.1 - | request(unbounded)
20:25:19.553 [main] INFO  reactor.Flux.Array.1 - | onNext(1)
20:25:19.553 [main] INFO  reactor.Flux.Array.1 - | onNext(2)
20:25:19.553 [main] INFO  reactor.Flux.Array.1 - | onNext(3)
20:25:19.553 [main] INFO  reactor.Flux.Array.1 - | onNext(4)
20:25:19.553 [main] INFO  reactor.Flux.Array.1 - | onComplete()
Войти в полноэкранный режим Выход из полноэкранного режима

Конечно, оператор .subscribe() выполняет свою работу и заполняет коллекцию elements каждым полученным значением. Утверждение подтверждает это.

Но… не находите ли вы это очень разочаровывающим?

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

Как поддерживать процесс как Flux от начала и до конца наших операций обработки?

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

Вот почему реактивное программирование кажется хорошей альтернативой императивной парадигме.

Императивное программирование

Императивное программирование — это наш повседневный способ выполнения работы. Мы знаем его настолько, что не задаемся вопросом и принимаем его ограничения по двум основным причинам:

  1. это нормально — делать так, как мы научились, но способ, которому мы научились, также обусловлен процедурной природой большинства языков
  2. это способ работы нашего мозга: причина -> следствие в одном потоке и последовательно.

В императивном стиле программирования мы используем для проектирования операции, которые будут выполняться одна за другой.

методА(…) —> методВ(…) —> методС(…)

Когда вызывается methodA(...), он выполняет свои действия и по завершении запускает следующий метод. В это время methodB(...) ожидает, как и methodC(...).

Конечно, мы все знаем некоторые обходные пути, такие как итерация по коллекции и распараллеливание вызовов methodB(...), а затем methodC(...). Но нам придется иметь дело с потоками, что на самом деле забавно, но и трудно отлаживаемо.

Или мы можем, конечно, использовать все возможности функционального программирования, например, параллельно-потоковые коллекции, но код быстро станет нечитабельным с функциями в функциях в функциях…

Подумайте о вызове хранилища, которое возвращает множество объектов. Вы не сможете обработать ни один из этих результатов до того, как сервер базы данных вернет свой набор результатов. Запрос может занять много времени, а в это время ничего не произойдет.
Напротив, реактивное программирование будет посылать вам объекты из хранилища каждый раз, когда один из них будет найден. Пока сервер базы данных обрабатывает ваш запрос, вы можете начать обрабатывать то, что уже было найдено на данный момент.

Реактивное приложение может работать быстрее не потому, что оно по своей сути быстрее, а просто оно никогда не ждет.

Никогда не ждать — это то, что мы хотим спроектировать и построить. Нам нужны трубы с
жидкими данными, текущими внутри. Нам нужен поток.

ReactivePipeline: отказ от ответственности, прежде чем мы начнем его использовать

Вот что такое ReactivePipeline: создать постоянный Flux для всего приложения.

Значит ли это, что не нужно писать реактивный код?

Нет. Я расскажу вам о классе Operation, который является чистым реактивным объектом.

Значит ли это, что вам не придется подключать все операции в
непрерывном потоке самостоятельно?

Да. Я расскажу вам о классах Task и Pipeline, которые предназначены для того, чтобы легко соединять операции вместе.

Является ли это идеальным приложением для создания вещей реактивным способом?

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

Увидимся в следующий раз на практических занятиях: Реактивный конвейер: приложение

Lovegiver

Написано с помощью StackEdit.

Оцените статью
devanswers.ru
Добавить комментарий