Trunk-Based Development
Почему короткоживущие ветки и частая интеграция ускоряют доставку
Проблема длинных веток
Знакомая картина: разработчик создаёт ветку под фичу, работает неделю, потом две, потом три, и когда подходит время мержить — main ушёл далеко вперёд, конфликтов накопилось на пару дней разбора, а код, отлично работавший в изоляции, разваливается при столкновении с изменениями коллег. Чем дольше ветка живёт, тем сильнее расходится с основной кодовой базой и тем болезненнее интеграция. Это не мнение, а математика: объём конфликтов растёт нелинейно по отношению к времени жизни ветки.
GitFlow, который Vincent Driessen популяризировал в 2010 году, предлагал целую иерархию веток: feature branches, develop, release, hotfix. В своё время это выглядело логично. На практике GitFlow хорошо работал только в мире, где релизы случались раз в месяц или реже. Когда индустрия сдвинулась к continuous delivery и деплоям несколько раз в день, GitFlow превратился из помощника в тормоз.
Trunk-Based Development: идея
Trunk-Based Development (TBD) — подход, при котором все разработчики вливают свои изменения в одну основную ветку (trunk, main, master) часто и маленькими порциями. Paul Hammant, один из главных евангелистов TBD, описывает правила так: ветки живут день-два, каждый коммит в trunk проходит автоматические проверки, trunk всегда в deployable-состоянии.
В чистом виде TBD означает коммиты прямо в trunk — так живёт Google, где больше 25 000 инженеров пишут в один монорепозиторий. В более распространённом виде — scaled trunk-based development — разработчики создают короткоживущие ветки (день-два), они проходят CI и code review, после чего мержатся в main. Главное отличие от GitFlow — не в наличии веток, а в продолжительности их жизни.
Что говорят данные DORA
DORA называет trunk-based development одной из ключевых технических практик, предсказывающих производительность команды. Анализ данных State of DevOps Report за 2016–2017 годы показал чёткую закономерность: команды добиваются более высокой скорости доставки и стабильности, если в репозитории одновременно не больше трёх активных веток и если ветки мержатся в trunk минимум раз в день.
Report 2021 года добавил количественную оценку: элитные команды, выполнявшие свои SLO по надёжности, в 2,3 раза чаще практиковали trunk-based development по сравнению с отстающими. Отстающие, в свою очередь, чаще держали долгоживущие ветки и откладывали мерж.
Причинно-следственная связь здесь не про сам мерж. TBD работает не потому, что «мерж в main» обладает магическими свойствами, а потому что короткоживущие ветки вынуждают делать маленькие атомарные изменения. Маленькие изменения проще ревьюить (PR на 50 строк вместо 2000), проще тестировать (меньше поверхность поломок), проще откатывать (revert одного коммита вместо археологических раскопок в мега-мерже).
Как живут Google и Meta
Google — канонический пример TBD в масштабе. Больше 25 000 инженеров работают в одном монорепозитории, и почти весь код живёт в trunk. Разработчики отправляют изменения сразу в main (после code review и автоматических проверок), а feature flags управляют тем, какой функционал виден пользователям. В книге «Software Engineering at Google» описано, что такой подход требует серьёзной инфраструктуры — мощного CI, хорошего инструмента для code review (Critique), системы feature flags — и окупается минимальными конфликтами и постоянной интеграцией.
Meta живёт на похожей модели: разработчики пушат изменения в main, гейтинг-система решает, что попадёт в следующий релиз, каждое изменение проходит автоматические проверки и canary deployment.
Предварительные условия
TBD — не подход, который внедряется в понедельник утром без подготовки. Без нескольких базовых условий получится не continuous delivery, а continuous chaos.
Быстрый CI. При сборке и тестах в 40 минут несколько мержей в main в день не получится. CI для TBD должен укладываться в 10 минут, лучше в 5, иначе очередь мержей превращается в пробку.
Автоматические тесты с хорошим покрытием. Несколько мержей в main в день не оставляют времени на ручной QA каждого изменения. Автотесты — сеть безопасности, и она должна быть надёжной. Про flaky-тесты — в следующей главе.
Feature flags. Если фича не готова за день-два (а большинство фич не готовы), нужен способ деплоить незавершённый код, не показывая его пользователям. Этим и занимаются feature flags, им посвящена отдельная глава.
Культура маленьких изменений. Самое сложное условие, потому что требует ломать привычку. Разработчики, привыкшие к большим feature-веткам, должны научиться разбивать задачу на маленькие самодостаточные куски, каждый из которых уезжает в main, не ломая его.
Частые возражения
«А как деплоить недоделанную фичу?» Feature flags. Код едет в main и в продакшен, но скрыт за флагом. Фича готова — флаг включается, и это уже релиз, а не деплой. Про разницу между деплоем и релизом — в главе про feature flags.
«У нас недостаточно тестов». TBD эту проблему обнажает, а не создаёт. Без тестов и с GitFlow плохо — про проблемы узнаёте позже и с большим трудом. TBD мотивирует вкладываться в тесты, потому что без них он действительно опасен.
«Пробовали, всё ломалось». Скорее всего, пропустили одно из предварительных условий: CI был медленным, тестов не хватало, или команда продолжала делать большие изменения, просто мержа их чаще. Без дисциплины маленьких инкрементальных изменений TBD не работает.
С чего начать
Если сейчас в работе долгоживущие ветки и хочется двигаться к TBD, начните с одного правила: ветка живёт максимум два рабочих дня. За два дня изменение не готово к мержу — оно слишком большое, и его нужно бить на части. Через месяц такой практики обнаружите, что конфликтов стало меньше, ревью идут быстрее (PR стали меньше), и появилось куда более точное представление о состоянии кодовой базы — потому что main отражает реальность, а не фантазию трёхмесячной давности.