Noveo

Наш блог Подходы к управлению ветками в системах контроля версий (часть 3)

Подходы к управлению ветками в системах контроля версий (часть 3)

Третья часть статьи Мартина Фаулера посвящена различным способам осуществления релиза в продакшн.

Путь от mainline до релиза в прод

Mainline — это активная ветка, с регулярно появляющимися фрагментами нового и измененного кода. Поддержание ее в рабочем состоянии важно для того, чтобы люди, начиная работу над новой задачей, начинали ее со стабильной базы. Если код достаточно стабилен (прим.: Фаулер называет такой код «здоровым»), вы также можете релизить код непосредственно с mainline в прод.

Managing Source Code Branches Fowler Noveo translation

Эта философия поддержания mainline в постоянно доступном состоянии является центральным принципом Continuous Delivery, которая требует решимости и навыков поддержания mainline в «здоровом» состоянии, как правило, с помощью Deployment Pipelines для поддержки необходимого интенсивного тестирования.

 

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

Релизная ветка

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

 

Типичная релизная ветка будет копироваться с текущей mainline, но не позволит добавлять в неё новые фичи. Основная команда разработчиков продолжает добавлять фичи в mainline, и они будут включены в следующий релиз. А разработчики, занимающиеся релизом, ориентированы исключительно на устранение дефектов, которые мешают релизу быть готовым к выпуску на прод. Все исправления этих дефектов делаются в релизной ветке и мержатся с mainline. Когда все дефекты устранены, ветка готова к релизу в прод.

Managing Source Code Branches Fowler Noveo translation

Хотя объем работ по фиксам в релизной ветке (будем надеяться) меньше, чем по новой функциональности, с течением времени становится всё сложнее их слить обратно в mainline. Ветки неизбежно расходятся, и чем больше коммитов изменяют mainline, тем труднее смержить с ней релизную ветку.

 

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

Managing Source Code Branches Fowler Noveo translation

Выборочное копирование (cherry-pick) — это когда коммит копируется из одной ветки в другую, но ветки не сливаются. То есть копируется только один коммит, а не все предыдущие коммиты, начиная с точки ответвления. В этом примере, если бы я мержил F1 с релизной веткой, то включил бы M4 и M5. Но при выборочном копировании я взял бы только F1. Выборочное копирование не всегда может быть корректно применено к релизной ветке, так как может основываться на изменениях, сделанных в M4 и M5.

 

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

 

Командам с одной версией на проде понадобится только одна релизная ветка, но некоторые продукты будут использовать на проде много релизов. ПО, которым владеет заказчик, будет обновляться только по его желанию. Многие клиенты, обжегшись на неудачных обновлениях, неохотно идут на апгрейд, если не нужно добавлять мощные новые фичи. Такие клиенты, однако, все равно хотят исправлять баги, особенно если они связаны с проблемами безопасности. В подобной ситуации команда разработчиков держит релизные ветки открытыми для каждого используемого релиза и применяет к ним исправления по мере необходимости.Managing Source Code Branches Fowler Noveo translation

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

 

(Другие термины, которые я слышал для релизной ветки, включают в себя такие, как «ветка для подготовки релизов» («release-preparation branch»), «ветка стабилизации» («stabilization branch»), «ветка кандидата» («candidate branch») и «защитная ветка» («hardening branch»). Но «релизная ветка», похоже, самая распространенная).

 

Когда это использовать

 

Релизные ветки являются ценным инструментом, когда команда не в состоянии поддерживать свою mainline в здоровом состоянии. Это позволяет части команды сосредоточиться на исправлении багов, которые необходимо устранить до выпуска в продакшн. Тестировщики могут работать с самой стабильной последней версией из конца ветки. Каждый может увидеть, что сделано для стабилизации продукта.

 

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

 

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

 

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

 

Релизная ветка может также быть и веткой окружения («Environment Branch»), что влечет за собой все опасения, связанные с использованием этой схемы. Возможен и вариант долгоживущей релизной ветки, который я вскоре вкратце опишу.

Maturity Branch («Ветка готовности»)

Ветка, последний коммит которой указывает на последнюю версию уровня зрелости кодовой базы.

 

Команды часто хотят знать, какая версия исходного кода самая актуальная; это может быть сложно, если код в системе разного уровня зрелости. Тестировщик может захотеть взглянуть на последнюю версию продукта в работе, а кто-то, кто дебажит сбой в проде, захочет взглянуть на последнюю production-версию.

 

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

 

Рассмотрим maturity branche для проды. Когда мы готовим релиз на продакшн, мы открываем релизную ветку для стабилизации продукта. Как только релиз готов, мы копируем его в долгосрочную ветку для продакшн. Я думаю об этом скорее как о копировании, а не о мерже, поскольку мы хотим, чтобы production-код был точно таким же, как тот, что был протестирован в отслеживаемых ветках («upstream branches»).

Managing Source Code Branches Fowler Noveo translation

Одно из преимуществ Maturity branche заключается в том, что она четко показывает каждую версию кода, которая достигает этой стадии в рабочем процессе релиза. Поэтому в приведённом выше примере нам нужен только один коммит в production-ветке, который объединяет коммиты M1-3 и F1-2. Нужно будет немного пошаманить с SCM, чтобы сделать это, но в любом случае это ослабляет зависимость от мелкомодульных коммитов на mainline. Эти коммиты должны быть записаны в сообщении о коммите, чтобы помочь людям отследить их позже.

 

Maturity branches обычно называются в честь соответствующей стадии в процессе разработки. Отсюда и такие термины, как «production-ветка», «staging-ветка» и «ветка QA». Иногда я слышал, что люди называют production maturity branch «релизной веткой».

 

Когда это использовать

 

Системы управления исходным кодом поддерживают совместную работу и отслеживание истории кодовой базы. Использование maturity branch позволяет получить важные кусочки информации, показывая историю версий отдельных этапов в процессе работы над релизом.

 

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

 

В изменения конкретных веток можно интегрировать автоматизацию — например, автоматизированный процесс может деплоить версию в прод каждый раз, когда на production-ветку делается коммит.

 

Как альтернативу maturity branches можно использовать схему тегирования. Как только версия готова для тестирования, ей можно присвоить соответствующий тег — обычно он включает в себя и номер билда. Таким образом, когда билд 762 готов для тестирования, он может получить тег «qa-762», а когда он готов к выпуску в прод, то получает «prod-762». Поискав в репозитории кода теги, соответствующие нашей схеме, мы можем увидеть историю. Аналогичным образом к присвоению тегов может быть прикручена и  автоматизация.

Итак, maturity branch может сделать рабочий процесс более удобным, но многие компании считают, что и теги работают превосходно. Поэтому я смотрю на это как на один из тех паттернов, которые не имеют ни ярко выраженных преимуществ, ни недостатков. Часто, однако, необходимость использования системы управления исходным кодом для такого отслеживания является признаком бедного инструментария Deployment Pipeline команды.

 

Вариация: долгоживущая релизная ветка

 

Я могу думать об этом как о разновидности паттерна релизной ветки, которая сочетает его с maturity branch для кандидата в релиз. Когда мы хотим сделать релиз, мы копируем mainline в эту релизную ветку. Как и в случае с пре-релизными ветками, коммиты делаются в релизную ветку только для улучшения стабильности. Эти фиксы также мержатся с mainline. Когда это происходит, мы вешаем тег на релиз и можем снова скопировать mainline, когда хотим сделать другой релиз.

Managing Source Code Branches Fowler Noveo translation

Коммиты могут быть скопированы, что более типично для maturity branches, или смержены. При мерже мы должны внимательно следить, чтобы последний коммит релизной ветки точно совпадал с последним коммитом mainline. Один из способов сделать это — отменить все фиксы, которые были применены к mainline перед мержем. Некоторые команды также добавляют коммиты после слияния, чтобы убедиться, что каждый коммит представляет собой полноценный кандидат в релиз. (У людей, которые считают это сложным, есть веские причины предпочитать новую ветку для каждого релиза).

 

Такой подход применим только для продуктов с одним выпуском в продакшн за раз.

 

Одна из причин, по которой командам нравится этот подход, заключается в том, что при нем последний коммит релизной ветки всегда указывает на следующего релиз-кандидата, и не приходится последнюю релизную ветку, чтобы найти на ней последний коммит. Однако, по крайней мере, в git’е мы достигаем того же эффекта с помощью слова «релиз» в имени ветки, которое переходит к следующей вместе с hard reset, когда команда создает новую релизную ветку, оставляя тег на старой.

Ветка для окружения

Сконфигурируйте возможность запустить продукт в новом окружении, сделав коммит в исходный код.

 

Софт, как правило, запускается в различных средах, таких как рабочая машина разработчика, продакшн-сервер и, возможно, разные среды тестирования и staging’а. Обычно запуск в этих различных средах требует внесения некоторых изменений в конфигурацию, таких как URL, используемый для доступа к базе данных, расположение системы обмена сообщениями и URL для ключевых ресурсов.

 

Ветка для окружения — это ветка с коммитами, которые применяются к исходному коду для перенастройки продукта для работы в другой среде. Например, у нас есть версия 2.4, работающая на mainline, и теперь мы хотим запустить её на нашем staging-сервере. Мы делаем это, создавая новую ветку, начиная с версии 2.4, применяем соответствующие изменения окружения, пересобираем продукт и деплоим его в staging-окружение.

Managing Source Code Branches Fowler Noveo translation

Изменения обычно вносятся вручную, хотя, если ответственные за это люди не возражают против git’а, они могут выбрать (cherry pick) изменения из более ранней ветки.

 

Паттерн ветки для окружения часто сочетается с Maturity Branch. Долгоживущая QA maturity branch может включать в себя настройки конфигурации для QA-окружения. Мержи в эту ветку будут подхватывать изменения в конфигурации. Аналогично долгоживущая релизная ветка может включать в себя эти изменения настроек.

 

Когда это использовать

 

Ветка для окружения — это привлекательный подход. Она позволяет нам настроить приложение таким образом, чтобы оно было готово к работе в любой новой среде. Мы можем держать эти изменения в diff’е, который можем избирательно включать в будущие версии продукта. Это, однако, классический пример антипаттерна — то, что выглядит привлекательно сначала, но вскоре приводит вас в мир страданий, драконов и коронавирусов.

 

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

 

Проблема с ветками для окружения заключается в той самой гибкости, которая делает их такими привлекательными. Так как мы можем изменить любой аспект кода в этих diff’ах, мы легко можем добавить патчи с настройками, которые приводят к различному поведению и сопутствующим этому багам.

 

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

 

Простое разграничение между исполняемым файлом и конфигурацией может легко размыться, если софт исполняет свой исходник напрямую (например, JavaScript, Python, Ruby), но здесь применимы те же самые принципы. Старайтесь менять окружение маленькими шажками и не используйте ветвление исходного кода для их применения. Общее правило заключается в том, что вы должны иметь возможность проверять любую версию продукта и запускать его в любом окружении, так что всё, что изменяется исключительно из-за различных сред деплоймента, не должно быть в системах контроля версий. По поводу хранения комбинаций дефолтных параметров в системах контроля версий ведутся споры, но каждая версия приложения должна иметь возможность переключаться между этими различными конфигурациями по мере необходимости, основываясь на динамическом факторе, а именно — на переменных окружения.

 

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

Ветка для хотфикса

Ветка для работы над исправлением критичной ошибки на проде.

 

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

 

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

Managing Source Code Branches Fowler Noveo translation

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

 

Если команда использует релизные ветки, то можно сделать хотфикс там, а новый релиз — по завершении работы над ним. По сути, это превращает старую релизную ветку в ветку для хотфикса.

 

Managing Source Code Branches Fowler Noveo translation

 

 

Как и в релизных ветках, можно делать хотфиксы на mainline и выборочно забирать их в ветку для релизов. Но это довольно редкий случай, поскольку хотфиксы обычно делаются в очень сжатые сроки.

 

Если команда делает непрерывное развертывание (Continuous Delivery), она может релизить хотфиксы непосредственно из mainline. И хотя разработчики могут использовать ветку для хотфиксов, начинать они будут скорее с последнего коммита вообще, чем с последнего, выпущенного в релиз.

Managing Source Code Branches Fowler Noveo translation

Я повесил на новый релиз тег 2.2.1, так как если команда работает таким образом, то, скорее всего, M4 и M5 не содержат новых фич. Если содержат, то хотфикс, наиболее вероятно, просто войдет в релиз 2.3. Это, конечно, иллюстрирует, что при Continuous Delivery хотфиксам нет необходимости обходить нормальный процесс релиза. Если в команде налажен достаточно эффективный процесс релиза, хотфикс может быть обработан так же, как и обычный релиз — и это является существенным преимуществом мышления Continuous Delivery.

 

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

 

Когда это использовать

 

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

 

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

Релиз-поезд (Release Train)

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

 

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

 

Команда, использующая ежемесячные поезда, начнет ветку в марте, основываясь на февральском релизе. В течение месяца они будут добавлять новые фичи. В установленную дату, возможно, в третью среду месяца, поезд отправляется — и добавление новых фич в эту ветку становится невозможным. Они запускают новую ветку для апрельского поезда и новые фичи добавляют на нее. Тем временем кто-то из разработчиков стабилизирует мартовский поезд, выпуская его в прод, когда он будет готов. Любые исправления, применяемые к мартовскому поезду, переносятся и на апрельский поезд.

Managing Source Code Branches Fowler Noveo translation

Релиз-поезда обычно используются вместе с ветвлением по фичам. Когда Алла почувствует, что скоро допилит свою фичу, она решит, на какой поезд садиться. Если она думает, что успеет до мартовского релиза, она интегрируется в мартовский поезд, но если нет, она подождет следующего и интегрируется там.

 

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

 

В наши дни, когда люди слышат «релиз-поезд», то часто это в контексте концепции Agile Release Train от SAFe. Agile Release Train от SAFe — это организационная структура команды, рассчитанная на крупномасштабную команду из нескольких групп, у которых общее расписание поездов для релизов. Но, хотя здесь и используется схема релиз-поезда, она не совпадает с той, которую я описываю здесь.

 

Когда это использовать

 

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

 

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

 

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

 

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

 

Релиз-поезд может стать значимым этапом в улучшении процесса релиза, используемого командой. Если команда испытывает трудности с выпуском стабильных релизов, то прыжок сразу в Continuous Delivery может быть слишком сложным. Выбор подходящего периода выпуска релизов, который трудно, но возможно соблюдать, может стать хорошим первым шагом. По мере того, как команда прокачивает свои скиллы, она может увеличить частоту отправки поездов, в конечном счете отказываясь от них в пользу Continuous Delivery, когда дорастет до этого.

 

Вариация: загрузка будущих поездов

 

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

Managing Source Code Branches Fowler Noveo translation

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

 

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

 

В сравнении с регулярными релизами из mainline

 

Одно из главных преимуществ релиз-поезда — регулярный выпуск релизов в прод. Но наличие нескольких ветвей для новых разработок усложняет процесс. Если наша цель — регулярные релизы, то мы можем достичь этого также и с помощью mainline. Решите, каков график выпуска релизов, а затем создавайте релизную ветку по этому графику из того, что находится в последнем коммите mainline.

Managing Source Code Branches Fowler Noveo translation

Если mainline готова к релизу (Release-Ready Mainline), то в релизной ветке нет необходимости. При регулярных релизах, подобных этому, у разработчиков есть возможность придержать почти готовую фичу для следующего релиза, просто не заливая ее на mainline, если до даты следующего релиза осталось совсем мало времени. При Continuous Integration разработчики всегда могут отложить реализацию графического интерфейса для фичи или держать ее неактивной, если хотят, чтобы фича ждала следующего запланированного релиза.

Mainline, готовая к релизу (Release-Ready Mainline)

Поддерживайте mainline достаточно здоровой, чтобы ее последний коммит всегда мог быть запущен непосредственно в прод.

 

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

Managing Source Code Branches Fowler Noveo translation

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

 

Тот факт, что каждый коммит, сделанный на mainline, может идти в релиз, еще не означает, что так и должно случиться. Это тонкое различие между Continuous Delivery и Continuous Deployment. Команда, использующая Continuous Deployment, релизит каждое изменение, принятое на mainline, но в случае с Continuous Delivery каждое изменение готово к релизу, а вот выпускать его или нет — это уже бизнес-решение (таким образом, Continuous Deployment представляет собой подвид непрерывной доставки). Мы можем рассматривать Continuous Delivery как возможность делать релизы в любое время, а наше решение о реализации этой опции зависит от других факторов.

 

Когда это использовать

 

В сочетании с Continuous Integration как частью Continuous Delivery готовая к релизу mainline является общей особенностью высокопроизводительных команд. Учитывая это, а также мой хорошо известный энтузиазм по поводу Continuous Delivery, вы, наверное, ожидаете от меня слов о том, что готовая к релизу mainline — это всегда лучший выбор по сравнению с альтернативами, о которых я рассказывал в этом разделе.

 

Однако паттерны всегда связаны с контекстом. Паттерн, превосходный в одном контексте, может оказаться ловушкой в другом. Эффективность готовой к релизу mainline зависит от частоты интеграции команды. Если команда использует ветвление по фичам и интегрирует новую фичу, как правило, только раз в месяц, то команда, скорее всего, не в самом лучшем состоянии, и работа по модели готовой к релизу mainline может стать препятствием на пути их развития. Не лучшее состояние — это состояние, в котором они не могут реагировать на меняющиеся потребности продукта, потому что время цикла от идеи до производства слишком велико. Кроме того, у них, скорее всего, будут сложные мержи и проверки, так как каждая фича — крупная, что приводит к многочисленным конфликтам. Они могут проявляться во время интеграции или быть постоянной проблемой для разработчиков, когда они копируют mainline в свои ветки для фич. Такие сложности препятствуют рефакторингу, что снижает модульность, а это, в свою очередь, еще усугубляет проблему.

 

Ключом к выходу из этой ловушки является более частая интеграция, но во многих случаях этого может быть трудно достичь, сохраняя при этом готовую к выпуску mainline. В таком случае часто лучше отказаться от готовой к выпуску mainline, поддерживать более частую интеграцию и использовать релизную ветку для стабилизации mainline для продакшн. Со временем, конечно, мы будем надеяться устранить необходимость релизной ветки, улучшив deployment pipeline.

 

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

 

Кроме того, поддержание mainline готовой к выпуску повышает дисциплину. Это удерживает готовность к выходу в продакшн в центре внимания разработчиков, гарантируя, что в систему не будут то и дело просачиваться проблемы — ни баги, ни сложности в процессах, замедляющие время цикла продукта. Полная дисциплина Continuous Delivery — с интеграциями в mainline по несколько раз в день без вреда для нее — многим кажется пугающе трудной. Однако, достигнув ее и привыкнув, команды обнаруживают, что это значительно снижает стресс и сравнительно легко поддерживается. Именно поэтому она является ключевой delivering zone в модели Agile Fluency®.

Если вы нашли ошибку, пожалуйста, выделите фрагмент текста и нажмите Ctrl+Enter.

НазадПредыдущий пост ВпередСледующий пост

Сообщить об опечатке

Текст, который будет отправлен нашим редакторам: