Настройка Feature Flags в мобильном приложении
Feature flags — механизм включения и выключения функций без обновления приложения. Звучит как мелочь, но меняет весь процесс разработки: trunk-based development становится возможен, релизный поезд отделяется от готовности фичи, и у вас есть kill switch на случай, если новая функция ломает производство.
Самое частое применение — postmortem protection: фича в проде ломает платёжный флоу у 5% пользователей, команда не может выпустить хотфикс за 2 часа из-за ревью App Store. Флаг выключается за 30 секунд.
Firebase Remote Config как базовый инструмент
Remote Config — простейший способ реализовать флаги без дополнительных SDK:
// iOS
let remoteConfig = RemoteConfig.remoteConfig()
// Дефолтные значения — работают offline и до первого fetch
remoteConfig.setDefaults([
"new_payment_flow_enabled": false as NSObject,
"chat_feature_enabled": false as NSObject,
"max_cart_items": 50 as NSObject
])
remoteConfig.fetch(withExpirationDuration: 300) { status, error in // 5 минут
remoteConfig.activate()
}
// Использование
var isNewPaymentEnabled: Bool {
remoteConfig.configValue(forKey: "new_payment_flow_enabled").boolValue
}
// Android
val remoteConfig = Firebase.remoteConfig
remoteConfig.setDefaultsAsync(mapOf(
"new_payment_flow_enabled" to false,
"chat_feature_enabled" to false
))
remoteConfig.fetchAndActivate().addOnCompleteListener { task ->
val isNewPaymentEnabled = remoteConfig.getBoolean("new_payment_flow_enabled")
}
Главный минус Firebase Remote Config — нет гибкого таргетинга. Флаг включен для всех или для сегмента по условиям (страна, версия приложения, аудитория Firebase). Процентный rollout есть, но через A/B Testing интерфейс.
LaunchDarkly для сложного таргетинга
Если нужен rollout по конкретным user_id, компаниям или сложным правилам:
// iOS LaunchDarkly SDK
import LaunchDarkly
let user = LDUser(key: userId, email: userEmail)
LDClient.start(config: LDConfig(mobileKey: "mob-xxx"), user: user)
// Синхронная проверка флага
let isEnabled = LDClient.shared.boolVariation(forKey: "new_payment_flow", defaultValue: false)
// С контекстом для логирования
let (value, detail) = LDClient.shared.boolVariationDetail(forKey: "new_payment_flow", defaultValue: false)
print("Reason: \(detail.reason)") // RULE_MATCH, FALLTHROUGH, OFF...
LaunchDarkly поддерживает targeting rules: включить флаг для пользователей с plan == "enterprise" или для первых 10% пользователей, отсортированных по user_id. Для постепенного rollout это точнее, чем случайный процент.
Организация флагов в коде
Все флаги в одном месте — не разбросаны по бизнес-логике:
// FeatureFlags.swift
struct FeatureFlags {
private let remoteConfig = RemoteConfig.remoteConfig()
var isNewPaymentFlowEnabled: Bool {
remoteConfig.configValue(forKey: "new_payment_flow_enabled").boolValue
}
var isChatEnabled: Bool {
remoteConfig.configValue(forKey: "chat_feature_enabled").boolValue
}
var maxCartItems: Int {
Int(remoteConfig.configValue(forKey: "max_cart_items").numberValue)
}
}
// Использование
if AppDependencies.featureFlags.isNewPaymentFlowEnabled {
showNewPaymentFlow()
} else {
showLegacyPaymentFlow()
}
Если флаги централизованы, найти все места использования через grep или рефактор — задача минут, а не часов.
Lifecycle флага: создание → удаление
Флаги накапливаются и становятся техдолгом. Хорошая практика — флаг живёт максимум 3 месяца:
- Флаг создан — фича скрыта
- Rollout начался — включаем постепенно
- 100% пользователей на новой версии → флаг = true для всех
- Удаляем флаг и мёртвый код старого поведения из кодовой базы
Если не удалять — через год в коде будет 40 флагов, половина из которых давно true для 100% аудитории.
Что входит в работу
- Подключение Remote Config (Firebase) или LaunchDarkly / Statsig
- Реализация централизованного
FeatureFlagsслоя - Настройка дефолтных значений для offline-работы
- Конфигурация targeting rules и rollout процентов
- Настройка мониторинга флагов в дашборде
- Документация жизненного цикла флагов для команды
Сроки
Firebase Remote Config с базовым набором флагов: 0,5–1 день. LaunchDarkly с targeting rules и процентным rollout: 1–2 дня. Стоимость рассчитывается индивидуально.







