Что выбрать: Coroutines или RxJava?

Сравниваем плюсы и минусы фреймворков
4 минуты3944

Какой фреймворк выбрать для своего проекта — Coroutines или RxJava? Чтобы помочь ответить на этот вопрос, перевели для вас статью про плюсы и минусы обоих фреймворков.

В компании Trello мы подумывали перейти с RxJava на корутины. Мы уже использовали корутины тут и там, но до недавнего времени не рассматривали их как полноценную замену Rx, в основном из-за бедной функциональности корутин. Теперь, с добавлением StateFlow и SharedFlow, корутины можно сравнивать с Rx. 

Чтобы оправдать переход с Rx на корутины, я написал список «за и против» для каждого фреймворка.

Преимущества RxJava

Зрелый и проверенный фреймворк

RxJava прекрасно работает в нашем проекте и многих других. Мы уже давно и успешно используем Rx в нашем приложении, дополнили фреймворк своим функционалом. У нас богатый опыт использования Rx, и мы знаем все тонкости фреймворка и возможные узкие места. 

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

Стабильность

API RxJava стабилен.

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

Проще искать баги

RxJava знаменита тем, что её сложно дебажить, но стектрейс корутин даст фору даже Rx. У нас уже есть опыт в дебаге Rx, и нам придется переучиваться для корутин (хотя для дебага корутин есть свои инструменты).

Совместимость с Java

RxJava можно использовать с любым Java-совместимым языком, корутины же можно писать только на Kotlin. Для нашего проекта это не страшно, но это может стать проблемой для других. (Обратите внимание, что я говорю о написании кода, а не о его использовании: любая сторонняя библиотека может использовать корутины под капотом, а наружу выставлять вполне обычный API на Java.)

Преимущества корутин

Kotlin Multiplatform

RxJava, как следует из названия, ограничена языком Java. Корутины работают на любой платформе, поддерживающей Kotlin, поэтому, если нам вдруг понадобится переиспользовать асинхронный код между Android и iOS, мы можем спокойно использовать корутины.

Простой API

У Rx есть много разных типов потоков (Observable, Flowable, Maybe, Single, Completable) для каждого конкретного случая. Kotlin дублирует весь этот функционал двумя типами: suspend fun и Flow. Такое решение гораздо проще в использовании не только потому, что типов всего два, но и потому, что можно вызывать асинхронные функции через простые лямбда-выражения (в отличие от комбинирования разных потоков через множество порой неочевидных операторов в Rx).

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

Более простые операторы

Написание кастомных операторов в Rx — отдельная головная боль. Чтобы сделать это по-настоящему хорошо, нужно понимать, как работает Rx под капотом (например, понимание back-pressure), что само по себе большое достижение, покорившееся только одному человеку (тут я почти не шучу). С другой стороны, новые операторы для Flow пишутся как и весь остальной код. Сравните полный класс для оператора Rx map() и аналогичный оператор (пара строк кода) для Flow.

Структурированная многопоточность

Потоки Rx склонны к утечкам, в то время как корутины обрабатывают входящие объекты, даже если вы забыли про них. Корутины Kotlin структурированы (разнесены по областям видимости и применения), что сильно упрощает управление жизненным циклом открытых потоков.

Простое управление back-pressure

Back-pressure (переизбыток входящих событий) происходит, когда источник данных выдаёт эти данные быстрее, чем принимающий поток успевает их обрабатывать. Это реальная проблема в Rx и источник избыточного и запутанного кода во фреймворке, потому что принимающие потоки должны постоянно взаимодействовать с испускающими, чтобы избежать переизбытка событий.

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

Производительность

У Flow производительность не хуже (если не лучше) чем у Rx. Reactive Scrabble является стандартом для проверки эффективности потоков, и у Kotlin в их репозитории  есть версия Scrabble. Судя по измерениям (чем ниже, тем лучше), Flow корутин превосходит RxJava.

Взаимозаменяемость (interoperability)

Тут стоит отметить хорошую взаимозаменяемость между корутинами и Rx. Kotlin предоставляет разные преобразователи из Rx во Flow. Без их помощи вам пришлось бы вручную переписывать весь код, — такая себе перспектива. Благодаря преобразователям кода вы можете переводить Rx в корутины поэтапно. Это также значит, что вы можете и дальше использовать библиотеки на основе Rx в проекте, который работает на корутинах. 

У корутин есть и инструменты миграции с устаревших потоков Rx на аналоги во Flow. С помощью этого инструмента вы просто переводите Rx-поток на Flow, и замена производится автоматически в среде разработки. (Обратите внимание, что это работает именно для устаревших потоков, а не просто переводит весь Rx на Flow.)

В заключениe

Основная проблема в переходе с Rx на корутины заключается в том, что это новая необкатанная технология, со всеми вытекающими. Вам придется привыкать и адаптироваться к ней, выводить для себя собственные подходы и решения, дописывать что-то под себя. Вне всяких сомнений, вы пропустите какой-то крупный баг (а то и два-три) просто потому, что вы не знаете всех нюансов в специфических случаях. 

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

Мы с командой постепенно начнём переходить на корутины. Как и с любым крупным изменением, мы будем переходить на корутины поэтапно, на случай непредвиденных проблем. Пока, вроде бы, всё хорошо. Учитывая всё вышесказанное и ваше отношение к рискам, вы можете не менять знакомый и понятный вам Rx на корутины, пока они не станут более стабильными и проверенными.

Читайте больше полезных статей для начинающих Android-разработчиков:

А если затянет — приходите на факультет Android-разработки. В время учебы вы разработаете Android-приложение и выложите его в Google Play, даже если никогда не программировали. А также своите языки Java и Kotlin, командную разработку, Material Design и принципы тестирования.

программированиеandroid
Нашли ошибку в тексте? Напишите нам.
Спасибо,
что читаете наш блог!