Натив или кроссплатформа? Детальный разбор простым языком

Натив или кроссплатформа? Детальный разбор простым языком

Статья о проблемах, возможностях и компромиссах в разработке мобильных приложений сквозь призму личного опыта. Flutter - хорошо всегда? Знакомый кодер порекомендовал React Native? Для всех интересующихся и далёких от программирования. За 10 минут мы научимся понимать ху есть ху во всей этой истории.

Терминология

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

SDK — software development kit — инструментарий разработчика. Говорят например, — AppStore SDK — набор инструментов для реализации платежей и подписок в приложении. Или Android SDK — совокупность более мелких SDK для разработки под всю платформу.

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

API — это программный интерфейс, (тяжело объяснять простыми словами оказывается). Руль — физический интерфейс к колёсам, коробка передач — к двигателю, мы дергаем за них, чтобы машинерия внутри сделала для нас более сложную работу через простой для восприятия интерфейс. Программные интерфейсы — наборы функций, объектов, используя которые программисты выполняют сложную работу более простыми действиями.

Истоки

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

Так или иначе, клиент любого бизнеса, пожелавшего открыть для себя вожделенную айтишечку, доступен через 3 окошка:

  • Окошко браузера — считай, в вебе. Так как мы говорим о платформах, то стоит упомянуть, что несмотря на некоторые различия браузеров и подходов к разработке, мы больше не рассуждаем о проблемах запуска веб-приложений в разных браузерах: десктопных, мобильных, от разных вендоров и тд.
  • Окошко приложения смартфоне/планшете. Зона с наибольшим трением. О ней и пойдет речь в статье.
  • Окошко приложения в настольной ОС соответственно. Рассматривать не будем. Или будем в другой статье, но если грубо прикинуть, то проблемы те же, что и на мобилках.

Также мы не рассматриваем устройства носимой электроники, интернета вещей, экранов холодильников, различных embedded систем — уж очень они специфичны.

Немного истории с погружением в детали

На заре широкого коммерческого успеха мобильных гаджетов, некто по фамилии Джобс, отстаивал идею о том, что персональный смартфон — это всего лишь окошко к всемирной паутине, которое всегда с собой. Круто же звучит! Вот что он говорил:

Полноценный движок Safari уже присутствует внутри iPhone. То есть, вы можете создавать изумительные Web 2.0 и Ajax приложения, которые выглядят и ведут себя так же, как родные программы iPhone. И они способны прекрасно взаимодействовать с его сервисами: звонить, отправлять электронные письма, разыскивать местоположение в Google Maps. И знаете, что? Для этого не нужен SDK! У вас уже все есть для написания невероятных приложений для iPhone, если вы знаете, как создавать программы, используя современные веб-стандарты.

Стив Джобс

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

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

-Нативное приложение — созданное с использованием инструментов разработки вендоров: Apple/Google и распространяемое через магазины приложений. Для разработки под Apple актуальны технологии: UIKit, SwiftUI + богатый iOS SDK, язык программирования Swift (и для особых случаев старичок Objective-C)Для Андроид соответственно — Android SDK, Jetpack Compose, языки: Java 8, Kotlin

Веб-приложение, использующее браузер в качестве среды выполнения и ограниченного доступа к ресурсам девайса (я специально не называю веб-приложение сайтом, так мы в терминах отделяем статические странички от динамичных, наполненных различной бизнес-логикой, приложений). К ним же относятся так называемые WebView — приложения, обернутые тонким слоем нативного кода, использующего SDK браузера для открытия веб-приложения, также распространяются через сторы.На ладан дышащие представители этого вымирающиего семейства — Apache Cordova и Ionic. Они не скрывают свое основное назначение — быстрое прототипирование приложений. Для них актуальны классические веб технологии — HTML, CSS, Javascript. Сюда же попадают поделки из no-code конструкторов типа GlideApps и его аналогов.

Оба подхода стоят диаметрально противоположно друг другу по ряду критериев:

  • Доступ к ресурсам девайса
  • Производительность вычислений
  • Возможности фоновой работы
  • Отзывчивость интерфейса и пользовательский опыт
  • Доступность продукта для пользователей с особыми потребностями
  • Скорость разработки и доставки обновлений, time to market
  • Сложность поддержки
  • Стоимость разработки

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

Гибридные, компилируемые в нативный код — приложения написанные с использованием сторонних инструментов разработки, языков программирования, которые имеют свой набор библиотек, связывающих программные интерфейсы платформенных SDK с собственными интерфейсами или полностью заменяющие их.

К ним относятся:

  • Flutter (Flutter SDK и язык програмирования Dart)
  • Xamarin (Xamarin Forms, .NET + язык C#)
  • Kotlin Multiplatform Mobile — (Инструментарий так и называется KMM, язык Kotlin соответственно)
  • QT6 — богатый инструментарий создания графических приложений для всего — от Windows до дисплеев на приборной панели авто (там он вообще стандарт де-факто). Язык C++

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

Типичные представители этого семейства: React Native, Native Script, Electron.

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

О технологиях и пользовательском опыте

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

  • Look-&-feel — преемственность внешнего вида, интуитивная адаптация на прежнем опыте: жесты, положение элементов управления и навигации и тд.
  • Производительность при выполнении задач пользователя — никто не любит долго ждать.
  • Отзывчивость интерфейса. Анимации, переходы между экранами, задержки в реагировании на прикосновения, физика скроллинга и тд.
  • Непрерывность работы. Вашего пользователя может бесить невозможность продолжать работу в приложении, если он отвлекся на Instagram, а вернувшись обратно, видит как приложение открывается заново со стартового экрана и сбросило текущий прогресс.
  • Интеграция в операционную систему. Когда ты видишь перед собой приложение, а оно ведет себя как сайт ничего не зная о возможностях ОС в которой работает.
  • Прожорливость до батареи и нагрев девайса (чатик поддержки в приложении Yota так люто накалял девайс и мое терпение, что пришлось перейти на другого оператора)
  • Доступность — экранные дикторы, голосовая навигация для людей с ограниченными возможностями — на поддержку этих функций, на старте разработки как правило кладут болт.

Глубинная проблема радикального ухудшения пользовательского опыта в приложении чаще всего - следствие появления большого числа прослоек между физическим железом и тентаклями наших пользователей. (Если не считать, что кое-кто мог люто наговнокодить). Эти прослойки программисты называют абстракциями - слоями, которые упрощают разработку в тех или иных местах. Аналогия из жизни, к примеру, электрическая розетка - абстрактный слой между чайником и электростанцией, ЛЭП, трансформаторами и тд. Однако, за подобные удобства надо платить и цена этой прослойки - потери электроэнергии по пути к розетке, которые включены в наш тариф. Если бы для нагрева чайника мы брали электричество непосредственно от электростанции ее добывающей, нам бы, во-первых, пришлось жить рядом, обзавестись набором специальных знаний и допусков, столкнуться со сложностями сопряжения интерфейсов раздачи и потребления. Собственно, эта аналогия работает и в предмете нашей темы. Чем более абстратна технология к физической платформе, тем больше функций нам придется реализовывать самостоятельно, чтобы привести пользовательский опыт к требованиям, которые эти треклятые пользователи и диктуют.

Говоря образно, по степени абстрактности к конечной мобильной платформе, технологии можно разделить так:

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

Гибридные - делят между собой оттенки серого:

  • Xamarin и Kotlin Multiplatform предлагают делать кроссплатформенной только логику приложения, оставляя реализацию UI нативным языкам и библиотекам. (Очень толковый подход)
  • Flutter в свою очередь - полностью абстрагирует UI: носит с собой движок для рисования, перекочевавший из браузера, собственная UI библиотека с основным упором на Андроидный look-and-feel, собственный язык программирования Dart - единственной целью жизни оказался flutter. Пытался заменить Javascript, но провалил состязание и решил быть похожим на все языки одновременно.
  • React Native занял положение между подходом Flutter и WebView. Это всё также UI абстракция с довольно компромиссной и спорной архитектурой. Для обеспечения работоспособности этой машинерии используется большое количество различных слоев абстрагирующих исходный код UI от платформы. Поэтому пользовательский опыт React Native приложений имеет больше сходств с работой в браузере. Вообще сама технология явилась решением проблем WebView приложений и в силу своих особенностей не переродится во что-то принципиально новое.

WebView приложения в обертке браузера - тут сплошные компромиссы. Увядающее направление куда никто с наполеоновскими планами не идет.

О возможностях, проблемах и компромиссах

Давайте добавим практических деталей в разбор технологий. Я предлагаю сузить обзор до нативных инструментов разработки и инструментов, абстрагирующих UI - Flutter & React Native. Эти технологии хайпуют, у всех на слуху, масса аутсорсеров вышли с ними на рынок. Ставьте плюс статье или пишите в комментариях, если хотели бы больше подробностей о Kotlin Multiplatform Mobile и Xamarin.

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

  • Скорость разработки, кратчайший time2market
  • Удешевление человекочаса на фичу
  • Консолидация экспертизы
  • Выявленные ошибки фиксятся сразу под все целевые платформы
  • Единство внешнего вида приложения (спорно)

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

Обсудим.

О нативе

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

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

Однако, (люблю когда есть "однако") прямо в данный момент, если приглядеться, опыт разработки под нативные платформы становится всё более унифицированным. Swift и Kotlin - языки-побратимы. Просто посмотрите простым человеческим взглядом на кусочки кода обоих языков. Сходство очевидно. Разработчики языков стремятся сгладить углы миграции программистов между языками.

Следующая хорошая новость - с выходом андроид фреймворка Jetpack Compose (недавно он получил стабильную версию и готов к использованию) мы вступили в эпоху унификации подходов к описанию интерфейсов. Совокупно с фреймворком SwiftUI от Apple можно считать и этот опыт стал переносим.

Сравните 2 кусочка кода, описывающих карточку с картинкой:

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

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

Команды нативных разработчиков часто разбавляют C/C++ программистами. Они пишут кроссплатформенные модули для разных задач в основном не связанных непосредственно с бизнес логикой.

О Flutter

На старте с нуля ему нет равных в качестве продукта к скорости разработки. 2-3 разработчика способны наковырять безумное количество фич в кратчайшие сроки и выпустить продукт. При этом look-and-feel, производительность будут более чем приемлемыми. Большое количество библиотек решат множество задач типовой функциональности. Я бы назвал flutter серебряной пулей, но... надо кое-что иметь в виду.

Технология предназначена для создания UI! Как и язык программирования Dart.

Скрин главной страницы сайта языка Dart.
Скрин главной страницы сайта языка Dart.

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

Выдержка из википедии в доказательство о том, что есть флаттер на самом деле:

Flutter is an open-source UI software development kit created by Google.

Поняли, да? UI SDK!

С толку сбивает тот факт, что на Dart и Flutter всё таки можно написать приложение целиком. Если суть вашего приложения - сходить за данными в интернет и вывести на экран - ни в чем себе не отказывайте. Мощность девайсов растет и круг возможностей для применения одного инструмента расширяется. Но забывать о существовании границ не стоит, как и рассчитывать, что абсолютно любая задача может быть решена с Флаттер (часто встречаю такое мнение). Впрочем, если уже начали педалить код и вдруг уперлись в ограничение - не беда. Тут как раз и приходит понимание, что этот фреймворк больше про интерфейсы. Докупаете экспертизу у нативных разработчиков и получаете платформенный код (по количеству целевых платформ), решающий вашу проблему. Некоторые комбинируют Flutter и KMM - получают многообещающие результаты. Так экспериментировать себе позволяют только мозговитые и очень любознательные ребята, в свободном плавании таких на рынке мало, ведь рубить надо в массу областей.

Второе, о чем следует знать, если вы утвердили дизайнеру 2 макета: для iOS (к примеру с соблюдением Human Interface Design Guidelines) и для Android (новомодный Material You) флаттер может немного разочаровать. Поддержка в одной кодовой базе 2х дизайн подходов - сущий ад. Во-первых, разница не только во внешнем виде, но и в навигации, организации компонентов - вы пишите 2 модуля с интерфейсом, обкладывая код условиями что для одной платформы, а что для другой. Во-вторых, готовые элементы интерфейса для iOS реализованы очень топорно и застряли в гайдлайнах iOS 12.

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

Подводя итог, Flutter - очень интересный инструмент, конкурирующий больше с React Native чем с кем-то еще. Подходит вам в том случае, если по задумке опыт использования UI должен быть общим для всех платформ.

О React Native (NativeScript)

Разработка с этим SDK мне всегда напоминала письмо из Простоквашино:

...то лапы ломит, то хвост отваливается. А на днях, я линять начал. Старая шерсть с меня сыплется, хоть в дом не заходи.. Зато новая растет - чистая -шелковистая.. Так что лохматость у меня повысилась.

Шарик и Дядя Федор

Тот самый случай, когда полировка и багфикс начинается с первых строчек кода. Чтобы сварить кашу из RN, которую можно пользователям подавать, придется нехило потрудиться. Команды разработчиков и тестировщиков в крупных RN продуктах, часто в 1,5 - 2 раза больше, чем там где пишут нативно. Логично, за одного iOS разработчика двух React-щиков дают. Отсюда беда - квалификация кадров, их пруд пруди, но прутся они сюда из веба, а туда, как известно, прутся толпы «вайтишков» из онлайн-школ, бродят как белые ходоки, с собеса на собес.

Что касается непосредственно скорости разработки, результат близкий к Flutter, но пресловутый платформенный look-and-feel будет полностью размыт ощущением взаимодействия с веб-приложением. Зачем он тогда такой нужен, спросите вы? У этой технологии самые богатые возможности по переиспользовани кода между мобильными и вебом. Насколько это хорошо единого мнения нет, Airbnb 5 лет тащили RN на своем горбу, так и не получив удовлетворительного пользовательского опыта приняли решение к переходу на натив - долго, дорого и больно. Coinbase пошли в обратном направлении и, похоже, довольны собой. Я скачал их аппку. Окно регистрации основательно прогрело девайс, сожрав 4 процента батареи прежде, чем я заполнил поля. Думайте сами.

React Native облюбовали изготовители умной электроники. Приложения для умного дома - сплошь на RN. Если у вас уже есть веб-приложение c React под капотом, вашим пользователям может оказаться полезным расширить опыт оффлайн возможностями, push-уведомлениями и прочим. Чем меньше логики содержит приложение (тоньше клиент) - тем больше смысла в этой технологии. Ну и прототипы, куда без них.

Напоследок

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

Вот список бед на кроссплатформе, которые на поздней стадии сожрут больше денег, чем на старте:

  • Уменьшить потребление памяти и пакета приложения
  • Избавиться он лагов анимации
  • Снизить влияние на батарею
  • Прокачать производительность
  • Отполировать тач-интерфейс
  • Техдолг. Кроссплатформенный код обрастает им значительно быстрее
  • Прикрутить функциональность с интенсивными вычислениями на процессоре или видеоядре
  • Ликвидация пойманных багов внутри кроссплатформенных библиотек. (Airbnb устав ждать багфиксы Facebook сама контрибьютила в исходный код RN и создавала сопутствующую инфраструктуру. А вам это надо?)
  • Кадры.
  • и это далеко не всё.

Беспощадная БигДата может показать, что надо всех уволить (зачеркнуто) подавляющее большинство платящих юзеров страдает на iPhone 7-8 от лагов и деваться будет некуда - придется вкладываться в оптимизацию.

Может показаться, что я особо топлю за натив, но это не так. Основная ниша Flutter и RN - клиенты к веб-сервисам, было бы глупо стрелять из нативной пушки по воробьям. Мой опыт программиста и IT менеджера подсказывает, что для амбициозных проектов, кроссплатформенной лучше делать бизнес-логику, как это предлагает Kotlin Multiplatform или Xamarin. Этот код, в отличие от кода UI на 100% под контролем разработчика. Впрочем это тема для совсем другой истории.

Дайте знать, если хотите продолжение про KMM и Xamarin, жду вас и ваши мнения в комментариях!

Канала в телеге нет, но если что, пишите в личку

Спасибо за прочтение!

66
Начать дискуссию