Короткий ответ
Разработка ведётся напрямую в main небольшими, часто мерджащимися изменениями, незавершённая или ещё не готовая к показу пользователям функциональность скрывается за feature flag (выключенным по умолчанию), что позволяет автоматически деплоить main в прод после каждого мерджа, не дожидаясь завершения всей фичи — включение функциональности для пользователей становится отдельной, независимой от деплоя операцией.
Как это работает подробнее
вместо долгоживущей feature-ветки, которая мерджится только когда вся функциональность готова (что создаёт риск больших конфликтов и «большого взрыва» при мердже), разработчик разбивает фичу на маленькие части, каждая из которых мерджится в main и деплоится в прод в выключенном состоянии. Когда вся функциональность готова и протестирована, флаг включается — отдельно от любого деплоя кода.
Пример кода
# Код уже в main и задеплоен в прод, но выключен по умолчанию
if feature_flags.is_enabled("new_pricing_engine"):
return calculate_price_v2(order)
return calculate_price_v1(order)Что использовать на практике
- На практике. это требует дисциплины — код должен быть написан так, чтобы частично реализованная фича не ломала существующее поведение, даже находясь в main (например, недоделанный обработчик скрыт за условием флага). Также это снижает merge conflict risk и соответствует duration критерию DORA (lead time for changes), хотя сама по себе частота деплоев не является доказательством качества — важна связка с мониторингом и возможностью быстро выключить флаг при проблеме.
- Пример. Ожидаемое поведение: несколько PR, последовательно мерджащих части `new_pricing_engine`, деплоятся в прод по мере готовности без видимого эффекта для пользователей; включение флага для 100% пользователей — отдельное действие в системе управления флагами, не требующее нового деплоя кода.
Подводные камни
- Частые ошибки. используют feature-флаги, но всё равно держат долгоживущие ветки «на всякий случай», теряя основное преимущество подхода — маленькие, часто интегрируемые изменения; не тестируют оба состояния флага (включен/выключен) в CI, из-за чего код, работающий при включённом флаге, может незаметно сломать поведение при выключенном.