Сегодня только ленивый бизнес не мечтает о том, чтобы сэкономить ресурсы и время на создании ПО, а один из самых очевидных способов - кроссплатформенная разработка клиентов. Многие ищут этот философский камень, чтобы превратить две, а то и три команды, дублирующие друг друга, в одну.
Если смотреть со стороны разработки, я каждый раз хочу заплакать, когда вижу, как 2 или 3 независимые команды реализуют одну и ту же фичу. А если при этом у разных команд имеют место сложные решения с похожими багами, то начинаю рыдать в голос.
На сегодня существует несколько решений, которые позволяют уменьшить дублирование и делать кросс-платформенные решения, но ни одно из них пока не стало стандартом де-факто. Опытный разработчик может возразить, что стандарт – это утопия и этого никогда не будет, но существуют примеры решений, которым индустрия сказала единогласное "да": Linux, Git, Docker и прочие.
Наверное, самый старый из подходов, надежный, но явно не самый простой.
Однажды я курировал попытку сделать такой клиент, и первое с чем я столкнулся – было непросто найти разработчиков. Также очень много вещей, к которым мы привыкли в других инфраструктурах, отсутствуют в библиотеках и тулинге.
Сегодня по своей воле я бы такой путь точно не избрал, слишком он тернист. К тому же многие просто не хотят писать на C++, и я их не осуждаю.
Dropbox, избравший подобный подход в 2013 году, в 2019 решил от него отказаться. Если кратко, то они пробовали общие вещи писать на C++, но столкнулись с такими проблемами:
Разница в платформах докатилась и до общей C++ библиотеки, что заметно усложняет жизнь. В итоге по словам Dropbox все бонусы от переиспользования фактически сведены на нет. Подробнее об их опыте можно прочитать здесь.
Судя по коду мобильных клиентов, Telegram тоже использует этот подход. Но на мой вкус их клиенты написаны очень специфически. В коде Android-клиента несколько раз замечал места, которые кажутся намеренно частично обфусцированными. Если так, то все нормально.
Продуктово Telegram очень крутые, но технически много вопросов. В их решениях почти все кричит о том, что они "гениальные математики". Вот, к примеру, весьма убедительная критика их протокола.
В этом подходе вы по сути пишете React-приложение. React Native запускается в фоновом потоке, интерпретирует ваш JavaScript-код и обеспечивает взаимодействие с устройством.
Airbnb в свое время была одной из первых компаний, кто стал серьезно использовать ReactNative в продакшн. Это было в 2016 году.
А уже в 2018 они выпустили серию статей, где говорят, что отказываются от этого фреймворка в пользу нативной разработки по ряду причин. Но при этом не оставляют утопичных мыслей о единой кодовой базе для нескольких платформ, намекая на другие набирающие популярность решения.
Среди известных приложений, целиком или частично написанных на React Native, можно отметить клиенты Instagram и Skype.
Почти нет больших приложений или компаний, кто бы сделал ставку на этот фреймворк. Единственный известный мне пример – Untappd (социальная сеть пива).
То есть на этого "белого боксера" я бы тоже не ставил.
Xamarin имеет в своем портфолио достаточно успешные приложения. Например, американский UPS.
Или мой любимый менеджер паролей Bitwarden, который я часто использую в смартфоне, и не испытываю никакого негатива.
Но многие отмечают сложность поддержи и постоянную борьбу с ветряными мельницами в софте на стыке Xamarin и нативных платформ. Однако если вы хорошо знакомы с C# и .Net инфраструктурой, то вполне можно попробовать использовать для прототипа или MVP.
Разработанный Google фреймворк позволяет писать приложения на языке Dart, который рендерит UI не нативными средствами платформы, а своим способом, написанным на C++, подобно игровым движкам.
Технологию начинают адаптировать большие игроки (Yandex, Alibaba и другие), хотя инфраструктура, откровенно говоря, сыровата и все нужно реализовывать с нуля. Google продолжает активно развивать этот подход, довольно успешно вливая ресурсы в маркетинг.
Среди успешных кейсов Google Ads, Яндекс.Лавка, eBay Motors. Или вот Meduza не так давно сделала новое приложение целиком на Flutter.
Есть разные мнения на счет Flutter. Наш Lord & Saviour Джэйк Уортон на эту тему высказался так. А еще помню читал его мысли о том, что мимикрировать под каждую из платформ – дорога в никуда.
Моя экспертиза во Flutter заканчивается на запуске простых hello world'ов и demo.
Но так как эта платформа сейчас на подъеме, то я попросил помощи у эксперта в этой области @otopba1. Спонсором дальнейших твитов о Flutter является именно он, за что ему большое спасибо.
Как известно, флаттер старается стать супер сверх решением, на всех платформах от часов до телевизоров. Настолько гугл топит за эту идею, что на одной из своих презентаций они показали Flutter Octopus, возможность запуска и дебага кода сразу на нескольких девайсах.
Это конечно круто, но весь код обрастает условиями типа Platform.isAndroid.
Часть методов из библиотек и фреймворка работают только на определенных платформах, а часть вовсе кидают исключения, если вызывать на не предназначенной платформе.
Flutter активно растет. Это круто. Но вместе с количеством новых фич появляется неимоверное количество багов.
https://github.com/flutter/flutter/issues
Постоянно вылезают баги совершенно разного рода, начиная от нативных крашей, заканчивая вечно поломанными шрифтами на iOS.
Пишешь на flutter более-менее крупное приложение? Будь готов контрибьютить во flutter-плагины. Это такой репозиторий с самыми основными библиотеками, вроде работы с пушами. Большая часть плагинов имеет версию 0.x.
Вам постоянно придется форкать и дописывать библиотеки. А если ваша библиотека работает с фичами платформы, будьте добры еще написать платформенный код, кроме dart.
https://github.com/flutter/plugins
Если вы думаете, что вы сейчас напишите все недостающие фичи основных плагинов, закинете пул-реквест и весь такой в золотых доспехах и на коне въедите в master ветку, вы ошибаетесь.
Команда flutter мастерски игнорирует пул-реквесты. Иногда создается впечатление, что команда гугл принимает только реквесты длиною не более 5 строк. Пул-реквесты висят годами, в комментариях уже появляются свои приколы.
https://github.com/flutter/plugins/pull/1721
Индексация постоянно отваливается, студия жрет гигабайты памяти, gradle порой впадает в бесконечную синхронизацию и другие увлекательные моменты из жизни Flutter разработчика.
Во Flutter виджеты бывают иммутабельные (StatelessWidget) и мутабельные (StatefulWidget). Идея StatefulWidget в том, чтобы не перерисовывать лишний раз экран, если состояние не поменялось.
Но рано или поздно каждый Flutter разработчик приходит к тому, что каждое обновление одного виджета перерисовывает весь экран.
И в этот момент начинается обмазывание кода проверками когда обновлять виджет, когда не обновлять, прикручивание очередного фреймворка или написание своего подхода к менеджменту состояний.
Dart вроде типизированный язык, а вроде и нет. Компилятор не будет ругаться если вы забудете где-то сделать return или не укажите тип объекта. IDE вам тоже не всегда подскажет.
Как бы flutter не прикидывался нативным приложением, все равно физика, отображение системных элементов и прочее отличается от нативных.
Периодически возникает ощущение, что у вас в руках какая-то подделка, а не настоящее приложение. Команда flutter постоянно улучшают поведение фреймворка, но ощущение, что никогда не достигнут совпадения 1 в 1.
Dart это однопоточный язык. Круто что ты вроде можешь делать какие-то операции прямо в основном потоке и вроде это даже никак не влияет. Но это только на первый взгляд.
В какой-то момент приложение обязательно начнет лагать, придется выносить тяжелую работу в отдельные изоляты и в целом следить за выполнением тех или иных методов.
Это вот мы такие молодцы и все сделали аккуратно. Но я напоминаю, что большая часть библиотек версий 0.x и там далеко не все ребята обеспокоены скоростью работы вашего приложение.
действительно cross-platform
быстро развивается
большое комьюнити
заливка кода на лету работает очень быстро
можно легко и быстро прототипировать, ui делается удобно
очень быстрые и удобные в использовании анимации
Dart супер простой язык
вместе с flutter идёт большой набор инструментов: для профилирования, инспектирования верстки и тп
не обязательно писать полностью приложение на flutter. Можно встроить кусок flutter в натив или наоборот
Kotlin MultiPlatform – это наиболее разумный подход к cross-platform.
Он лишен большинства недостатков других подходов, самые явные из которых:
При этом подходе UI остается нативным для платформы. Работа с компонентами системы, датчиками и прочим тоже нативная.
А все остальное при желании можно вытянуть в общие модули:
Это не так просто, как кажется. Чтобы построить такое приложение, надо довольно четко понимать как строить common library, какие вещи выносить в expect/actual, как осуществлять взаимодействие суб-компонент.
Собственно на этом и зарабатывает консалтинг-компания, евангелист KMP – Touchlab https://touchlab.co
Но, если вы хоть раз делали библиотеку/sdk, которая использовалась для разных клиентов (пусть и одной платформы), то вероятно больших проблем для вас это не составит.
Большим камнем преткновения был различающаяся для JVM и Native Memory Model. Из-за этого была принята суровая thread-confined frozen
concurrency. Но не так давно команда Kotlin объявила об изменениях, и вскоре сделают по-другому.
О подробности нового подхода к Memory Management можно почитать тут
blog.jetbrains.com/kotlin/2020/07/kotlin-native-memory-management-roadmap/
medium.com/@kpgalligan/kotlin-native-concurrency-changes-bbb1a5147e6
Самый большой недостаток KMP – это то, что подход еще очень сырой и immature. Но уже сейчас Cash App от Square написана с таким подходом. Да и ряд других приложений: Space от JetBrains, VMWare и прочие.
Я бы хотел использовать общую логику и сущности между мобильными и веб-клиентом. Но с вебом в этом подходе пока все не очень хорошо. Видимо, очень мало ресурсов на это выделено, все брошено на мобильные платформы.
Вы можете компилировать все это в JavaScript и запускать, как это сделал Jake Wharton в https://github.com/JakeWharton/SdkSearch. Но вы не можете использовать этот подход для встраивания в другие frontend-фреймворки. Точнее можно, но только для внутренних нужд и суровых админок, где огромный bundle не играет роли.
Мне бы хотелось скомпилировать common library с логикой и просто заимпортить в существующем Vue или React проекте, чтобы делать вызовы. Но сейчас это не так просто.
Вот тут немного говорят о том же.
Довольно стремительно развиваются различные библиотеки, чтобы сделать жизнь в KMP-инфраструктуре попроще: Ktor (http-client & server), Serizalization (с поддержкой JSON, Protobuf, CBOR), и другие.
Но больше всего мне нравится SqlDelight – библиотека для работы с базой. До встречи с ней Room мне казался прекрасным, но сейчас SqlDelight кажется более удобным, продуманным и feature-rich инструментом.
Священный Грааль пока не найден. Но многие очень сильно стараются, чтобы сделать хорошее решение в направлении cross-platform. Ну, а кто победит – время покажет.
Я лично склоняюсь к решениям типа C++ или Kotlin, когда UI и логика живут отдельно. Кажется, что это наименьшее из зол на средней и длинной дистанциях. Само собой, с явным предпочтением в сторону Kotlin.
Решения типа Flutter заманчивы, но не хочется тратить силы на борьбу с ветряными мельницами на стыке технологий. Хотя знакомый из HoReCa сказал, что их "мобильщики" счастливы после перехода. Да и @otopba1 кажется вполне довольным от использования.
30.10.2020