Программ без ошибок не бывает. Делая что-то полезное, мы невольно привносим в код то, что не собирались. Иногда неожиданности возникают на стыке, казалось бы, не связанных друг с другом изменений. Вот чудесный пример, как оптимизация драйвера мыши мешает обновлению адресной книги в Outlook. Поэтому всегда наступает такое время, когда команда сосредоточена исключительно на тестировании и исправлении ошибок. Добавление новых функций в это время запрещено.
Но источники новых требований, пожеланий и прочих хотелок не оскудевают. Пока идет стабилизация релиза, очередь на соседнем светофоре / бэклог продукта только растёт. Получается классическая пробка. Как разрешить этот конфликт?
Экстремальное программирование предлагает исправлять ошибки по мере их обнаружения, не останавливая разработку. И вообще, программировать надо без ошибок.Классный метод, мне нравится, но, к сожалению, разработчики всё равно программируют с ошибками. Интересно,
Другая крайность — это классический Waterfall, который призывает не смешивать одно с другим. Сначала все спроектировать, потом аккуратно реализовать, внимательно протестировать, исправить ошибки и результат передать заказчику.
Подход довольно разумный с точки зрения оптимизации затрат, но часто не очень эффективный в условиях неопределенности. При создании новых продуктов часто нет возможности достоверно узнать, что и как должно быть реализовано. Многое делается «на пробу» и переделывается впоследствии. При последовательном прохождении по фазам от идеи до её проверки проходит слишком много времени.
Продвигаясь по проторенному пути, полному проб и ошибок, мне кажется, нам удалось найти разумный компромисс между этими двумя крайностями – обеспечить гибкость, необходимую при разработке новых продуктов, и при этом сохранить высокий уровень качества. В этой статье я хотел бы поделиться нашим опытом, может, кому-то он будет полезен.
Сначала мы попробовали работать короткими итерациями, в результате которых получается работающая, протестированная версия. Ограниченный скоуп итерации помогает команде сконцентрироваться и не отвлекаться. Чтобы успеть устранить все шероховатости к финишу итерации, принято закладывать некоторое время на стабилизацию кода. В это время серьезные изменения в код не вносятся, только исправляются ошибки.
Период стабилизации необходим, он ограничивает количество изменений в коде и делает процесс сходящимся. На практике оказалось, что значительная часть команды в это время скучает: ошибок на всех не хватает. Конечно, всегда есть работа и за пределами итерации, но вносить изменения нельзя — идет стабилизация. А в начале следующей итерации скучают в ожидании новых ошибок тестировщики… Руководство, видя что что работники простаивают, грозится перевести их на другие проекты.
Следующим шагом стала попытка работать по Канбан-методике. Задачи идут непрерывным потоком, после завершения каждой задачи получается версия. Но надежду на качество разрушает основной закон органической химии: если смешать бочку меда и ложку дерьма — получится бочка дерьма. Ситуацию могло бы спасти полное тестирование версии после каждой задачи, но это оказалось слишком дорого как по трудозатратам, так и по времени.
Казалось бы, ситуация безвыходная… Но кто сказал, что изменения нужно вносить туда же, где идет стабилизация?
Сейчас мы работаем по модели «трех уровней нестабильности»:
- Ветка разработки — слабо контролируемая стабильность. Здесь делаются задачи «на будущее», которые не войдут в текущий релиз.
- Ветка релиза — контролируемое снижение нестабильности. Набор изменений, который будет реализован в этой ветке, ограничен и довольно жестко зафиксирован.
- Стабильная версия — зафиксированное в какой-то момент состояние с допустимым уровнем качества. Изменения вносятся крайне редко и очень небольшие (хотфиксы)
Работает это так.
Из продуктового бэклога мы набираем задач на релиз таким образом, чтобы сделать за месяц. Это наш текущий спринт. Команда приступает к реализации релиза, а ближе к его окончанию, когда изменений немного и работы на всех не хватает, начинаются плавные подготовительные работы к следующему спринту. Работы ведутся в отдельной ветке в гите, в отдельном разделе канбан-доски в Джире. Когда скоуп текущего релиза завершен, протестирован и стабилизирован, ветка релиза становится стабильной, ветка разработки становится базовой для следующего спринта, а ветка разработки замирает в ожидании окончания следующего спринта.
Позвольте, скажет кто-то, но тогда в ветке разработки нет актуальных правок. Да и с ошибками неудобно, их приходится править в двух ветках сразу. Чтобы таких проблем не было, мы договорились любую работу в ветке разработки предварять вливанием изменений из релизной ветки. После этой процедуры ветка разработки содержит все актуальные наработки и исправления ошибок.
Изменения из ветки разработки не попадают в релизную до окончания стабилизации. Это даёт возможность завершить релиз и передать стабильную версию в отдел продаж. А перед началом следующего релиза все наработки попадают в релизную ветку.
Теперь у нас есть непрерывный поток задач и неблокирующая процедура стабилизации релиза, которая позволяет нам выпускать качественные версии, не прекращая разработки.
Следующая точка приложения усилий — сокращение срока стабилизации для уменьшения разрыва между ветками и сокращения общего времени TimeToMarket.
Комментарии (8)
pronchakov
06.09.2016 18:13Подскажите пожалуйста:
- Сколько разработчиков работают одновременно?
- Я правильно понимаю, что проект состоит из одного репозитория?
- Что если в разработке в данный момент находятся фичи аля Proof Of Concept или разные реализации одной задачи для проверки производительности или еще что то, которые не нужно нести в релиз? Они в каких-то отдельных ветках? Кто и как часто следит за их обновлением? Или такого не бывает?
- Как осуществляется поддержка старых версий, работающих у клиентов? Ну например нужно поправить баг в пред-пред-стабильной версии. Небольшой. Или это не релевантно и везде используется только последняя версия?
Спасибо.ganouver
06.09.2016 19:26+11. Одновременно работают 6 разработчиков. Планируем расти.
2. Да, проект состоит из одного (довольно большого) репозитория. На нескольких организовать управляемый процесс довольно трудно :(
3. Каждая задача до завершения ведется в отдельной ветке и вливается в один из стволов (dev || release) только после завершения и предварительного тестирования на стенде разработчика. Я не стал пока про это писать, чтобы не усложнять. Таких веток в работе в идеальном случае — по количеству разработчиков, но иногда какие-то ProofOfConcept могут жить подольше. Могут двое работать в одной feature-ветке, например делая согласованные изменения на фронтенде и бэкенде. Вообще, стараемся делать так, чтобы эти ветки не висели долго. Делим задачи так, чтобы они делались за несколько дней и вливались в ствол. Старые ветки периодически чистим.
4. Для поддержки старых версий есть два варианта. Первый — очень-очень осторожно сделать маленький-маленький хотфикс с последующим Sanity тестированием. Редкий кейс, стараемся избегать. Предпочитаем исправить обнаруженный баг в текущем релизе и обычным порядком выставить обновление.
geov
Мне кажется вы придумали GitFlow
ganouver
Почти. Мы начинали работать по GitFlow, а потом немного расширили модель, «развалив» ветку develop на две: dev и release.
ggo
Классика жанра про dev, release, master
ganouver
Да, на первый взгляд одно и то же, различие в деталях. В GitFlow для каждого релиза стартуют отдельную ветку, которая потом сливается с мастером. Использование release branch полезно, когда нужно релизить несколько версий одновременно, но мы предпочли сфокусироваться на коротком цикле выпуска. У нас ветка релиза всегда одна, каждый следующий планируемый релиз просто вливается в неё из dev. Ветки dev & release друг от друга по сути почти не отличаются и больше похожи на develop из GitFlow. А то что в GitFlow называется release branch у нас не прижилось. Ветки обрабатываются сервером сборки абсолютно одинаково, результаты сборки деплоятся на разных стендах. В ветке release ведется разработка также как и в dev, но границы возможных изменений в release жестко ограничены, чтобы процесс был сходящимся. Также существенная разница приоритетах усилий по тестированию и исправлению ошибок — основное внимание уделяется ветке release, dev тестируется и правится по остаточному принципу. Все усилия фокусируются на стабилизации и выпуске релиза.