Проблема, друзья. Реактивщина везде, её слишком много и уже никому от неё не спрятаться. Мы с вами все умеем написать ASyncTask, Service или ContentProvider (я в это верю!). Все можем повернуть битмапу или сгонять на сервер за данными. Это все довольно очевидно. Но ещё МЫ ДУМАЕМ, что можем готовить реактивищну правильно. Это далеко не всегда так.

Что такое правильное реактивное программирование на Android?


image

– Добрый день. Расскажи в двух словах о себе. Где работаешь, чем занимаешься, когда начал продвигать реактивный подход?

— Привет. Меня зовут Матвей Мальков (на хабре lNevermore ). Я Android-разработчик уже, наверное, лет 5-6. Конкретно сейчас я занимаюсь Scala-разработкой в одном стартапе. Стартап находится в Москве и о нём я говорить особо много не могу. Но суть в том, что это будет такая комьюнити-платформа, наподобие Телеграма. И её я, собственно, пишу под Android на Scala.

Первый проект, который я полностью перевел на RxJava, у меня был в компании 2GIS. Архитектура, база, работа с сетью — всё. После этого начал активно продвигать фреймворк RxJava и реактивный подход в целом на конференциях. Сейчас пишу на Scala, где использую вовсю функциональный подход, а в свободное время интересуюсь новостями реактивного мира.

– Пользователи Хабрахабра наверняка в курсе концепции реактивного программирования. Расскажи про особенности этой парадигмы на Android и про реактивные потоки данных.

– В программировании под Андроид довольно много особенностей, связанных с реактивным программированием. Я как раз хотел бы сказать о том, что не все принципы реактивного программирования, о которых мы попозже подискутируем, хорошо ложатся на Андроид. Чтобы не быть голословным: есть такое понятие как масштабируемость, под которой обычно понимается масштабируемость на большое количество нод, то есть это какая-то серверная масштабируемость. В Андроиде же это всего лишь масштабируемость на треды, что не есть «настоящая маштабируемость». И она не даёт такого большого мощного импакта на систему в целом. Хотя, конечно, всё равно даёт, но по-другому.

Ещё одна особенность заключается в том, что очень много в Андроиде завязано на императивщину. То есть на мутабельность, на изменяемость данных, и конкретно из-за неё очень сложно всё это завернуть в реактивные потоки. Это приводит к тому, что приходится делать много хаков, что всё очень усложняет. Императивность Android заставляет большое количество разработчиков использовать такие вещи, как сабжекты, которые вообще-то были задуманы и сделаны для того, чтобы сращивать мир реактивный и мир императивный. Но по факту, на самом деле, все пользуются им для того, чтобы что-то легко завернуть в Observable, Это обычно происходит в ущерб архитектуре, особенно на длинной дистанции, на больших проектах. Получается мешанина из императивщины и абы как сделанной на ней реактивщины. А всё потому, что многим людям просто лень сделать правильно или они не знают, как именно правильно.

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

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

– Если говорить о принципах из реактивного манифеста, который, собственно говоря, и является фундаментом и основой идеологии реактивного программирования, то в своей статье на Хабрахабре я подробно раскрывал все эти пять принципов и проецировал их на Андроид-разработку. И безусловно да, я с ними до сих пор согласен. Это костяк, это основные принципы, основные импакты, на которые стоит рассчитывать, когда ты разрабатываешь, используя реактивный подход, и это основные вещи, за которые ты должен бороться, когда ты используешь реактивщину.

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

– Что важнее: ресурсоёмкость или надёжность? Ведь есть лимит на выдачу потоков в Android, можно выбросить бюджетные устройства за «борт», просто потому, что приложение (стало) более требовательно к ресурсам :)

– Конечно и безусловно, намного важнее надёжность, потому что сейчас в андроид-мире наметился тренд на то, что очень много устройств находится в дешёвом сегменте. В Индии запустили Android One, в Америке продают телефоны за несколько долларов. То есть появились очень дешёвые и супердешёвые андроид-смартфоны, которые безусловно не могут работать также, как Nexus 6P. Владельцев таких смартфонов становится всё больше и списывать их всех со счетов нельзя.

Но, конечно, про ресурсоёмкость забывать тоже нельзя. Она не вторична, эти два принципа должны идти параллельно друг другу. В той же реактивщине мы можем в зависимости от устройства, от количества ядер задавать разное количество потоков для операций. То есть пусть в бюджетных устройствах что-то работает медленнее, но работает точно и отрабатывает чётко. Пусть это занимает больше времени, но тем не менее. Между этими вещами стоит находить баланс, но внимание держать нужно на обоих!

– Ты сказал, что довольно консервативен в плане технологий и фреймворков. Расскажи про фреймфорк RxJava и его плюсах и минусах.

– Есть такая вещь как Framework-driven-development. Это болезнь, наверное, фронтенда в первую очередь. Да и всего андроид-мира. Представь, что ты не можешь решить какую-то задачу быстро, и тебе конечно же лень думать и ты пытаешься найти какой-то фреймворк, который написал никому не известный индус. У этого фреймворка версия 1.0.0 или 1.0.1, то есть пропатчил он его всего один раз, а написал года три назад. И он как-то удовлетворяет твои нужды. Библиотека не расширяемая, может падать, но свою работу как-то выполняет. Это очень сильно распространено и люди постоянно тянут подобные фреймворки к себе в проект. Я считаю, что так делать нельзя и поэтому везде пишу, что я довольно консервативен в этом плане.

Что можно сказать про фреймворк RxJava? Очень круто, что около него уже есть мощное комьюнити, он часто правится, баги всё время фиксятся. Прикольно, что идёт в разные стороны импрувмент RxJava, т.е. они и нацеливаются на быструю обработку каких-то событий, что очень важно для андроида, и в такой же степени они работают над тем, чтобы RxJava хорошо работала в серверной части. Например, уже была добавлена обработка backpressure, а это уже бекэндовая штука. Раньше там был только on-backpressure-buffer и on-backpressure-drop, а теперь они позволяют кастомно обрабатывать все эти backpressure. В современном Андроиде тоже приходится с этим сталкиваться — не только в высоконагруженных системах. Особенно если система построена на реактивщине, много потоков, один очень быстро пишет данные, а другой поток медленно их читает (неторопливый норвежский читатель) и тогда обработчик начинает задыхаться. И это тоже надо обрабатывать, а обычно Андроид-разработчики не очень в курсе того, что такое backpressure, и очень удивляются, когда слышат эти слова. А это важно и нужно знать в процессе Андроид-разработке.

Минусы у RxJava, безусловно, тоже есть. Дело в том, что это совершенно другой подход, если мы говорим об Андроиде. До сих пор в этой ОС больше применяется императивный подход, а RxJava – это больше функциональщина. И очень немного людей умеют правильно «готовить» RxJava. Даже я сам не супер-правильно понимаю все концепции RxJava, потому что это очень глубокая штука. Но в свою защиту могу сказать, что даже на практическом уровне не все понимают этот фреймворк. :)

Также в очевидных минусах нужно отметить то, что происходит очень много копирований объектов. К чему это приводит – понятно. Это дополнительная нагрузка на GC.

– RxJava vs Bolts: принципиальная разница между ними? Какие у тебя личные предпочтения, ну и потенциал каждого из конкретных подходов?

– Я с Bolts практически не работал, так чисто пробовал потыкать. RxJava мне кажется более родной и лаконичной в плане синтаксиса. Она хорошо выглядит и довольно удобная. Но в то же время Bolts более глубок в плане реактивного подхода. Одни только async и await доставляют, которых, кстати, в “нормальной” RxJava нет. Bolts, как мне кажется, более низкоуровневый и близок к фундаментальным вещам.

Потенциал ясен и он огромен. И одна, и другая библиотека нанесли огромный импакт на разработку. RxJava, насколько я вижу, повлиял больше, так как Bolts всё-таки меньше используется. Какой библиотекой пользоваться – выбор каждого, но мне кажется, что RxJava попроще в плане синтаксиса и понимания.

– Как ты оцениваешь современные приложения от топовых разработчиков: 2GIS, Soundcloud, Facebook и какая у них разница в подходе к парадигме?

– Это абсолютно разные приложения, начиная с того, что они про разные вещи. 2GIS про геолокацию и карты, Soundcloud про музыку, а Facebook про социальные вещи. Они интересно подобраны, потому что написаны на абсолютно разных технологиях. 2GIS написан на Qt 5 + QML, Soundcloud — джавовое приложение с использованием реактивщины RxJava, а Facebook сейчас написан на Reactive Native. Как минимум в этом уже есть принципиальная разница. Плюс есть разница в том, как они относятся к своим пользователям.

То есть, например, Facebook не соблюдает все гайдлайны и у фейсбук-мессенджера есть такая вещь, как Pop-Up или Overlay. Когда ты чатишься, у тебя прямо на рабочем столе стоит лицо того, с кем ты переписываешься. И по клику на него открывается приложение, которое перекрывает всё, что сейчас есть на экране. Так делать не очень правильно и меня лично очень раздражает.

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

Ну а 2GIS – это 2GIS. (кстати, знаете, что правильно произносить не “дубльГИС”, а “двагис”? Теперь знаете! :) У них свои запары, у них QML и они вроде как не могут особо использовать стандартные андроидовские виджеты. Суть в том, что они тоже стараются следовать стандартному материал-дизайну, но у них не всегда это получается.

Мне очень нравятся приложения типа Soundcloud или Телеграма, которые очень быстро работают. Я не знаю, как их оценивать. Приложения работают стабильно и хорошо, дизайн может кому-то нравиться, а кому-то — нет. А парадигмы у них всех разные.

– Как ты оцениваешь динамичность развития реактивного программирования и применение в сферах, отличных от мобильной разработки (Elm)?

– Про Elm ничего сказать не могу, потому что никогда не пользовался. Само же реактивное программирование сейчас, как я вижу, набирает обороты. Оно нашло очень хорошую нишу в server-side, много компаний используют его в своих серверах, что позволяет создавать хорошо маштабируемые сервисы, работающие под большими нагрузками. В BigData тоже можно легко увидеть такие вещи как Akka Streams и RxJava. Вот такой «крутой» (нагруженный, распределенный и бла-бла) сервис как Netflix написан на RxJava почти полностью.

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

– О чём будет твой доклад The Art of Rx на конференции Mobius 2016?

– Доклад планируется довольно философский, о том, куда идёт реактивщина и о том, как на самом деле правильно её готовить. Я рассмотрю некоторые аспекты, связанные с построением архитектуры приложений с использованием этого подхода. Язык не поворачивается совместить слова «архитектура» и «программирование». Как ни странно, эти ошибки очень многие допускают! Как я об этом узнал? Да очень просто! Я их частенько вижу на всяких форумах. А почему? Да потому что люди много чего делают неправильно в самой реактивщине и пошло-поехало: становится очень сложно всё это поддерживать и вся идея реактивного подхода как будто бы рушится. Ну а я в докладе попытаюсь рассмотреть некоторые архитектурные вещи внутри самой RxJava. А именно: как на самом деле работает тот же flatmap, покажу интересные вещи, связанные с Zip, ну и коснусь нескольких внутренних вещей, например, как создаётся Observable из Observable. В общем, интересных штук я заготовил прилично :).

Многие об этом, наверное, просто никогда даже не задумывались и я постараюсь все так преподнести, чтобы было интересно и познавательно. Самое главное – познавательно.




Полезные ссылки

Комментарии (27)


  1. KoCMoHaBT61
    29.04.2016 21:51
    +7

    Талант!
    В первый раз на хабрахабре вижу статью на 70% состоящую из баззвордов.


    1. lNevermore
      30.04.2016 17:05
      +1

      Сорри, я старался быть максимально понятным, не вышло.


  1. HeaTTheatR
    29.04.2016 22:18

    Я так и не понял, что автор хотел сказать…


    1. zim32
      29.04.2016 22:25

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


      1. Artem_zin
        30.04.2016 01:00
        +6

        Если дату вашего комментария перевести года на 2, то ~правда.

        Сейчас это уже штука, которая выстрелила и знание желательно в нормальных вакансиях.


        1. Bringoff
          30.04.2016 15:46

          знание желательно в нормальных вакансиях

          Не знаю, где вы смотрите вакансии, но зашел на jobs.dou.ua, из 60 вакансий по android слово "rxjava" встречается в 3-х. "Rx" нет нигде. То есть, 5% вакансий. И не факт, что эти 3 — самые нормальные.


          1. lNevermore
            30.04.2016 17:06
            +3

            Я соглашусь с Артемом. Дело в том, что этого не называют конкретно в вакансии, но на собеседовании многие компании, которые использую всякие новый технологии, наверняка будут рады, если вы будете знать что-нибудь связанное с Rx. Не говоря о том, что самих проектов на ней под Android становится все больше и больше.


  1. gurinderu
    29.04.2016 23:07

    А откуда информация про двагис? Я так понимаю 2gis называют дубльгисом, лишь только потому, что он так назывался до ребренгинга.


    1. lNevermore
      30.04.2016 17:07
      +1

      Вроде как продукт называется ДВАгис, а сама компания до сих пор ДульГис


  1. Bringoff
    30.04.2016 07:19

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

    Вот это мнение меня всегда удивляло. Мы пишем под android, значит, надо завязываться на это, оптимизироваться под это, использовать там структуры данных из библиотеки саппортов ради скорости, компоненты системы. Это ж мобилка, здесь не до архитектурного оверхеда, надо память экономить, батарейку, а не гонять данные по слоям туда-сюда, как в clean architecture


    1. xoxol_89
      30.04.2016 09:52
      +3

      Зря вы про архитектурный оверхед.
      Это вовсе не оверхед, и никак оно на производительность приложения в худшую сторону не влияет. Другое дело, что приложение у вас становится четко декомпозированным, разбитым на модули. Плюс вы сможете покрывать свой код тестами, что придаст большую стабильность коду. Еще вы сможете легко разбивать какую либо задачу между разработчиками — один на ui, один на бизнес-логику, другой на data-уровень.
      Вообще преимуществ у чистой архитектуры много. Другое дело — чтобы понять их и прочувствовать, нужно садиться, пробовать и писать. Иначе ну никак. Количество абстракций и уровней всегда будет пугать. Но разобравшись, понимаешь, что все это необходимо и нужно.


      1. Bringoff
        30.04.2016 10:14

        никак оно на производительность приложения в худшую сторону не влияет

        Вы замеряли? :) Как бы чем больше объектов мы создаем, тем больше работы у GC. Как минимум.


        Еще вы сможете легко разбивать какую либо задачу между разработчиками — один на ui, один на бизнес-логику, другой на data-уровень

        Ну, во-первых, 3 разработчика на одно android-приложение — это многовато. Во-вторых, на обычном каком-нибудь rest-клиентике "бизнес-логики" — минимум (поэтому xamarin не слишком популярен — количество общего кода не во всяких там корпоративных приложениях невелико, а интерфейс для каждой платформы надо свой делать), поэтому лишний слой нужен очень редко.


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


        Архитектуру вполне можно организовать и на основе компонентов android: contentprovider-ов/observer-ов, service-ов, но это, вилите ли, не модно :)


      1. Bringoff
        30.04.2016 10:30
        +1

        Или вот philm. Даже несмотря на то, что давно не обновлялся, этот репозиторий содержит очень стройный код.


        1. xoxol_89
          30.04.2016 11:16
          +3

          1. Спасибо за ссылки, посмотрю внимательно)
          2. Нет, не замерял. Но у GC больше работы, это да. Вопрос только в том, на сколько критично и велико это увеличение. Мне кажется, вообще не критично. Но опять таки, лучше измерить.
          3. 3 разработчика на одно приложение — это нормально. Как и пять) Приложения то разные бывают. Вообще очень разные. И какой бы не был rest-клиент, все начинает меняться, когда вам необходимо эти данные кешировать, синхронизировать. Мне в этом отношении очень нравится подход, как был в конкурсе Telegram — https://vk.com/durovschallenge?w=wall-55882680_69. Суть в том, что есть некая нативная библиотечка с API. И эта библиотеска полностью берет на себя вопросы кеширования, синхронизации. Единое такое решение для всех платформ для data-уровня.
          4. То, что можно все организовать на contentprovider-ов/observer-ов, service-ов, никто не спорит) Но я вот, честно говоря, не знаю, на сколько это будет поддаваться тестированию. С Clean architecture вы каждый слой спокойно можете покрыть юнит тестами (кроме ui) без дополнительных тулзов, так как там нет android компонент.


    1. Lovesuper
      30.04.2016 22:32
      +1

      Вы мобилки-то видели вообще текущие? Каждая из них помощнее моего нетбука 4-летней давности. А чистая архитектура для развесистого приложения поможет сохранить код понятным и доступным для поддержки.


  1. VioletGiraffe
    30.04.2016 12:06
    +1

    Читал на Хабре как минимум ещё 2 статьи по Rx, но так и не понял, что это и зачем может мне понадобиться. Гугление тоже ничем не увенчалось. Не посоветуете годное, понятное описание?


    1. xoxol_89
      30.04.2016 12:53

      https://github.com/kaushikgopal/RxJava-Android-Samples
      Посмотрите эти примеры. Дают вполне нормальное представление, как Rx может помочь)


    1. lNevermore
      30.04.2016 17:09
      +1

      На самом деле очень сложно поначалу вникнуть и понять, зачем все это нужно. Мне кажется, что некоторые люди просто ее используют, потому что это «модно», а не потому, что дает им какие-то выгоды.

      Если говорить про понимание, то, возможно, саам стоит начать с лекций и видео каких-нибудь. Из довольно много и про Android и про iOS, про веб фронтенд и даже про бекенды. Там частенько бывают вещи, которые раскрывают всю суть реактивного подхода


    1. burjui
      30.04.2016 17:39
      +3

      Если кратко, то Rx — это Iterable, вывернутый наизнанку: вместо того, чтобы самому просить данные в цикле и что-то с ними делать, вы предоставляете «обработчики», которые Rx вызывает, когда приходят данные. Только вместо лапши из callback и состояний получаются потоки данных, в которых ваши «обработчики» на каждом шаге преобразуют данные, а Rx их протаскивает далее по цепочке. Этакая смесь асинхронности с функциональщиной.

      Посмотрите выступление Эрика Мейера — может, станет понятнее:
      https://www.youtube.com/watch?v=sTSQlYX5DU0


      1. VioletGiraffe
        30.04.2016 21:36
        +1

        Спасибо!


    1. zim32
      30.04.2016 21:26

      В мире джаваскрипт их описывают как смесь Promises + Events завернутую в объекты первого рода


  1. lair
    30.04.2016 13:46
    +2

    Занятно, кстати: очередная статья, в которой "реактивщина" незаметно приравнивается к Rx (окей, здесь еще Akka Streams припомнили, но это тоже поток событий). Хотя Кун — один из авторов цитируемого Reactive Manifesto, — скажем, считает акторы не менее жизнеспособной моделью.


    1. lNevermore
      30.04.2016 17:12
      +2

      Ну ладно, что уж вы) Я не приравнивал Rx к самому подходу. Конечно, это лишь одна из многих реализаций, тут я полностью с вами согласен.
      Другое дело, что для Android все таки сильно чаще используется именно RxJava или RxKotlin или еще что из Rx.

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

      Но соглашусь, что чаще говорят именно про RxJava и меньше про другие фреймворки и подходы.


      1. lair
        30.04.2016 19:59
        +1

        Я не приравнивал Rx к самому подходу.

        Ага. Статья с заголовком "The Art of Rx" и тизером "Что такое правильное реактивное программирование на Android?"


        Никто же не запрещает их вместе использовать их в одном проекте

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


  1. deeGraYve
    30.04.2016 22:08
    +1

    с трудом заставил себя прочитать статью по теме которой интересуюсь, а виной всему

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


    1. lNevermore
      04.05.2016 15:03

      Я с трудом читаю какие-то статьи, где вместо «Активити» или «Activity» написано «Активность» а вместо сабджекта «объект» или «субъект».

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


      1. deeGraYve
        06.05.2016 17:14
        +2

        Есть разница между упоминанием в тексте Activity и импрувментом. Первое — совершенно нормально и не удивит никого знакомого с предметом статьи, насчет второго наши мнения скорее всего могут разойтись. А subject — всегда «субъект», по крайней мере должен быть, но не прямой противоположностью самому себе, то есть никак не «объектом»