Статья написана при поддержке канала Mobile Developer.

В “далеком” 2018 г. разработчик компании EPAM Systems Владимир Иванов провел опрос среди своих подписчиков в Twitter, пытаясь узнать, какой фреймворк для организации асинхронной работы предпочитают Android-разработчики. 65% опрошенных назвали RxJava, 28% выбрали корутины.

Ирония в том, что результаты опроса Владимир приводил в докладе “RxJava не нужен: меняем Rx на корутины в Котлине”. Сегодня, спустя 6 лет после релиза стабильной версии Kotlin Coroutines, с трудом верится, что когда-то в мире асинхронной работы под Android был другой хозяин. 

Действительно ли RxJava так плоха, что ей не осталось места в наших приложениях? Используется ли она сейчас на проектах? Есть ли смысл изучать RxJava новичку?

Меня зовут Александр Гирев, я Android-разработчик проекта Go Invest. Давайте разбираться.

Почему упала популярность RxJava?

У меня нет под рукой сухих цифр, но очевидно, что с 2018 г. отношение к RxJava в коммьюнити “слегка” изменилось. 

Причина этому, внезапно - появление корутин. Так, на Google I/O 2019 было объявлено, что язык программирования Kotlin стал приоритетным в разработке под Android. Поскольку корутины являлись частью нового языка, было логично, что кроме Kotlin Google начал поддерживать и новый подход к обработке асинхронных операций в мобильных приложениях. Так, в официальной документации на сайте Android Developers в качестве рекомендуемого решения для асинхронной работы указаны корутины. Т.е. нам как бы намекают, что “правильнее” использовать на проекте при запросе в сеть. 

Однако корутины начали набирать популярность до того, как Google “дал добро” на их использование. Опрос, приведенный в начале статьи, был сделан накануне официального релиза стабильной версии корутин, но уже тогда треть респондентов (пусть выборка в опросе были не идеальной” была готова использовать новый фреймворк в своем проекте.

Сильным местом RxJava, которое могло охладить пыл в использовании свежей технологии, была ее проверенность и стабильность API в сравнении со неопробованными тогда корутинами. Кроме того, в RxJava имелись операторы для работы с потоками данных. Однако в корутинах для этой цели были созданы channels, а потом потом подоспели Kotlin Flow. Поэтому это преимущество RxJava нивелировалось. Кроме того, этот пункт часто записывался в недостаток использования RxJava, поскольку в небольших тонких клиентских приложениях вся мощь rx-цепочек была ни к чему.

В итоге корутины и Flow постепенно распространялись по мобильным приложениям.

Каковы настроения в сообществе?

По сети в большом разнообразии разбросаны накопленные за 6 лет материалы с рекомендациями по безболезненному отказу RxJava, а также с доводами, зачем это нужно делать.  Среди российских компаний своим успешным опытом миграции с RxJava на корутины делились коллеги из “Тинькофф”. А ребятами из Podlodka Android Crew проводился круглый стол на тему “Планируем переход с RX на Coroutines”.

Начинающих свой путь в ИТ стремятся мягко уберечь от неправильной асинхронной веры, например, соответствующие материалы можно найти в базе знаний GeekBrains. В совсем свежей статье о технологиях, которые нужно учить Android-разработчику в 2024 году Андрей Белоус и боярыня мобильной разработки Анна Жаркова отмечают, что в Kotlin Coroutines будут более предпочтительным выбором для изучения, нежели RxJava.

Однако нельзя сказать, что интерес сообщества к RxJava совсем угас. Так, на Хабре можно встретить годные и достаточно свежие материалы, посвященные RxJava. Например, статья с интригующим названием “Корни RxJava — о чем мы не подозревали”.  

В другой статье 2023 г.,  посвященной многопоточности в мобильной разработке, основные средства и инструменты в RxJava рассмотрены с такой же подробностью, как и основы корутин. А в конце статьи автор тактично резюмирует, что “что выбор инструмента для работы с многопоточностью зависит от конкретной задачи и потребностей приложения и что RxJava и Kotlin Coroutines представляют собой два мощных инструмента для работы с асинхронными операциями в мобильной разработке”.

Сделаем и мы промежуточный вывод: все чаще в адрес некогда популярного фреймворка можно услышать презрительное “Legacy”, остатки rx-цепочек на проектах мозолят глаза целым командам. Но остались “староверы”, чье сердце продолжает биться в ритме Rx. 

Действительно ли RxJava плоха?

В многочисленных докладах и статьях о преимуществах корутин приводятся следующие доводы миграции с RxJava:

  • код на корутинах легче читать и писать, потому что он выглядит как синхронный код;

  • у RxJava высокий порог входа по сравнению с корутинами, нужно изучить множество классов и операторов;

  • корутины более производительны;

  • RxJava - это внешняя зависимость в проекте, в то время как корутины со временем были интегрированы в Kotlin как часть языка;

  • код на RxJava труднее поддается отладке;

  • корутины подходят для кросс-платформенных приложений, потому что используют нативный Kotlin.

Давайте разберем некоторые тезисы из предыдущего пункта.

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

Продолжая тему читаемости кода, стоит признать, что для начинающих разработчиков код на RxJava действительно может показаться сложным и непонятным. Однако если отойти от маркетинговых примеров “асинхронного кода на корутинах в синхронном стиле” и взглянуть на цепочки данных на Kotlin Flow, то мы получим что-то очень похожее на RxJava, и, возможно, такое же страшное. Вот неплохая статья с примерами кода rx-цепочек и их аналогов на Flow.

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

Что касается производительности, то анализ материалов, в которых производилось сравнение различных инструментов для асинхронных операций(раз, два), позволяет сказать следующее: по скорости при проведении большинства типов задач RxJava была равной по производительности корутинам, а в отдельных задачах показывала лучшие результаты, однако при построении длинных цепочек проигрывала по использованию памяти. 

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

Ситуация на рынке

Исходя из вышесказанного, популярность корутин на действующих Android-проектах должна быть выше, чем популярность RxJava. Проверим, так ли это, проанализировав активные вакансии на hh.ru.

Поиск по ключевым словам “Android coroutines”, “Android Flow”, “Android корутины” предоставил в общей сумме 198 вакансий, в то время как по запросу “Android RxJava” - только 73 вакансии. 

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

Также нужно отметить, что вакансии на проекты с RxJava предусматривали доход от 90 до 400 тыс. рублей, а в списке компаний можно было найти Сбер, Яндекс, VK, Тинькофф, МТС, Альфа-Банк и, собственно, сам HeadHunter. Что может свидетельствовать об актуальности и востребованности опыта работы с RxJava у ряда известных работодателей на русскоязычном рынке.

Стоит ли писать новый проект на RxJava?

Как мы уже выяснили, RxJava не является популярным решением среди относительно новых проектов. И вопрос не только и не столько в том, что сам фреймворк плох, сколько в том, что современные API и фреймворки Android SDK выпускаются без поддержки RxJava из коробки. 

Самый простой пример: у ViewModel из Android Jetpack с одним из релизом androidx.lifecycle:lifecycle-*:2.1.0 появилась дефолтная реализация CoruitineScope в виде viewModelScope для работы с корутинами, но нет встроенного Disposable для RxJava. 

Исключение из правила есть, это WorkManager из той же Android Jetpack, который из коробки имеет свою реализацию RxWorker. Но причина тут проста: релиз WorkManager произошел примерно в одно время со стабильной версией корутин, поэтому наличие адаптаци�� для RxJava было необходимым шагом, чтобы новым инструментом для фоновой работы можно было пользоваться на уже существующих проектах.

Как мы уже обсудили, корутины являются частью Kotlin. И если интерес Google к Kotlin Multiplatform будет усиливаться, места для не Kotlin-решений, к каким относится и RxJava, в наших проектах со временем будет все меньше и меньше.

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

С натяжкой в качестве зеленого света для RxJava можно назвать 100% гарантию, что вы будете писать нативное приложение и не полезете в историю с кросс-платформой. 

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

Стоит ли новичку учить RxJava?

Если что-то и осталось прежним в отношении RxJava, так это страх и ужас в глазах студентов ИТ-курсов при виде rx-цепочек. Стоит ли сегодня начинающим разработчикам превозмогать этот страх и из последних сил заучивать отличия между Single и Maybe?

На мой взгляд, must have-знанием для новичка являются корутины и Flow: как мы обсудили выше, Kotlin Flow писались по образу и подобию RxJava, если вы достаточно глубоко изучите работу с ними, то вам будет легче в последующем разобраться с Rx, когда возникнет такая необходимость.

Кроме того, небольшие и относительно молодые проекты с большей вероятностью используют корутины, а именно на такие проекты часто открыты вакансии для специалистов уровня Junior. Чтобы не быть голословным, приведу результаты анализа все того же hh.ru: по запросу «android developer junior» для специалистов без опыта работы либо с опытом от 1 до 3 лет было найдено около 30 релевантных вакансий, из которых только в трех вакансиях в требованиях явно было указано знание RxJava.

Выводы

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

При написании приложения с нуля RxJava выглядит не самым оптимальным решением ввиду официальной политики Google по поддержке корутин и интереса компании к Kotlin Multiplatform. Кроме того, наличие RxJava в стеке проекта может снизить привлекательность вакансии среди кандидатов, часть разработчиков могут принять использование Rx в проекте за легаси. 

Для начинающих знание RxJava будет не лишним, поскольку на рынке достаточное количество вакансий на проекты, в которых используется Rx. В то же время, в ряде случаев отсутствие опыта с RxJava можно компенсировать уверенными знаниями Kotlin Flow. И если вы сумели разобраться с Flow, изучение RxJava станет не такой сложной задачей.