Статья написана при поддержке канала 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 станет не такой сложной задачей.