Кто догадается, что тут написано - с меня шоколадка :)
22$zT1D2$ 5`C q~C5 4$j% Á
Вместо вступления
Feature flags - заманчивая плюшка, которая позволяет разработчикам включать и выключать функциональность приложения при помощи UI какого-нибудь инструмента автоматизации. Например, поддержка FF есть у GitLab-а в бесплатной версии, что как раз мы сегодня и попробуем. В общем и целом, фиче-флаги могут быть полезны для реализации канареечных релизов (постепенных релизов на часть пользователей), так как позволяют раскатывать фичи не на всех пользователей, а лишь на их часть.
Пример реализации
В данном примере рассмотрим, как интегрировать GitLab feature flags в Spring Boot приложение. В качестве языка программирования в примере будет Kotlin, но, очевидно, примеры легко портируются на Java.
Шаг 1
Для того чтобы обращаться к GitLab и узнавать информацию о статусе фиче-флагов нужно добавить в зависимости Unleash client Java SDK. Вообще говоря, Unleash - это софтина, реализующая механизм фиче-флагов, который под капотом использует GitLab. Подробнее о проекте можно почитать в их официальном репозитории.
Шаг 2
Пилим свою абстракцию для feature flags!
enum class FeatureFlags(
val flagId: String,
) {
TEST_FEATURE("test-feature"),
;
}
interface FeatureFlagsManager {
fun isFeatureEnabled(featureFlag: FeatureFlags): Boolean
fun ifFeatureEnabled(
featureFlag: FeatureFlags,
action: () -> Unit,
) {
if (isFeatureEnabled(featureFlag)) {
action.invoke()
}
}
}
class GitLabFeatureFlagsManager(
private val environment: Environment,
): FeatureFlagsManager {
private lateinit var unleash: Unleash
@PostConstruct
fun init() {
unleash = DefaultUnleash(
UnleashConfig.builder()
.appName(environment.getRequiredProperty("feature-flags.gitlab.app-name"))
.instanceId(environment.getRequiredProperty("feature-flags.gitlab.instance-id"))
.unleashAPI(environment.getRequiredProperty("feature-flags.gitlab.url"))
.build()
)
}
override fun isFeatureEnabled(featureFlag: FeatureFlags): Boolean =
try {
unleash.isEnabled(featureFlag.flagId, false)
} catch (e: Exception) {
log.warn("GitLab feature flags API is not available")
false
}
}
private const val STUB_FEATURE_FLAGS_PREFIX = "feature-flags.stubs"
class StubFeatureFlagsManager(
private val environment: Environment,
): FeatureFlagsManager {
override fun isFeatureEnabled(featureFlag: FeatureFlags): Boolean =
getPropertyValue(
name = keyForFeatureFlag(featureFlag)
)
private fun keyForFeatureFlag(featureFlag: FeatureFlags): String =
"$STUB_FEATURE_FLAGS_PREFIX.${featureFlag.flagId}"
private fun getPropertyValue(name: String): Boolean =
environment.getProperty(name, Boolean::class.java, false)
}
@Configuration
class FeatureFlagsProvider {
@Bean
@Profile("dev")
fun stubFeatureFlagsManager(
environment: Environment,
): FeatureFlagsManager = StubFeatureFlagsManager(environment)
@Bean
@Profile("prod", "stage")
fun gitlabFeatureFlagsManager(
environment: Environment,
): FeatureFlagsManager = GitLabFeatureFlagsManager(environment)
}
Из интересного - благодаря наличию интерфейса FeatureFlagsManager мы имеем две реализации логики вычисления значения фиче-флага - для локальной разработки на основе application.properties и для продукционного использования на основе GitLab + Unleash. Ну а свой енамчик с перечислением существующих фиче-флагов - это просто приятно и удобно :)
Шаг 3
Проперти для dev профиля и настройка интеграции с GitLab. Данные для интеграции с GitLab-ом (url, instance-id, app-name) нужно взять из инструкции по конфигурации feature flag, выдаваемым самим гитлабом. Для этого переходим в нужный репозиторий и далее Deploy -> Feature Flags. Там можно создать feature flag, обратите внимание, название флага, задаваемое в гитлабе, должно совпадать со значение поля flagId соответствующей константы FeatureFlags.
feature-flags:
gitlab:
app-name: dev
instance-id: secret
url: https://<my-gitlab>/api/v4/feature_flags/unleash/1
stubs:
test-feature: true
Шаг 4
Пример использования feature flag-а в коде.
@RestController
@RequestMapping("/api/v1/test/feature-flags")
class TestFeatureFlagsController(
private val featureFlagsManager: FeatureFlagsManager,
) {
@GetMapping
fun testFeatureFlags(): String = if (featureFlagsManager.isFeatureEnabled(FeatureFlags.TEST_FEATURE)) {
"Feature is enabled"
} else {
"Feature is disabled"
}
}
Шаг 5
Запускаем наше приложение, идем в GitLab (Deploy -> Feature Flags) и играемся с тогллом фиче-флага!
Подробности можно почитать в официальной доке GitLab: https://docs.gitlab.com/ee/operations/feature_flags.html#integrate-feature-flags-with-your-application
К тому же в этой доке можно почитать про различные стратегии feature flag-а (на всех пользователей, на процент пользователей и т.д.)
P.S. Шоколадка только первому угадавшему!