Супераппы мертвы. Да здравствуют супераппы! Доклад Яндекса

Всем привет, меня зовут Илья Богин, я руковожу отделом разработки мобильного портального приложения Яндекса и Яндекс.Браузера для Android/iOS. В докладе на конференции YaTalks я решил поговорить о том, что сейчас понимается под супераппами, какие задачи они решают, чем отличаются азиатские и российские подходы к созданию супераппов. Еще я поделился опытом своей команды: какие технические вызовы бросает суперапп, может ли в этой роли выступать веб-платформа, что мы поняли в процессе разработки и почему в итоге решили, что мы не суперапп.— Мобильная часть нашего YaTalks посвящена самой хайповой на сегодняшний момент теме. Это тема супераппов. Поскольку я первым врываюсь в наш виртуальный зал, то мне нужно чуть больше рассказать о том, что такое супераппы, чтобы мы с вами были на одной волне.
Я хочу рассказать, как мы в Яндексе построили один из супераппов, а потом сделали из него нечто большее, чем суперапп. Хотя, казалось бы, что может быть больше, чем суперапп, который и так в себя все вобрал? Но не будем забегать вперед.

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

bgvdiakswlcaxjfqjiic8pc41vi.jpeg

Мне подсказывают, что не все знают мордорский диалект. Что ж, у меня есть стихотворный, красивый, поэтический перевод на русский язык. Думаю, все догадались, что речь идет о том самом стихе о кольце всевластия. При чем здесь суперапп? Суперапп по концепции очень похож на кольцо всевластия.

pcigwyxecwlhrqltfbg-rdetoae.jpeg

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

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

quicmwouzquvywise9apsgb5p5w.jpeg

Вот из этого и состоит суперапп. Теперь давайте поговорим о том, какие бывают супераппы. Можно разделить текущее множество супераппов на две большие категории.

kxf5qg-kdzr2wqqecuapld5hwqg.jpeg

Первая категория — это экосистемы, которые мы назовем закрытыми. В закрытой экосистеме количество партнеров, сервисов, которые предоставляет суперапп, очень ограничено, жестко регулируется создателями супераппа и, как правило, одну функциональность предоставляет один партнер. Часто этот партнер либо является частью компании, выпускающей суперапп, или, даже если это внешняя фирма, может выступать просто как white label, без собственного бренда. Он предоставляет услугу через суперапп, не имея других конкурентов внутри супераппа. Но он и не имеет собственного бренда внутри супераппа. В противоположность этому существуют системы, которые мы назовем пока еще не совсем открытыми, а частично открытыми.

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

Мы можем перейти к конкретным примерам. На азиатском и южноамериканском рынке эти системы супераппов развиваются очень активно. На российский рынок они стали проникать чуть позже, только начинают развиваться. В качестве классического примера закрытой экосистемы можно представить приложение Яндекс Go, которое выросло из приложения Яндекс.Такси. (…)

jg2nqytcwfjufn6pot8fv7f14-q.jpeg

Помимо закрытых экосистем существуют частично открытые и на российском рынке тоже. Наиболее яркий пример — VK с Mini Apps. Вы можете создать Mini App и въехать в VK или, например, в «Тинькофф», который тоже предоставляет возможности по интеграции внешних сервисов внутрь банковского приложения.

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

Технические вызовы при создании супераппа


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

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

a_rtxwmu9fks04t41vatyzfbhse.jpeg

Это уже достаточно непростая задача. Второй момент — чтобы эти сервисы давали пользователям приложения максимально качественный, нативный, идеальный user experience. Тоже не самая простая задача. Чтобы дать на нее ответ, нам нужно разобраться, что мы вкладываем в понятие того самого идеального user experience, который мы хотим предоставить.

360gjlw-8ojpdinxtpkdsabxbcc.jpeg

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

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

Следующий момент, который я бы обязательно включил в понятие качественного user experience — это широкий доступ сервисов к нативным возможностям девайса. Современный мобильный телефон или планшет — очень мощное устройство с большим количеством дополнительных нативных возможностей. Нативная оплата: Apple Pay, Google Pay, Huawei Pay; куча дополнительных инструментов, гироскопы, AR. И конечно, чем больше возможностей мы даем сервисам внутри нашего супераппа, тем более качественные и инновационные сервисы мы сможем давать нашим пользователям.

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

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

9v2jwps2pw6t_o7iqgnelcrrejo.jpeg

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

Вроде бы понятный подход, но он имеет свои минусы. Да, у вас получается максимально идеальный look and feel. Но представьте, что таких сервисов у вас сто или двести. Или не дай бог, тысяча. Если мы говорим, например, о WeChat, Dianping или о приложении VK, то сервисов может быть очень много, число может исчисляться тысячами. Вы встаете перед дилеммой: либо вы пытаетесь интегрировать большое количество внешнего UI — что, наверное, рано или поздно просто станет невозможным; либо вы пытаетесь предоставить им некий общий UI, который они будут пытаться кастомизировать под себя. Это тоже может быть не так просто.

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

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

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

Мы долго думали. Вначале долго обсуждали, холиварили при выборе подхода, но в какой-то момент нам пришлось сказать самим себе: alea iacta est, жребий брошен, Рубикон перейден. Мы выбрали технологию. Думаю, вы уже догадались: мы выбрали интеграцию сервисов в виде веба.

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

t0qb0muxqwaxakb_vec-w0ezi3k.jpeg

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

Второй важный момент. Сервис, который к нам въезжает, не дублирует свой код между платформами: веб, iOS, Android. У него есть единое представление. Это единое представление он использует как в вебе, в любых браузерах, так и внутри нашего супераппа на платформе iOS или на Android. Но как мы уже упоминали, выбор похода интеграции через веб-сервис ставит очень тяжелые задачи, связанные с улучшением технологических характеристик, потому что скорость, плавность, нативность UI — все это очень сильно проседает.

Мы потратили много усилий и нервных клеток, чтобы достичь максимально хороших характеристик веба внутри нашего супераппа. Давайте поговорим об этом чуть подробнее.

-iupr_h6xhn8xup13irz1wiocs4.jpeg

Кто-то скажет, что современные веб-движки прекрасно справляются с веб-контентом и такой проблемы вроде бы уже не должно существовать. Веб отображается быстро и работает замечательно. Да, я бы тоже хотел сказать, что ситуация выглядит так, но, к сожалению, бесстрастная статистика говорит нам в том числе и об обратном. Например, если посмотреть не время получения первого байта. Это время установки соединения, прогрузки веб-движка. Оно может в среднем превышать 2,5 с. А если у вас еще нет ни одного байта, вам нечего отобразить, кроме какого-нибудь красивого спиннера или splash screen.

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

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

Систему Native Cache мы построили на самом нижнем возможном уровне. Он просто подменяет контент, который идет из запроса.

vhipfiqkzhbtdd8m1m-cjocucgw.jpeg

Таким образом мы не тратим дополнительное время на установку и перехват соединения, как это было бы в сервис-воркере. Чем сайт более SPA-oriented, тем больше контента мы можем предзакешировать. Чем он более SSR-oriented — тем меньше. Но наши измерения показали, что даже в случае тяжелых SSR-сайтов кеширование в Native Cache подресурсов, статических картинок, стилей позволяет сильно сократить время загрузки. А главное — сделать его максимально независимым от скорости сетевого соединения. Для остальных этапов мы тоже предложили решения, дополнительные оптимизации, связанные с нашим движком. На данный момент мы считаем, что проблему скорости загрузки, скорости показа контента мы очень сильно улучшили внутри нашего супераппа. Выбор веб-подхода был оправдан. Мы смогли решить те технологические проблемы, которые он за собой повлек.

Если бы мы интегрировались на уровне натива, доступ к нативным возможностям телефонов, аппаратов, планшетов, телевизоров был бы максимально простым. Но если мы говорим о вебе, то текущее W3C API, к сожалению, содержит не все возможные точки доступа к нативным возможностям. Мы провели брейншторм, собрали максимум возможностей, которые были бы полезны и удобны сервисам, приоритизировали их и постарались реализовать наиболее важные.

dnctjvs02mwhn7ggymgy6dag6ic.jpeg

Думаю, вы легко догадаетесь, какие оказались наиболее важными. Это вещи, связанные с авторизацией, с проведением платежей, с заполнением из профилей пользователей значений при оформлении заказа. Из дополнительных вещей, интересных и необычных, я бы отметил такую publisher specific identifier. Это возможность идентификации пользователя внутри одного publisher сервиса между устройствами.

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

Перейдем к следующей, достаточно интересной теме — UX.

UX супераппа. Айсберги на горизонте


Как должен выглядеть сервис внутри нашего супераппа? Сразу небольшой забег вперед, заглядывание в замочную скважину. Айсберги на горизонте. Все оказалось не так просто, как мы думали изначально. Сейчас расскажу, почему.

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

o3vgotb0n4woy-vw8tx0bkeerv8.jpeg

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

Но есть маленький подвох. Если мы выбираем этот путь, то начинаем отрисовывать этот элемент поверх веб-контента. Значит, мы можем конфликтовать с тем, что находится под этим элементом. Там тоже могут быть элементы управления. Это вроде бы очень небольшая область, сколько там, 50 на 100 пикселей.

Но как оказалось на практике, это очень используемая область в тех сервисах, которые хотели к нам въехать. Для них это была просто гигантская головная боль. Мы к ним приходили и говорили: интеграция практически элементарна, вам нужно написать манифест, в котором вы описываете ресурсы для хранения в Native Cache, использовать JS API, который предоставит вам возможности использования нативных элементов авторизации или платежей, и все будет замечательно. Мы забыли упомянуть, что нужно еще оставить небольшое место под наш нативный элемент. Сервисы начинали хвататься за голову: у нас там на тысячах страниц есть наши элементы управления, и мы будем переделывать это целый год.

Мы поняли, что если хотим, чтобы сервисы въезжали к нам быстро и удобно, нам нужно что-то делать и придумывать другое решение. Следующим решением было… возможно, кто-то уже догадался, поскольку в Яндекс Go вы это видели миллион раз. Шторки. То есть концепция следующая: контент выезжает в виде шторки, и эту шторку вы можете смахнуть после завершения работы или приспустить, чтобы получить доступ к дополнительной шапке — например, с элементами управления или с дополнительным описанием сервиса.

Тут, казалось бы, мы решили предыдущую проблему. Мы никогда не перекрываем контент сервиса, он может въезжать к нам без изменений внешнего вида. Но к сожалению, механика взаимодействия со шторкой рождает дополнительные проблемы. В первую очередь она конфликтует с pull-to-refresh. Стандартное движение, которое привычно пользователю для обновления контента: немного оттянуть контент — и магия, он начинает перезагружаться.

45erlifgevh7v2sh6nomyifqzj4.jpeg

Нам приходится отключать pull-to-refresh. Также бывают сложные скроллы внутри контента: вертикальные или горизонтальные галереи, а в самом тяжелом случае — карта. Это бесконечно скроллируемый контент. Вам нужно каким-то образом уметь взаимодействовать с этими картами, с такими бесконечными областями для скролла.

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

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

К чему мы пришли? Мы пришли к full screen-контенту с навигационной панелью, которая возникает снизу. Это очень похоже на веб-табы, которые и так уже существуют в браузерах, в том числе в Яндекс.Браузере и в приложении «Яндекс». Тут мы предоставляем сервису максимум области для контента. Мы не перекрываем его, но, к сожалению, у нас теряется та самая некая выделенность сервиса по сравнению с обычными веб-сайтами. То есть мы хотели предоставить ему дополнительный внешний вид, дополнительную изюминку. Но к сожалению, в этом решении мы от этого отказываемся. И за счет навигационной панели снизу начинаем немного подрезать видимую область сервиса. Он может предоставить своим пользователям чуть меньше контента, доступного при первом старте.

bv-rxm__lpx3i0p1r_ih0pecgro.jpeg

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

Веб в целом как суперапп


Отвечая на вопрос, поставленный в самом начале нашей беседы (почему супераппы мертвы и почему они все-таки продолжают здравствовать), к какой идеологии мы пришли в результате? Мы пришли к пониманию того, что веб сам по себе и есть суперапп. Когда вы пытаетесь ужать весь веб или сделать его аналог внутри вашего конкретного супераппа, вы ограничиваете этим и пользователей, и сервисы.

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

bbpbj7cxt3jelwol7wc7bp2hodw.jpeg

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

Нам важно предоставить сервисам наборы функциональности, которые они могут использовать опционально. Если им интересны нативные платежи или м интересна авторизация — они подключают соответствующие модули. Если хотят ускорить работу своего приложения внутри супераппа — подключают манифест и описывают свои ресурсы, чтобы они работали внутри Native Cache.

Последний и самый важный момент: мы хотим, чтобы наша экосистема, наш суперапп не был завязан на конкретное приложение, а был доступен из любого веб-браузера. Если сервис загружается внутри нашего супераппа, внутри поискового приложения «Яндекс» или Яндекс.Браузера, мы используем как раз все те оптимизации, о которых я рассказывал, чтобы сервис работал быстро и качественно. Мы используем Native Cache и дополнительное JS API, которое пробрасывает взаимодействие пользователя в нативные интерфейсы. Пример — нативная авторизация.

bzr02gkn4fwtgbf_eda3wq0ytis.jpeg

vraclq7u1uxcnyisqkjzk1mj0ls.jpeg

Мы используем дополнительные оптимизации на уровне движка веб-рендеринга. Но если пользователь заходит к нам через обычный внешний браузер, он по-прежнему может использовать те же самые возможности, которые реализованы другими средствами. Эти средства, может быть, менее эффективны, но при этом все равно реализовывают те возможности, ради которых пользователь приходил и ради которых сервис интегрировался в нашу экосистему. Мы можем использовать сервис-воркеры вместо Native Cache, использовать веб-реализацию JS API, который будет проводить это все через JS-средства и через веб-взаимодействие. И у пользователя будет возможность использовать нашу экосистему и входящие в нее сервисы через любой мобильный браузер, поддерживающий современные технологии.

Таким образом, наш суперапп вырастает из приложений, сбрасывает с себя оболочку нативного приложения и живет полноценно во всем вебе.

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

© Habrahabr.ru