Влияет ли размер команды или приложения на процесс выпуска? Смотря как. Представим себе стартап с одной небольшой командой. В этом случае команда обычно делает фичу, а затем просто выпускает ее. Теперь давайте представим себе большой проект, например банковское приложение, над которым работает множество команд.
В этом случае, вероятно, должен быть процесс, циклы выпуска и, возможно, некоторая бюрократия. Без этого будет хаос.
Итак, когда станет ясно, что пора настроить такой процесс для вашего приложения?
В этой статье я поделюсь своим опытом реализации Release Train для приложения Dodo Pizza (Android и iOS) и проблемами, с которыми мы столкнулись, из-за которых наша команда реализовала Release Train.
Если вы являетесь руководителем группы или техническим руководителем проекта Android или iOS, который быстро развивается, и вы еще не руководили процессом выпуска, я надеюсь, что наш опыт вам поможет.
В 2021 году мы уже использовали в наших командах подход Trunk-based Development (TBD). Мы включили в код переключатели функций, декомпозировали задачи и провели модульные тесты и тесты пользовательского интерфейса. Наши функциональные ветки прожили недолго, и у нас работала CI.
Процесс выпуска был очень простым: тот, кто был готов выпустить свою функцию, выкатил ее.
Вот примерно как выглядел рабочий процесс нашего филиала. Несколько команд (серая, синяя, оранжевая и зеленая) работали над разными функциями. Поскольку мы работали в соответствии с TBD, каждая функция могла проходить через несколько последовательных ветвей.
Например, серая команда выполнила свою функцию за 4 шага, синяя и оранжевая команды сделали свою за 1 шаг, а зеленая команда сделала свою за 2 шага.
Когда команда завершила работу над функцией, она могла выпустить релиз. Например, если синяя команда завершила работу над функцией, они могут выпустить релиз. Затем оранжевая команда заканчивала работу и выпускала еще один релиз.
У нас был идеальный поток, как тогда казалось. До определенного момента всё работало отлично, но всему хорошему когда-нибудь приходит конец.
Что-то пошло не так: сложно, многолюдно и непредсказуемо
Первая проблема, с которой мы столкнулись, заключалась в том, что релизы начали накапливать много функций и стали слишком большими.
Команды не всегда хотели сразу выпускать свои функции. Процесс выпуска и регрессии был трудоемким и занял 3–4 дня. Таким образом, если ваша функция была небольшой и несрочной, вам не всегда удавалось выпустить ее самостоятельно, потому что, вероятно, какая-то другая команда скоро выпустит релиз, и она будет включена в этот выпуск. Примерно это выглядело так:
Это была довольно хрупкая договоренность, особенно когда количество команд начало расти. Многие команды разработали множество мелких функций, и общий объем нового кода в каждом новом выпуске становился огромным. Когда кому-то приходилось выпускать свою большую функцию, ему приходилось выпускать вместе с ней целого мамонта .
Гигантские релизы привели к:
Нам нужно было сделать так, чтобы даже если сине-оранжевая команда из примера не захотела выпускать релиз, релиз как-то состоялся.
Каждая команда уникальна, и каждая функция уникальна. Иногда случалось так, что несколько команд заканчивали работу примерно в одно и то же время. При этом было много «подождите меня, я завтра утром солью, обещаю!» происходит вокруг.
В конечном итоге такие узкие места привели к:
Нам нужно было внести два важных изменения:
Выпускающей команде не нужно никого ждать;
каждая другая команда должна знать, когда ожидается следующий выпуск.
Представьте себе, синяя команда сделала небольшую функцию и ожидает, что оранжевая команда скоро ее выпустит. Но что-то пошло не так, и оранжевая команда не выкатила релиз тоже из-за каких-то собственных проблем.
В результате синяя команда сообщила бизнесу, что эта функция скоро будет запущена в производство, но оказалось, что это произойдет недостаточно скоро. В результате невозможно предсказать, когда эта функция будет запущена в производство.
Это не означает, что синяя команда безответственна. Если у них есть супер важная или срочная функция, то они, конечно, сами ее выпустят. Но в других случаях невозможно точно сказать, когда эта функция станет доступна пользователям.
Как вы можете догадаться, мы сталкивались с такими проблемами довольно часто. Нам нужно было иметь возможность точно сказать, когда клиенты получат новую функцию в производство, независимо от ее размера или срочности. Все три проблемы (гиганские выпуски, узкие места и отсутствие предсказуемости) тесно связаны и дополняют друг друга.
Однако, вероятно, самым фундаментальным и важным из них является отсутствие предсказуемости. Это порождает другие проблемы.
С нас достаточно; пришло время внести изменения. Release Train должен был помочь нам в этом.
Термин Release Train означает разные вещи: запланированный процесс выпуска или выделенная команда , которая управляет процессом выпуска. Здесь мы поговорим о запланированном процессе выпуска.
Мне нравится, как Release Train описан Мартином Фаулером в статье « Шаблоны для управления ветвями исходного кода », а также определение, данное Thoughtworks на их техническом радаре (возможно, оно тоже принадлежит Мартину).
Вот как мы определили для себя Release Train:
Release Train — это процесс координации релизов между командами. Все выпуски происходят по фиксированному графику, независимо от того, готовы ли функции или нет. Поезд никого не ждет. Если вы опоздали, вам придется дождаться следующего.
Давайте разберем это на нескольких примерах с использованием наших команд с цветовой кодировкой.
Release Train происходит по расписанию и не зависит от того, кто что сливал в основную ветку. В приведенном ниже примере будут реализованы функции синей и оранжевой команд. Остальные будут ждать следующего поезда. Мы могли бы подождать еще немного, но тогда мы получим мамонта.
В то же время Release Train помогает нам более эффективно планировать нашу работу. Допустим, синяя команда изначально планировала закончить какую-то функцию позже. Но поскольку дату релиза знают все, они могут немного изменить свои планы, чтобы закончить эту функцию раньше.
Или, наоборот, они могут понять, что точно не успеют на следующий поезд, и, следовательно, могут безопасно завершить функцию, потому что знают все расписание.
В приведенном ниже примере синяя команда хотела добраться до релиза и объединить все свои изменения до релиза. В противном случае могло возникнуть узкое место.
Самое главное, что Release Train обеспечил нам предсказуемость благодаря замыслу .
Кому-то эти примеры могут показаться очевидными, но мы решали проблемы по мере их возникновения. Когда проблем с релизами не было, мы не заморачивались с использованием Release Train. Когда проблемы накопились, мы поняли, что время пришло.
Первое, что мы сделали, это написали RFC . RFC относится как к самому процессу, так и к проектному документу, который многие компании используют перед началом работы над проектом. Некоторые используют конкретно RFC, некоторые используют ADR, а некоторые просто называют их более общим термином «Проектный документ».
В Dodo Engineering мы используем как RFC, так и ADR.
Наш процесс RFC выглядел так:
Мы разработали документ RFC;
мы обсуждали это в небольшой группе, собирали комментарии и вносили коррективы;
затем RFC был передан более широкой группе;
затем мы это реализовали;
после этого мы собирали отзывы, отслеживали показатели и оценивали результаты.
Структура документа RFC для нашего Release Train была следующей:
При составлении RFC мы опирались на опыт других компаний:
Сначала мы придумали этот процесс:
1 iOS-разработчик и 1 Android-разработчик из одной из функциональных команд;
2 инженера по контролю качества.
Схематически наш Release Train выглядел так:
Через месяц стало ясно, что хотя первый опыт и был отличным,
В 2021 году наш регрессионный тест занимал в среднем 3–4 дня. В 2022 году нам удалось сократить его до 2–3 дней, но иногда он превышал этот срок. Мы продолжали покрывать случаи регрессии с помощью e2e-тестов, но пока не добились 100% покрытия. У нас было около 70% и 60% покрытия случаев регрессии на каждой платформе соответственно.
Вывод из этого заключается в том, что пока у вас есть регрессионные тесты, выполнение которых занимает несколько дней, скорее всего, будет неудобно запускать цикл выпуска каждую неделю.
В итоге мы перешли на двухнедельные циклы выпуска, и теперь Release Train выглядит так:
1 iOS-разработчик и 1 Android-разработчик из одной из функциональных команд;
2 инженера по контролю качества.
Вот как выглядит процесс, если все идет по плану:
Все это выглядит как еженедельный цикл, за исключением того, что остается достаточно времени для потенциальных исправлений. Вот как это будет выглядеть в случае расширенных регрессионных тестов:
Ничего страшного; еще есть время даже для исправлений.
Главной целью для нас было повышение предсказуемости . Его можно разбить на две части:
Мы ответили на вопрос «Когда будет релиз?» путем реализации процесса Release Train. Теперь каждая команда сможет ответить на вопрос «в каком выпуске появится моя функция?» независимо в тот момент, когда они планируют и оценивают функцию.
Раньше нельзя было сказать наверняка, потому что другая команда могла сделать релиз, а могла и не сделать. Теперь все зависит только от собственного планирования этой команды.
Чтобы еще раз подтвердить это, мы провели опросы среди мобильных разработчиков, специалистов по контролю качества и менеджеров по продуктам, в которых, наряду с другими вопросами, мы задали:
Release Train также помог нам с зависанием кода и выпуском. У нас их было несколько, помимо Нового года (например, 1 сентября и некоторые праздники). Теперь, благодаря Release Train, нам не нужно подстраиваться под эти даты, создавая ветки релизов, регрессивное тестирование и всё такое. Релизы работают по графику; мы просто открываем их в магазинах позже.
Помимо решения проблем, мы также измеряли показатели. Давайте рассмотрим основные из них.
Первым важным показателем, который мы измерили, было время выполнения проекта .
Вот как выглядит график. Стрелкой я отметил точку, когда мы начали процесс Release Train.
График показывает, что время выполнения заказа сократилось примерно до шести дней. Шесть дней – это много или мало?
Есть
Я считаю, что для стандартных мобильных приложений время выполнения в идеале должно составлять половину цикла выпуска. Это эквивалентно ежедневному добавлению задачи в основную ветку. При этом, если цикл выпуска составляет 14 дней, время выполнения должно стремиться к 7 дням .
Еще один показатель, который мы отслеживаем, — это количество ошибок на регрессию. Он описывает, насколько стабилен кандидат на выпуск. Если предыдущий выпуск был выпущен очень давно, то мы, вероятно, создали много нового кода, который потенциально может содержать большое количество ошибок, и мы могли бы потратить больше времени на регрессию и исправления.
В какой-то момент этот показатель сократился до трех ошибок. Конкретные цифры не так уж важны, но в целом видно, что тенденция пошла на спад.
Я кратко расскажу, какие показатели также отслеживались в рамках Release Train.
Нам нравится текущий процесс, поскольку мы считаем, что он достиг своих целей. Мы также знаем, как его улучшить:
Хотя мы были относительно небольшими, нам не нужен был Release Train. Когда мы столкнулись с тем, что не можем предсказать выпуски, их размер и количество, мы решили реализовать Release Train. Сначала мы пробовали еженедельные циклы выпуска, но из-за трудоемких регрессов нам пришлось перейти на двухнедельные циклы выпуска. С тех пор мы живем так.
Теперь у нас есть предсказуемость релизов, а метрики показывают положительную динамику. Мы планируем увеличить охват регрессионных случаев e2e-тестами, автоматизировать процесс работы с ветками и оптимизировать процесс переводов.
Надеюсь, эта статья и наш опыт помогут вам, особенно если вы уже сталкивались с подобными проблемами и они заставили вас задуматься о процессе релиза.
Большое спасибо за чтение моей статьи. Надеюсь, вам понравилось. Если у вас есть какие-либо вопросы или предложения, напишите мне в комментариях, и я обязательно это прочту!
И
Также опубликовано здесь