Привет, я Андрей Кучеренко, тимлид мобильной разработки Skyeng. Мы делаем мобильные приложения под iOS и Android. У них одинаковая функциональность и одинаковый с точностью до стилистики интерфейс. Но из-за разных платформ разработка вроде бы одного приложения получается довольно дорогой. В поисках возможности сэкономить на мобильной кросс-платформенной разработке, мы опробовали четыре решения:


  • Объединение iOS- и Android-разработчиков в одну команду
  • Создание рабочих групп для решения сложных задач
  • Экономия на ведении документации
  • Написание общего кода

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


Объединение разработчиков iOS и Android в одну команду


Два года назад у нас было два отдельных мобильных приложения и две команды разработчиков, связанных только общим продакт-менеджером. Из этого вырастала куча проблем: приложения друг друга внешне напоминали лишь отдаленно, работали во многом по-разному, разработчики не имели представления о том, как устроено соседнее приложение, регулярно вылазили всякие баги и ошибки в логике. В определенный момент стало понятно, что продолжать так нельзя, и первое, что мы в этой связи сделали – объединили разработчиков iOS и Android в одну продуктовую команду, сделав ряд процессов общими.


Одним из таких процессов стало техническое ревью.


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


Как мы экономим на совместном техническом ревью:


  • в большинстве случаев получается одинаковое техническое решение для iOS и Android. Разные решения тоже возможны, это может быть обусловлено разной архитектурой платформ, но в контексте задачи разница чаще всего минимальна;
  • синхронизуется архитектура и структура двух приложений. Тем самым исключается ситуация, когда продакт приходит с очередной фичей, а мы iOS-задачу оцениваем в два часа, а Android – в неделю, потому что там вообще все придется переписывать;
  • чаще всего мы хорошо попадаем в оценку. Если у нас сильно отличаются оценки для платформ, это может говорить либо о том, что разработчики не поняли задачу, либо о каких-то проблемах платформы, на которые необходимо обратить внимание;
  • при таком ревью происходит обмен опытом между iOS- и Android-разработчиками, а я считаю, что они должны иметь представление о том, как работает соседняя платформа. Часто получается, что решение с одной платформы удачно и для другой;
  • упрощение ручного тестирования. Фичи реализуются на основании одного технического решения, если QA находит какие-то баги, то это повод повторить те же шаги на другой платформе. Чаще всего те же баги находятся и там;
  • универсальные солдаты, способные писать под обе платформы: если они есть, то можно их переключать между проектами, что повышает автобусный фактор и позволяет легко переносить отпуска и отсутствия. Не получается ситуаций, когда одна платформа в период отпусков убегает далеко вперед.

Автобусный фактор: количество человек в команде, которых должен сбить автобус, чтобы проект не мог дальше продолжаться.


Рабочие группы для решения сложных задач


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


Я проанализировал ворклоги на предмет распределения времени, которое тратится на написание кода, коммуникации, проектирование и research. Вот что получается для простых задач:



Здесь все понятно, в основном пишем код, затраты на него – до 80% времени.


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



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



Наконец, задачи, с которыми вообще непонятно, как подступиться, где надо сначала исследовать и проектировать:



Если работу над сложными задачами никак не координировать, то вся работа, не относящаяся непосредственно к написанию кода, будет делаться два раза. А в сложных задачах это по 50% времени решения, часто еще больше.


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


Рабочая группа – это несколько iOS- и Android-разрабочиков, которые будут заниматься непосредственно реализацией данной фичи. Один назначается ведущим, именно он будет отвечает за проектирование, research, взаимодействие с другими командами. Результатом его работы будет документация, где все зафиксировано; эти доки затем ревьювятся рабочей группой и тимлидом, и команда приступает к реализации.


В результате получили:


  • снизилась нагрузка на тимлида, при этом он не теряют контроль над ходом задачи. Я участвую во всех ключевых встречах, ревьювлю техническое решение, фактически контролирую задачу до того, как она попадает непосредствнено в разработку;
  • разработчики сильно замотивировались. Когда тестировали эту практику, все подходили и говорили «круто, давай еще попробуем». Не было таких, кто бы не хотел этим заниматься и предпочитал «просто кодить». У людей появилось больше возможностей для развития;
  • повысился автобусный фактор, команда стала более самостоятельной, плюс на таких задачах хорошо видно тех, кого дальше стоит развивать в тимлидов. Решается проблема с уходом тимлида в отпуск.

Экономия на документации


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


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


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


Общий код


Идея писать общий код не самая новая, существует куча инструментов, чтобы это делать. Мы пробовали C++ для написания библиотеки словарного тренажера, и у нас есть небольшое приложение, полностью написанное на Kotlin Multiplatform. Теоретически, при использовании инструмента кросс-платформенной разработки наши расходы на написание кода должны бы снизиться в два раза. Но появляются дополнительные:


  • расходы на старте. Массу времени придется потратить на то, чтобы это все собрать, запустить, протестировать, проверить гипотезы, обучить команду. В некоторых случаях эти расходы получаются такими большими, что профита не видно вообще;


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


  • устранение недоработок. Большинство инструментов все еще довольно сырые, в них есть баги, вам придется столкнуться с какими-нибудь ломающими обратную совместимость релизами, и на устранение всего этого тоже придется потратить какое-то время;


  • обход ограничений. У кросс-платформенных инструментов могут быть архитектурные или еще какие-то ограничения, в которые можно упереться и потратить время на их обход. Иногда такие ограничения оказываются настолько серьезными, что приходится вообще отказываться от инструмента. Так, например, Airbnb отказались от React Native и откатились назад к нативной разработке;


  • Усложнение разработки. Вам приходится или писать код под две платформы сразу, что не все умеют, плюс появятся дополнительные коммуникации. Отсутствие нативных IDE тоже не упрощает такую разработку.



Чтобы сравнить расходы на те методы кросс-платформенной разработки, которые мы попробовали, выделил четыре основные группы:


  • стартовые расходы
  • расходы на написание общего кода
  • расходы на написание платформенного кода
  • расходы на инфраструктуру (то, что не относится к первым трем пунктам)

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



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



Очень высокие стартовые, зато пока расходы на платформенный код и инфрастуктуру невелики. У нас не было достаточного для хорошего анализа количества задач, по текущему положению сэкономили 19%. Предположив, что мы сделаем очень много задач, и отбросив стартовые расходы, получим экономию порядка 40%, если, конечно, в дальнейшем не вылезет каких-то серьезных проблем. Еще один плюс – большинство разработчиков неплохо знакомы с Kotlin.


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


Итого:


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

Комментарии (4)


  1. Neikist
    26.06.2019 09:43

    Спасибо, было любопытно. Планирую котлин нейтив попробовать, хочется уточнить:
    1) Насколько больно жить без стандартной библиотеки java?
    2) Насколько сложно делать инетроп?
    3) В какой IDE пишете?


    1. akM12a Автор
      27.06.2019 12:03

      Добрый день,
      1. Полностью отказываться от стандартной библиотеки для всего приложения будет очень больно. А вот написать пару каких-то сервисов, нагруженных логикой — с этим ок.
      2. Идет с kotlin multiplatform из коробки
      3. idea для multiplatform проекта, xcode для iOS приложения, android studio для android


      1. Neikist
        27.06.2019 12:09

        Спасибо. На Kotlin MPP все же чаще отдельно выделенный человек пишет? Или эту роль на себя берет android/ios разраб который потом же для своей платформы и UI пишет? Или вообще для таких фичей подразумевается что в идеале один человек должен писать UI сразу под обе платформы и логику на kotlin MPP? Понимаю что скорее всего по разному в разных случаях, но как идеал видите?


  1. kubk
    27.06.2019 12:02

    Спасибо за анализ. Пробовали ли вы Flutter для кроссплатформенной разработки и если да, то чем не подошёл?