Кроссплатформенная разработка
Готов ли Kotlin Multiplatform к проду на iOS?
Как и в случае с любой другой технологией на грани возможного, осторожность всегда полезна.
Kotlin Multiplatform (или KMP, KMM и т. п.) уже несколько лет широко используется в продакшен приложениях. JetBrains создала веб-сайт со списком компаний, которые в настоящее время используют KMP.
Мультиплатформенная разработка
С момента появления мобильных платформ, которыми мы пользуемся сегодня, рынок всегда проявлял определенный интерес к продвижению мультиплатформенных технологий, таких как Cordova, Xamarin и другие. С большим или меньшим успехом эти технологии были нацелены на создание единой платформы для разработки нескольких кодовых баз, в основном фокусируясь на аспекте ценообразования (создать код один раз, развернуть несколько раз).
Однако стоимость — не единственный аспект, который может выиграть от поддержки единой кодовой базы:
- Повышение качества: единую кодовую базу легче поддерживать и проверять. Больше не нужно разрабатывать несколько вариантов для развертывания на нескольких платформах, поэтому некоторые задачи, например, устранение ошибок, становятся проще.
- Один технологический стек: найм в сфере технологий, как правило, является сложной задачей. Трудно найти Senior-инженеров, их сложно убедить перейти из одной компании в другую, если не предоставить достойный оффер. Единый технологический стек позволяет вашей компании сосредоточиться на технологическом стеке, с которым проще нанимать и который проще поддерживать.
- Функциональные команды: общий подход к мобильным устройствам заключается в разделении команд по платформам (iOS, Android). Вместо этого интересным подходом является создание функциональных групп, которые могут сосредоточиться на заданной функции и ее разработке. Это интересный долгосрочный подход, который можно использовать в определенных обстоятельствах. Использование единого стека технологий делает этот подход возможным.
У KMP хорошая кривая внедрения в Android-командах, поскольку язык и большая часть инструментов являются общими. JetBrains провела опрос об использовании Kotlin Multiplatform, и результаты вполне удовлетворительны. Например:
Было бы интересно получить разбивку удовлетворенности на основе платформы, на которой использовался KMP. Так, я подозреваю, цифры были бы другими. В частности, разработчикам iOS, похоже, труднее работать с KMP по целому ряду причин.
Этот статья показывает недостатки текущего применения KMP в проде на iOS. KMP — это динамичная технология, которая постоянно развивается (а JetBrains — это компания, которая прислушивается к своим пользователям при выпуске нового программного обеспечения), поэтому, если вы в конечном итоге читаете эту статью, имейте в виду дату, когда она была написана (май 2022 года).
Проблемы Kotlin Multiplatform на iOS
Давайте остановимся на неполном списке некоторых основных проблем при использовании KMP на iOS.
Отладка в iOS
В настоящее время у нас есть в основном два варианта отладки кода на iOS: мы можем использовать плагин Xcode Kotlin от Touchlab (который можно установить в Xcode) или Kotlin Multiplatform Mobile для AppCode (который можно установить в AppCode).
Touchlab — фантастическая компания, которая делает много хорошего для сообществ Kotlin и KMP. Плагин Kotlin для Xcode не идеален, и никто этого не ожидает. В настоящее время сообщается о проблемах с автодополнением, сбоях с различными версиями Xcode и многом другом. Это в самой природе стороннего плагина, разработанного для языка и стека, которые изначально не поддерживаются Apple в своей среде (и, вероятно, никогда не будет).
AppCode — это IDE JetBrains для разработки приложений на Swift, и, возможно, это лучшая IDE, чем та, которую предоставляет Apple. До недавнего времени Xcode не мог рефакторить код Swift, тогда как AppCode могла. Она имеет лучшие инструменты, интерфейс и многое другое. С другой стороны, это не официальная IDE от Apple, и в ней отсутствуют некоторые другие вещи, например, дизайн интерфейсов. На сегодняшний день нет идеальных решений, и отладка KMP на iOS по-прежнему болезненна.
Функциональная совместимость через Objective-C
KMP взаимодействует с iOS через Objective-C, а не Swift. Для этого используется инструмент Cinterop. Это означает, что если что-то не поддерживается в Objective-C, то уже не имеет значения, поддерживает это Swift или нет. И этому есть немало примеров. Например, исчерпывающие перечисления, аргументы по умолчанию и прочее.
Исчерпывающие перечисления
Перечисления (Enums) в Objective-C представлены как целые числа, а не как ссылочные типы в Kotlin. Если вы попытаетесь сделать switch для Enums в Swift, это будет похоже на применение switch к любому другому классу — Swift не знает, что существует конечное количество экземпляров для этого Enum, как это знает Kotlin. Есть готовый Feature Request на YouTrack, поэтому, если у вас есть интерес, не стесняйтесь взглянуть на него.
Аргументы по умолчанию
Аргументы по умолчанию (или аргументы) в Swift возможны. Например, следующая функция предоставляет аргумент по умолчанию:
Если мы не укажем параметр nice, вместо него будет взято значение по умолчанию:
Почему мы не можем использовать их в KMP, если Swift поддерживает аргументы по умолчанию? Потому что (опять же) интероперабельность идет через Objective-C. Таким образом, аргументы по умолчанию нельзя использовать при работе с артефактом, сгенерированным KMP для iOS. Вместо этого необходимо указать аргументы.
Отсутствие поддержки со стороны некоторых API
Codable — это API, представленный в Swift 4 и используемый для сериализации и десериализации данных, например, в формате JSON или из него.
Kotlinx.serialization предоставляет эту функциональность для Kotlin, но вы не можете напрямую сгенерировать реализацию Codable при экспорте классов Kotlin в Swift (опять же, есть запись в YouTrack). Хотя технически возможно постоянно использовать kotlinx.serialization, было бы разумно ожидать реализации Codable от самого KMP, являющегося базовым фреймворком для iOS. Можно представить команду Swift-разработчиков, у которых будет много сомнений по поводу принятия KMP, если они не смогут использовать Codable.
Поддержка нативных зависимостей ограничена
Kotlin/Native обеспечивает интеграцию с менеджером зависимостей CocoaPods через плагин CocoaPods и инструмент Cinterop. Однако если у вас есть зависимость, которая также зависит от другой библиотеки, в настоящее время она не поддерживается KMP (тикет YouTrack).
Сложная модель параллелизма
Модель параллелизма и управления памятью в KMP сложна, и в конечном итоге кажется, что она взаимоисключающая для iOS и Android. Нередки случаи, когда изменения приводят к сбою той или иной платформы. До недавнего времени корутины фактически были однопоточными, и это изменилось только с появлением 1.6.1-native-mt месяц назад.
Вопрос о том, как работают замороженные объекты и как работать с immutable объектами, быстро развивается и вскоре может превратиться в сложную задачу.
Готов ли тогда KMP к проду?
KMP готов, и это подтверждают кейсы JetBrains.
Как и в случае с любой другой технологией на грани возможного, осторожность всегда полезна. KMP опирается на слишком много краевых случаев и платформ, над которыми JetBrains вообще не имеет никакого контроля. Поэтому можно ожидать, что версии ваших приложений будут ломаться с выпуском новых версий Android или iOS, а также новых версий Swift.
Со временем мне удалось собрать контрольный список, который я стремлюсь использовать в любом проекте, прежде чем развертывать KMP:
- Используйте его с осторожностью: нет необходимости идти ва-банк с KMP. Модульный проект позволит вам проводить эксперименты с меньшими модулями и оценивать, сможете ли вы извлечь выгоду из KMP или нет.
- Общие компоненты: скорее всего, ваша цель использования KMP состоит в том, чтобы обмениваться компонентами между платформами, поэтому перед началом его использования проверьте, какие компоненты удобнее использовать совместно в вашем проекте. Определение кодовой базы, которую можно расшарить (и впоследствии определить, был ли KMP полезен или нет) — это мягкий и продуманный подход.
- Помните о версиях: Kotlin/Native изменили версионность в какой-то момент истории, и теперь версия привязана к версии самого Kotlin. Тем не менее, JetBrains поддерживает сайт со стабильностью Kotlin Components, и на сегодняшний день некоторые компоненты Kotlin/Native являются бета-версиями. Примените здесь собственную казуистику и определите, достаточно ли стабильности KMP для вашей организации.
Спасибо команде JetBrains из Мюнхена, которая всегда так полезна с обратной связью и поддержкой.