19 декабря 2012 г.

Git branch naming convention for SCRUM developers

...или Делаем систему контроля версий более информативной и гибкой



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

Тема поста возникла из недавнего обсуждения, посвященного следующей проблеме.

SCRUM команды используют Continuous Integration сервер для регулярного автоматического создания сборок. Разработчики с помощью него могут оперативно получать отклик на свой код (на сервере работают автоматические интеграционные тесты), заинтересованные лица (в том числе Product Owner) могут получать самые последние сборки с самыми последними изменениями.

Обычно оттуда же берут сборки и QA, и... сталкиваются с тем, что по сообщениям commit'ов невозможно понять, какая фича появилась, что нужно посмотреть/протестировать и т. д.

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

Однако, если не выработана привычка писать «вменяемые» комментарии к коммитам, эта возможность будет полезна только одному из программистов в команде — другие участники попросту не смогут разобраться без просматривания changeset'ов в том, что действительно изменилось. Кстати, это в принципе справедливо и для пользователей SVN.


Правило №1 при работе с VCS (Git, Mercurial...): В комментариях к коммиту пишем что изменилось. Например, "Bug fixed [DC-17]", "Enabled offline mode", "Packages refactorings", "Added tests for payments module" — хорошие комментарии. Плохие комментарии — "-", "commit", "fix", "implemented", "do not deploy!" и т. п.


Список изменений в веб-интерфейсе Continuous Integration сервера Jetbrains TeamCity
Список изменений в веб-интерфейсе Continuous Integration сервера Jetbrains TeamCity


Однако, «вменяемых» сообщений commit'а явно не достаточно — кроме сообщений об исправлении багов и появления новых фичей, 95% сообщений содержат информацию сугубо технического характера, которая не нужна ни QA, ни Product Owner'у в SCRUM команде.

Добавление меток в сообщения комитов

Один мой друг рассказал мне историю про то, как потратил несколько дней на разработку специального plugin'а для билд-сервера, который был призван решать проблему фильтрации ненужных сообщений. В основе решения лежала идея в том, чтобы разработчики сами помечали важные комиты специальными хеш-метками вроде #fixed #closed_task #user_story и т. д. 

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

Известные плагины для улучшения отображения changelog'ов билд-сервера и системы тикетов JIRA, работающие по такому принципу: 
  1. JIRA TeamCity Integration Plugin
  2. Jenkins JIRA Plugin
Оба они позволяют видеть в списке изменений ссылки на соответствующие тикеты в JIRA.

Копаем глубже: successful branching model

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

Но на пути к более информативному логу билдсервера, без удачной branching модели не обойтись.

Git-flow и Github-flow

Идея git-flow была изложена Винсентом Дриссеном. Git-flow подходит для release-ориентированных команд: есть девелоперская ветка, от которой каждый желающий делает свою ветку, есть релизная ветка, в которую попадают только завершенные фичи, есть также ветки под отдельные фичи.

Такой подход работает, однако порождает неудобства в случае если в production должен уходить законченный функционал как только он появляется (continuous delivery), а не как только релиз будет готов. 

Исходя из этого Скотт Чакон из GitHub развивает свою критику и предлагает свою модель создания веток, названную github-flow, которую применяет в работе над GitHub. Основная идея Github-flow заключается в том, что под каждую фичу ведется своя ветка, которая потом сливается в ветку, из которой CI-сервер собирает код и доставляет сборку в production среду. Подход очень хорошо работает с GitHub, где закончив ветку можно легко отослать pull request на внесение своих изменений в основную ветку.

Оба эти подхода хороши в нашем случае вот чем — каждое слияние ветки с основной production-ready веткой говорит нам о том, что произошел прирост функционала или багфикс. Это тревожный звонок для QA и радостная новость для Product Owner'а, возможно повод рассказать на standup'е.

Однако, это решение опять ограниченное. Если в случае с github-flow понять какой функционал добавился возможно, ведь имена веток строго соответствуют short-hand названиям фич, то c git-flow merge commit message содержит по-прежнему много мусора. Да и short-hand названия понятны далеко не всем, и еще тяжелее их понять роботам.

Другой подход: scrum-flow

Подход, который я предлагаю, был вдохновлен процессом работы над функционалом в команде SCRUM разработчиков. Он является скорее улучшением двух предыдущих branching model'ей на основе опыта работе в SCRUM команде.

Переход с SVN на Git в первых проектах заставил быстро отучиться от привычек SVN делать редкие комиты, занимаясь постоянным накатыванием изменений из ветки разработки, и первым органичным шагом было использование git-flow. Позже при активном взаимодействии в команде стали появляться проблемы с тем, что непонятно в какой ветке лежит тот или иной фукнционал, и были введены short-hand имена веток. Но что дальше? 

Взглянем на жизненный цикл User Story — минимально значимого функционала, взятого в разработку в итерацию. В ходе работы над беклогом, требования и ограничения накладываемые на продукт, backlog item'ы, постепенно переформулируются в User Stories. Каждая US содержит описание конечной измеримой цели. Иными словами, жизненный цикл пользовательской истории в ходе разработке конечен. В ходе планирования спринта, история попадает в спринтлог. В один прекрасный день, первая задача в этой истории берется в работу командой, а спустя некоторое время, когда работа над функционалом завершилась и история была верифицирована командой, она приобретает статус завершенной.

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

Это значимое замечание послужило к рождению практики и convention'а, которые мы внедрили сначала на одном проекте, а потом которая стала использоваться на других проектах. 

Вкратце практику можно сформулировать так: Приступая к работе над новой историей или багом, начинай работать в ветке именованной как US<номер_истории> если работаешь над историей или же FIX<номер_бага> для багфикса и порождай необходимые тебе ветки от нее. Закончив разработку и убедившись, что всё корректно, сливай эту ветку с основной веткой разработки.

Что мы имеем в итоге и как это работает?


  1. Все, что находится в ветке master готово к поставке.
  2. Для работы над новой историей или фиксом бага заводи ветку с именем US<номер_истории> (для истории) или FIX<номер_истории> (для багфикса)
  3. Делай комит в эту ветку локально и регулярно отправляй изменения push на ветку с тем же именем на сервере git-репозитория
  4. Когда тебе нужна помощь или когда ты считаешь что история или баг фикс готовы к поставке — уведоми команду об этом (создай pull request если работаешь с GitHub)
  5. После того как кто-то другой проведет ревью и верификацию — сливай ветку в master.
  6. Поставляй новый функционал или багфикс (deliver!)
Цикл scrum-flow в виде git-команд
Цикл scrum-flow в виде git-команд

Что мы получаем наряду с предыдущими подходами?

  1. Не надо выдумывать имя новой ветки и стремиться давать осмысленное название — не надо дублировать информацию, которая есть на SCRUM доске или в системе тикетов
  2. Git становится не только историей комитов, но и хранителем опыта — всегда можно найти похожую историю и посмотреть фактическое время ее выполнения и задачи, требовавшие решения. Обычно эта информация не так легко доступна в системе тикетов, как хотелось бы.
  3. Сообщение merge комита в списке изменений одинаково понятно как роботам, так и людям не причастным к работе с кодом.
  4. Все члены команды знают где смотреть ожидаемый функционал по конкретной истории. Не надо узнавать у других какую ветку посмотреть.
  5. Посмотреть статус работы над той или иной фичей может каждый член команды.
  6. Воспитывает у разработчиков ответственность и ориентированность на добавление ценности разрабатываемому продукту.
Диаграмма объясняющая различия между git-flow, github-flow и scrum-flow
Сравнение git-flow, github-flow, scrum-flow на диаграмме комитов

Расширяемость и гибкость

Если по каким-то причинам держать ветку master в production-ready состоянии не подходит для вашего продукта, продолжайте использовать девелоперскую ветку без ограничений.

Вы всегда можете настроить сборку ветки, содержащей конкретный функционал. Это удобно для QA.

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

Префиксы тикетов важны для вас? Отлично! Используйте их вместо US и FIX.

Заключение

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

Однако, современные системы тикетов и CI-сервера еще недостаточно дружелюбны и в целом слабо ориентированы на конкретную методологию разработки. 

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

Благодарности

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

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

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

И конечно же всей дружной команде компании «Флексис», без которой эта работа попросту не была бы начата.

Список к чтению

1. http://scm-notes.blogspot.ru/2010/09/branch-per-task-workflow-explained.html в блоге отставного SCM'щика рассказано о подходе «одна ветка на одну задачу».
Enhanced by Zemanta
Отправить комментарий