Мой опыт перевода команд разработки на trunk-based development

cb5d97c348655d87a084df5165bc935f.png

Привет, Хабр!

За свою карьеру руководителя разработки я успешно перевел на рельсы TBD 5 команд общей численностью 20 человек. Когда я общаюсь с коллегами из других компаний на тему TBD, то часто слышу про негативный опыт. Эта статья — мой личный опыт и разбор типовых ошибок других компаний.

Что такое trunk-based development?

Trunk-based development это, в первую очередь, инструмент. Чтобы эффективно применить инструмент, нужно понять что он делает и где может быть полезен.

Мой вольный перевод вступления с сайта trunkbaseddevelopment.com:

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

*trunk это main/master в терминологии Git.

По сути, TBD это набор хорошо зарекомендовавших себя практик. Вот самые важные из них:

  • Branch by Abstraction. Наверное, самая сложная практика для понимания и применения. Суть в чем — если нам надо заменить какой-то кусок программы, неважно это отдельная функция или целый блок программной логики, то мы делаем следующие шаги:

    • Закрываем интерфейсом старую реализацию, который мы хотим заменить.

    • Меняем в коде вызов старой реализации на вызов интерфейса. Dependency Inversion Principle.

    • Пишем новую реализацию и закрываем ее тем же интерфейсом.

    • Подменяем старую реализацию на новую.

    • Удаляем старую реализацию.

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

  • Branch for release. Тут есть 2 подхода:

    • Если у нас back-end или front-end разработка, то мы можем собирать релиз прямо из trunk ветки. Например, поставить tag с номером версии на тот коммит, с которого мы хотим собрать релиз и настроить CI/CD на это действие.

    • Если у нас мобильная разработка, то там есть бутылочное горлышко в лице проверки приложений от Apple/Google. Проверки могут быть по несколько дней, и по ее итогам могут прилететь правки. А еще мы можем захотеть сделать тестирование отдельным процессом и не хотим чтобы работа над релизом блокировала основную разработку. В этих случаях, мы заводим release ветку, если прилетают правки, то исправляем их в trunk и забираем в release ветку с помощью cherry-pick. Почему именно такой порядок — чтобы trunk всегда был актуален для остальных разработчиков. На последний коммит релизной ветки мы ставим tag с номером версии. Хранить релизную ветку или нет — решать вам, в моих командах мы храним релизную ветку до следующего релиза.

  • Feature flags. Если мы работаем над какой-то большой фичой, но при этом у нас частые релизы и мы не хотим их блокировать, то мы закрываем нашу работу с помощью feature flag. В моих командах back-end и front-end разработка под feature flags обычно имеют config файлы, а мобильная разработка делать отдельный feature screen, на котором QA отдел может включить/выключить фичи для тестирования.

  • CI/CD. Тут все стандартно:

    • Прогон линтеров и статических анализаторов кода

    • Прогон тестов

    • Сборка билда и отправка в в тестовую и/или боевую среду.

  • Ветки с коротким временем жизни. По сути, это означает что мы делаем фичу поэтапно, каждый этап — отдельная ветка, то есть feature веток на несколько тысяч строк в TBD нет. Как это можно реализовать:

    • Использовать branch by abstraction, каждое действие отправляем на code review.

    • Поставить в команде ограничение на размер merge/pull request. Я обычно ставлю максимум 300±50 строк бизнес-логики.

    • Завести в команде правило делать минимум один merge/pull request в день.

      • Из этого следует еще одно важное правило делать code review в течение получаса-часа, это культура continuous code review. Этот пункт не актуален если у вас pair или mob programming.

      • После каждого merge/pull request нужно сделать pull из ветки trunk, чтобы работать с актуальной версией кода

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

  • Коммиты прямо в trunk. В IT сообществе часто с осуждением смотрят на тех, кто отправляет свой код сразу в master, но в trunk это одна из основных концепций. Мне тоже потребовалось время чтобы принять эту мысль, но на практике я нашел в ней только плюсы:

    • Такой экстремальный подход порождает культуру написания тестов, если у вас по какой-то причине ее нет.

    • Нету кучи промежуточных веток, как в Git flow, есть только trunk и ветка с коротким временем жизни. Процесс вливания кода в общую ветку разработки становится гораздо проще.

    Отдельно хочется сказать про работу с багами в trunk. Предлагается 2 способа:

    • Fix forward, когда мы просто исправляем баг следующим коммитом.

    • Roll back, когда мы откатываемся на последнюю работающую версию кода.

    Тут все зависит от вашего контекста и SLA. Обычно для команд мобильной разработки я использую fix forward, т.к. мы все равно ограничены проверками Apple/Google и оперативное исправление в целом не играет большой роли. Для back-end и front-end команд я предпочитаю придерживаться стратегии roll back.

Нужен ли вам TBD?

На мой взгляд, нужно регулярно задавать себе вопрос «Не фигню ли я делаю?», особенно если вы — руководитель и хотите затащить в команду какую-то новую практику. TDB не исключение.

Итак, я не буду завозить в команду TBD если:

  • Команда 1–3 человека и расширение не планируется. Для такого размера команды TBD довольно сложный инструмент.

  • Процесс в команде налажены и бизнес доволен скоростью работы команды. Как говорится, работает — не трогай, лучшее — враг хорошего.

  • Merge conflicts в команде довольно редкие или их вообще нет.

  • У команды нет времени на внедрение новых практик из-за высокой загруженности, например в стартапе или при ограничениях по времени и срокам проектов от бизнеса. TBD требует времени на осмысление, принятие идей и интеграцию в работу. Быстро занести все практики в команду практически невозможно.

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

Разбор основных ошибок при переходе на TBD

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

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

  1. Определение текущих проблем. Тут важно взять именно кейсы из командной работы, которые можно исправить с помощью TBD. Например, неудачные слияния большого количества кода, огромные merge/pull requests, большое количество merge conflicts и т.д.

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

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

  4. Отработка возражений. Это мой любимый пункт. В своей работе я стремлюсь к тому, чтобы продать команде идею и преодолеть сопротивление непонимания. Если возражения не отработаны, то идея перехода на TBD с большой долей вероятности провалится.

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

Команда не поняла как это работает и откатилась к своим привычным рабочим процессам.

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

Мы внедрили TBD, поработали, нам не понравилось и мы решили вернуться к привычным рабочим процессам.

Тут я встречал 2 варианта:

  1. Неправильно реализовали практики, которые в итоге стали мешать. Например, feature toggle делались абсолютно на все фичи и не удаляли старые реализации, что в итоге привело к захламлению кода. Или не писали тесты и не проводили code review, вследствие чего trunk очень часто ломался и невозможно было выпустить срочный релиз.

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

Как изменились метрики команды при переходе на TBD

  1. Скорость поставки фичей вырастала на 20–30% при тех же командных усилиях.

  2. Объем кода на merge/pull request сократился, поэтому делать code review стало легче и быстрее на 15–20%. Однако, отмечу что это субъективные ощущения разработчиков в команде.

  3. Процесс релиза в мобильной разработке сократился с 3–5 до 1–2 дней. Во front-end и back-end разработки он сократился с 2–3 дней до 1 дня.

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

© Habrahabr.ru