Флаги функций — не единственный инструмент управления релизами
Одна команда, с которой я работал, потратила три месяца на разработку нового процесса оформления заказа. Код был готов, протестирован на стейджинге и влит в основную ветку под флагом функции. Когда они наконец включили флаг для 5% пользователей, платежный провайдер вернул ошибки, которых никогда не было на стейджинге. Флаг позволил отключить всё за секунды. Но настоящий вопрос был в другом: должен ли был этот код вообще находиться в продакшене?
Флаги функций — мощный инструмент. Они позволяют развернуть код, который ещё не активен, тестировать в продакшене на реальном трафике и раскатывать изменения постепенно. Но это не универсальное решение. Иногда лучше использовать ветку. Иногда отдельное окружение имеет больше смысла. А иногда нужно сочетать все три подхода.
Первый вопрос, на который нужно ответить: чего именно вы пытаетесь добиться, откладывая или ограничивая доступ к новой функциональности?
Когда использовать ветку
Ветки существуют для изоляции незавершённой работы. Если функциональность не готова и не может работать без поломки приложения, держите её в ветке. Код вообще не попадает в основную ветку. Никто случайно его не развернёт. Никому не нужно помнить, что существует флаг.
Это самая простая форма контроля. Она хорошо работает для функций, которые ещё разрабатываются, особенно когда несколько разработчиков работают над разными частями. Основная ветка остаётся чистой. Команда вливает изменения только когда функциональность завершена и проверена.
Но у веток есть ограничение. После того как код влит, вы теряете возможность управлять его активацией. Функциональность либо есть в основной ветке, либо нет. Промежуточного состояния не существует. Вот тут и приходят на помощь флаги функций.
Когда использовать флаг функции
Флаги функций управляют поведением после того, как код уже влит. Код находится в основной ветке, развёрнут в продакшене, но не активен для всех пользователей. Вы можете включить его для небольшого процента, для внутренних тестировщиков или при определённых условиях.
Это полезно, когда функциональность функционально завершена, но вы ещё не готовы показать её всем. Возможно, вы хотите проверить стабильность под реальной нагрузкой. Возможно, нужно отследить частоту ошибок перед полным запуском. Возможно, вы хотите делать постепенное увеличение доли в течение нескольких дней.
Флаги функций также помогают с откатом. Если что-то пошло не так, вы выключаете флаг вместо того, чтобы откатывать развёртывание. Это быстрее и безопаснее, чем откат кода, особенно когда развёртывание включает миграции базы данных или другие необратимые изменения.
Но флаги функций не бесплатны. Они добавляют сложности в кодовую базу. Каждый флаг — это ветвление if-else, которое нужно поддерживать, тестировать и в итоге удалять. Слишком много флагов, которые остаются слишком долго, создают технический долг. Команды, накопившие сотни устаревших флагов, получают код, который трудно читать и ещё труднее отлаживать.
Когда использовать отдельное окружение
Стейджинг-окружение даёт место для тестирования перед продакшеном. Оно изолировано от реальных пользователей. Вы можете запускать интеграционные тесты, ручное QA и исследовательское тестирование, ни на кого не влияя.
Проблема в том, что стейджинг никогда не идентичен продакшену. Паттерны трафика другие. Объёмы данных меньше. Поведение реальных пользователей невозможно воспроизвести. Некоторые проблемы проявляются только под продакшен-нагрузкой, с продакшен-данными или с точной конфигурацией инфраструктуры, которой нет на стейджинге.
Именно поэтому флаги функций и окружения дополняют друг друга. Используйте стейджинг для раннего тестирования. Используйте флаги функций для валидации в продакшене. Они не заменяют друг друга. Это два уровня безопасности.
Крупная функциональность, которая меняет ключевой процесс — например, замена платёжной системы или редизайн страницы входа — вероятно, должна сначала пройти через стейджинг. После того как она там прошла, можно развернуть её под флагом в продакшене и постепенно увеличивать охват.
Комбинирование ветки, окружения и флага
На практике многие команды используют все три подхода вместе. Вот распространённый паттерн:
- Работайте над крупной функциональностью в отдельной ветке.
- Влейте ветку в основную с выключенным флагом.
- Разверните на стейджинг, протестируйте функциональность, включив флаг на стейджинге.
- Разверните в продакшен с всё ещё выключенным флагом.
- Включите флаг для внутренних пользователей или небольшого процента.
- Постепенно увеличивайте процент на основе мониторинга.
- Удалите флаг после полного развёртывания и стабилизации.
Этот паттерн распространён в командах, практикующих trunk-based development. Основная ветка всегда готова к развёртыванию. Крупные функциональности разбиваются на более мелкие части, каждая под своим флагом. Команда часто вливает изменения, часто развёртывает и использует флаги для управления тем, что видят пользователи.
Когда флаги функций — неправильный выбор
Флаги функций не всегда лучший инструмент. Рассмотрите следующие ситуации:
- Функциональность неработоспособна. Если код не компилируется, падает на тестах или вызывает ошибки при запуске, не вливайте его. Держите в ветке, пока он не заработает.
- Изменение слишком велико для управления одним флагом. Флаг, который включает целую подсистему, трудно тестировать и рискованно переключать. Разбейте функциональность на более мелкие части, каждую со своим флагом, или используйте окружение для начальной валидации.
- Команда использует флаги, чтобы избегать решений. Если флаг существует, потому что никто не хочет решать, готова ли функциональность, это проблема процесса, а не инструмента. Флаги должны ускорять обратную связь, а не откладывать сложные разговоры.
- Флаг останется навсегда. Некоторые команды держат флаги бесконечно, потому что удаление кажется рискованным. Это признак того, что флаг был плохо спроектирован или команде не хватает уверенности в своём процессе релиза. У каждого флага должна быть запланированная дата удаления.
Практический чек-лист для выбора контроля релизов
| Ситуация | Рекомендуемый контроль |
|---|---|
| Функциональность не завершена и неработоспособна | Ветка |
| Функциональность завершена, но нужна валидация в продакшене | Флаг функции |
| Функциональность требует изолированного тестирования перед продакшеном | Стейджинг-окружение |
| Функциональность крупная и меняет ключевое поведение | Сначала стейджинг, затем флаг |
| Команда практикует trunk-based development | Комбинация ветки и флага |
| Функциональность маленькая и с низким риском | Флаг функции или прямой деплой |
Это не жёсткая таблица. У каждой команды разная толерантность к риску и инфраструктура. Используйте её как отправную точку для обсуждения, а не как свод правил.
Дерево решений ниже суммирует ключевые вопросы и рекомендуемые контроли.
Настоящая цель
Флаги функций, ветки и окружения — это инструменты. Цель не в том, чтобы использовать их все. Цель — безопасно доставлять программное обеспечение и быстро получать обратную связь.
Хорошая стратегия релизов позволяет часто развёртывать, тестировать в продакшене с контролируемым риском и отключать всё, когда что-то идёт не так. Она не позволяет откладывать решения или накапливать незавершённые функциональности в продакшене.
Начните с понимания того, что именно вы пытаетесь контролировать. Затем выберите подходящий инструмент. А когда используете флаг функции, не забудьте его удалить. Лучший флаг — тот, которого больше не существует.