Хабрахабр

[Перевод] (Не очень) скрытые издержки общей кодовой базы iOS и Android

До недавнего времени у Dropbox была техническая стратегия использовать общий код C++ для мобильных приложений iOS и Android. Идея понятна: написать код один раз на C++ вместо его дублирования отдельно на Java и Objective C. Мы приняли эту стратегию ещё в 2013 году, когда группа инженеров мобильной разработки была относительно небольшой и приходилось быстро развивать продукт. Такое решение позволило выдавать большой объём кода как на Android, так и на iOS силами маленькой команды.

Решение связано с (не очень) скрытыми издержками на совместное использование кода. Теперь мы полностью отказались от этой стратегии в пользу родных языков каждой платформы (в первую очередь Swift и Kotlin, которые не существовали, когда мы начинали).

Издержки фактически помешали двигаться в этом направлении. Все проблемы вытекают из главного: оверхед оказался больше, чем просто написать код два раза.
Прежде чем анализировать различные типы оверхеда, хотелось бы пояснить, что мы так никогда не дошли до момента, когда бóльшая часть кодовой базы велась на C++.

Такие решения пока не очень распространены. Также стоит отметить, что гораздо более крупные компании, такие как Google и Facebook, уже несколько лет разрабатывают масштабируемые решения для совместного использования кода. Например, Airbnb отказалась от использования React Native во многом по тем же причинам, что изложены в этой статье. Хотя сторонние системы вроде React Native или Flutter позволяют избежать части накладных расходов, некоторые издержки всё равно остаются (по крайней мере, до тех пор, пока одна из этих технологий не станет популярной и не созреет в достаточной степени).

Все издержки можно сгруппировать по четырём основным категориям.

Оверхед пользовательских фреймворков и библиотек

Проще всего прогнозировать издержки на создание фреймворков и библиотек. Они примерно разбиваются на две подкатегории:

  • Фреймворки, которые позволяют взаимодействовать с хост-средой для создания полноценного мобильного приложения. Например:
    • Djinni, инструмент для создания межъязыковых объявлений типов и интерфейсов соединения
    • Фреймворк для выполнения задач в фоновом режиме против основного потока (тривиально на родных языках платформы)

  • Библиотеки на замену языковым стандартам или решениям open source, которые можно было использовать в родных языках, например:
    • json11 для (де)сериализации JSON
    • nn, ненулевые указатели для C++

Ничего из этого не нужно, если оставаться на родных языках платформы. И наше участие в проектах open source на родных языках, вероятно, принесло бы больше пользы разработчикам. В сообществе C++ культура open source была (и есть?) не так развита, как в сообществе мобильных разработчиков, тем более что мобильного сообщества C++ практически не существует.

При этом только у C/C++ есть компилятор, поддерживаемый как Google, так и Apple, поэтому переход на иной язык порождает целый ряд других проблем. Обратите внимание, что эти издержки особенно высоки для C++ (в отличие от других возможных неродных языков, таких как Python или C#), потому что здесь нет одной полнофункциональной стандартной библиотеки.

Оверхед нестандартной среды разработки

В мобильной экосистеме много инструментов для повышения эффективности разработки. Мобильные IDE очень функциональны, а Google и Apple вложили много ресурсов, чтобы сделать их идеальными на своих платформах. Отойдя от дефолтов, мы отказываемся от некоторых преимуществ. В первую очередь, отладка на родном языке обычно превосходит отладку C++ в IDE по умолчанию.

Такие ошибки трудно отследить даже с простым, стандартным стеком. Мне особенно запомнилась одна ошибка, которая вызывала блокировку фоновой потоковой структуры, что приводило к случайным сбоям приложения. Поскольку проблема включала отладку многопоточного кода, работающего между C++ и Java, на её отслеживание ушли недели!

Самое главное, требовалась кастомная система сборки для создания библиотек, которые содержат код C++, а также оболочки Java и Objective-C. В дополнение к потере стандартного инструментария, пришлось инвестировать время в создание своих инструментов для поддержки общего кода C++. Создание такой системы отняло у нас много ресурсов, поскольку её приходилось постоянно обновлять для поддержки изменений в двух системах сборки. Она должна генерировать цели, понятные и Xcodebuild, и Gradle.

Оверхед на устранение различий между платформами

Хотя iOS и Android являются «мобильными приложениями», которые обычно предоставляют одни и те же функции, в самих платформах есть определённые различия, которые влияют на реализацию. Например, как приложение выполняет фоновые задачи. Даже похожие вещи со временем могут начать сильно отличаться (например, взаимодействие с камерой).

Нужно потратить много времени на интеграцию и кодирование под конкретную платформу, и иногда этот код заканчивается прямо на уровне C++! В результате нельзя просто так написать код один раз и запустить его на другой платформе.

Теоретическая экономия от написания кода только один раз не соответствует реальности, что сразу сильно снижает эффективность этого подхода.

Оверхед на найм, обучение и удержание разработчиков

Последнее, но не менее важное, — это стоимость обучения и/или найма разработчиков для работы с нашим очень своеобразным стеком. Когда Dropbox начал использовать эту мобильную стратегию, у нас была основная группа опытных разработчиков на C++. Эта группа запустила проект C++ и обучила других мобильных разработчиков.

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

Оставалось только два варианта, и каждый требовал существенных усилий: В результате мы столкнулись с реальной нехваткой критических знаний для поддержания кодовой базы C++.

  1. Найти и нанять кандидатов с очень специфическим набором навыков (мы безуспешно пытались в течение года).
  2. Обучить собственных мобильных (или C++) разработчиков, что практически невозможно сделать в отсутствие сеньоров с нужным набором навыков для выполнения обучения. Даже когда основная группа ещё не разошлась, мобильные разработчики обычно не интересовались C++, поэтому поиск людей для обучения также представлял большую проблему.

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

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

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

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

Показать больше

Похожие публикации

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *

Кнопка «Наверх»