Существует два основных подхода к совместной работе групп разработчиков с использованием системы контроля версий. Один из них — использование ветвей фич (feature branches), когда разработчик или группа разработчиков создают ветвь, обычно отходящую от ствола (также известную как main или mainline), и затем изолированно работают в этой ветке до тех пор, пока создаваемая ими фича не будет завершена. Когда команда считает, что функция готова к работе, она объединяет ветку с главным репозиторием.
Вторая модель известна как магистральная разработка (trunk-based), когда каждый разработчик делит свою работу на небольшие партии и сливает их в главный код (ствол, магистраль, trunk) как минимум один раз (а в перспективе и несколько раз) в день. Ключевое различие между этими подходами заключается в масштабах. Над ветвями фич обычно работает несколько разработчиков и они занимают несколько дней или даже недель работы. В отличие от этого, ветки в магистральной разработке обычно длятся не более нескольких часов, при этом многие разработчики часто сливают в главную ветку свои индивидуальные изменения.
На следующей диаграмме показан типичный график магистральной разработки:
В отличие от этого, на следующей диаграмме показан типичный стиль разработки без использования магистрали:
При таком подходе разработчики вносят изменения в долгоживущие ветви. Эти изменения требуют больших и более сложных событий слияния по сравнению с trunk-based разработкой. Этот подход также требует дополнительных усилий по стабилизации и периодов «блокировки» или «замораживания» кода, чтобы убедиться, что программное обеспечение остается в рабочем состоянии, поскольку при больших слияниях часто возникают ошибки или регрессии. В результате необходимо тщательно тестировать код после слияния и часто исправлять ошибки.
Как реализовать trunk-based разработку
Магистральная разработка — это необходимая для непрерывной интеграции практика. Непрерывная интеграция (CI) — это сочетание практики магистральной разработки с поддержкой набора быстрых автоматизированных тестов, которые запускаются после каждого коммита в магистраль, чтобы убедиться, что система всегда работоспособна.
Смысл использования непрерывной интеграции заключается в том, чтобы исключить длительные фазы интеграции и стабилизации путем частой интеграции небольших партий кода. Таким образом, разработчики гарантируют, что они сообщают о том, что они делают, а интеграция избавляет от больших слияний, которые могут создать значительный объем работы для других разработчиков и тестировщиков.
В парадигме CI разработчики отвечают за то, чтобы процесс сборки был «зеленым», т.е. работоспособным. Это означает, что если процесс CI дает сбой, разработчики должны прекратить свою работу либо для немедленного устранения проблемы, либо для возврата изменений, если они не могут быть исправлены в течение нескольких минут.
Практика trunk-based разработки требует, в свою очередь, от разработчиков понимания того, как разбивать свою работу на небольшие партии. Для разработчиков, не привыкших работать таким образом, это существенное изменение.
Анализ данных DevOps Research and Assessment (DORA) за 2016 и 2017 годы показывает, что команды достигают более высоких уровней доставки ПО и операционной производительности (скорость доставки, стабильность и доступность), если следуют этим практикам:
- Имеют три или менее активных ветки в репозитории кода приложения.
- Слияние веток в ствол происходит не реже одного раза в день.
- Не замораживают код и не проводят фазы интеграции.
Магистральная разработка и известные препятствия
К числу распространенных препятствий на пути к полному переходу на магистральную разработку относятся следующие:
- Чрезмерно тяжелый процесс рецензирования кода. Во многих организациях существует тяжелый процесс проверки кода, требующий многократного утверждения изменений перед их слиянием в главную ветку. Если проверка кода трудоемка и занимает несколько часов или дней, разработчики избегают работать небольшими партиями, а вместо этого собирают множество изменений. Это, в свою очередь, приводит к нисходящей спирали, когда рецензенты откладывают большие проверки кода из-за их сложности.Как следствие, запросы на слияние часто откладываются, поскольку разработчики избегают их. Поскольку трудно определить влияние больших изменений на систему путем инспекции, дефекты, скорее всего, ускользнут от внимания рецензентов, и преимущества магистральной разработки уменьшатся.
- Ревью кода происходит асинхронно. Если ваша команда практикует парное программирование, то код уже рассматривается вторым человеком. Если требуются дополнительные проверки, то они должны выполняться синхронно — когда разработчик готов зафиксировать код, он должен попросить кого-то еще из команды проверить его прямо сейчас. Не следует просить об асинхронной проверке — например, отправлять запрос в некий инструмент, а затем приступать к новой задаче в ожидании проверки. Чем дольше затягивается процесс слияния, тем больше вероятность возникновения конфликтов слияния и связанных с ними проблем. Реализация синхронных рецензий требует согласия команды на приоритет рецензирования кода друг друга над другой работой.
- Отсутствие автоматизированных тестов перед коммитом кода. Для того чтобы гарантировать поддержание главного кода в рабочем состоянии, необходимо проводить тесты на изменения кода перед коммитом. Это можно сделать на рабочих станциях разработчиков, а многие инструменты также предоставляют возможность удаленного запуска тестов на локальных изменениях с последующей автоматической фиксацией при их прохождении. Когда разработчики знают, что они могут без особых церемоний отправить свой код в магистраль, в результате получаются небольшие изменения кода, которые легко понять, просмотреть, протестировать и которые можно быстрее запустить в производство.
Способы улучшения магистральной разработки
Исходя из предыдущего обсуждения, приведем некоторые методы, которые можно применить для улучшения магистральной разработки:
- Разрабатывайте небольшими порциями. Одним из наиболее важных факторов, способствующих развитию магистральной разработки, является обучение команд разработке небольшими порциями. Это требует обучения и организационной поддержки команды разработчиков.
- Выполняйте синхронное рецензирование кода. Как уже говорилось, переход на синхронное рецензирование кода или, по крайней мере, обеспечение приоритетности рецензирования кода для разработчиков позволяет избежать многочасового или даже многодневного ожидания слияния изменений.
- Внедряйте комплексное автоматизированное тестирование. Убедитесь, что у вас есть полный и содержательный набор автоматизированных модульных тестов, и что они выполняются перед каждым коммитом. Например, если вы используете GitHub, вы можете защитить ветки, чтобы разрешить слияние запросов на выгрузку только после прохождения всех тестов. В руководстве Running builds with GitHub Checks показано, как интегрировать GitHub Checks с Cloud Build.
- Используйте быстрые сборки. Процесс сборки и тестирования должен выполняться за несколько минут. Если это кажется труднодостижимым, то, вероятно, это указывает на возможности улучшения архитектуры системы.
- Создайте основную группу сторонников и наставников. Разработка на основе магистрали — это существенное изменение для многих разработчиков, и следует ожидать некоторого сопротивления. Многие разработчики просто не могут представить себе, как можно работать таким образом. Хорошей практикой является поиск разработчиков, которые уже работали таким образом, и обучение ими других разработчиков. Также важно перевести некоторые команды на работу в магистральном стиле. Один из способов сделать это — собрать критическую массу разработчиков, имеющих опыт магистральной разработки, чтобы хотя бы одна команда следовала этой практике. Затем можно перевести другие команды на этот стиль, когда вы будете уверены, что команда, использующая эту практику, работает в соответствии с ожиданиями.
Способы оценки эффективности магистральной разработки
Измерить эффективность магистрального развития можно следующим образом.
Фактор | Что измерять | Цель |
---|---|---|
Активные ветки в репозитории кода приложения.. | Измерьте количество активных веток в системах контроля версий репозитория приложения и сделайте это число видимым для всех команд. Затем отслеживайте постепенное продвижение к целевому состоянию. | Три или менее активных ветвей. |
Периоды замораживания кода. | Измерьте, сколько раз ваша команда замораживала код и как долго заморозки длились. Эти измерения позволяют также классифицировать, сколько времени тратится на конфликты слияние, на замораживание кода, на стабилизацию и т.д. | Заморозки кода, когда никто не может засабмитить код, нет. |
Частота слияния ветвей и форков в магистраль. | Измеряйте либо двоичное значение (да/нет) для каждой слитой ветки, либо процент ветвей и форков, сливаемых каждый день. | Слияние не реже одного раза в день. |
Проверка времени, затрачиваемого на утверждение изменений кода. | Если обзор кода выполняется асинхронно, измерьте среднее время, необходимое для утверждения запросов на изменения, и обратите особое внимание на запросы, которые занимают значительно больше времени, чем в среднем. | Найдите способы сделать ревью кода синхронным действием, выполняемым в процессе разработки. |