Что такое фича-флаг?
Фича-флаг — это способ включить или выключить фичу или ветвь кода внутри приложения.
В идеале, «переключатель» не должен влиять на код или требовать новый релиз. Это просто тумблер, который вы включаете или выключаете с помощью какой-либо конфигурации.
Такие флаги имеют несколько вариаций:
- Условие на основе окружения, которое включает фичу во время QA и выключает в продакшне, пока фича не будет готова;
- Фича, которую необходимо развернуть для определённого пользователя или группы пользователей, например тестировщиков;
- Основанная на времени фича, которую необходимо развернуть в будущем или на определённое время, например, чтобы показать баннер;
- Клиент сам решает, включена фича или нет, в зависимости от предпочтений пользователя.
В фича-флагах в экосистеме .NET мне нравится то, что можно начать с чего-то простого и усложнять по мере необходимости. Как будет показано далее, самые полезные фича-флаги уже реализованы, и их достаточно просто подключить.
Теперь давайте реализуем простой фича-флаг в .NET и расширим его до более мощного решения.
Содержание
- Создание необходимых условий.
- Реализация базового фича-флага.
- Настраиваемый фича-флаг.
- Введение стандартов с помощью пакета Feature Management.
- Встроенные фильтры.
- Написание кастомной реализации фильтра.
- Использование параметров с кастомными фильтрами.
- FeatureGate для контроллеров MVC.
- Azure Feature Management.
- Заключение.
Создание необходимых условий
Создадим новое приложение со следующими командами.
Теперь, откроем приложение в IDE и откроем файл Program.cs
. Здесь вы найдёте код, который уже реализует эндпоинт GET
для получения набора прогнозов погоды.
Сокращенная версия кода только с самым необходимым (убрана реализация swagger) выглядит следующим образом.
Чтобы проверить, что всё работает, запустим приложение и зайдём на https://localhost:{portnumber}/weatherforecast (не забудьте поменять номер порта).
Если всё хорошо, вы увидите набор прогнозов. Вот что показывается для меня.
Реализация базового фича-флага
Теперь мы можем реализовать фича-флаг в эндпоинте прогнозов погоды.
Для простоты скажем, что эндпоинт включается или выключается в зависимости от флага.
Самый простой фича-флаг — это обычный оператор if
, зависящий от булева выражения. Для реализации фича-флага определим переменную forecastEnabled
. Значение этой переменной определяет значение, возвращаемое эндпоинтом:
true
(фича-флаг включен), эндпоинт возвращает данные прогнозов;false
(фича-флаг выключен), эндпоинт возвращает код состояния404
.
Настраиваемый фича-флаг
Пока в этом нет никакого смысла. Фича-флаг либо включен, либо выключен для всех клиентов. Для включения эндпоинта прогнозов необходимо изменить в коде переменную forecastEnabled
и повторно зарелизить приложение.
При этом теряется смысл фича-флагов. Чтобы убедиться, что наш фича-флаг полезен, сперва необходимо найти способ динамически менять его значение.
Для этого состояние фичи надо определять вне кода приложения. В результате мы сможем менять настройку во время релиза, а артефакты сборки можно будет использовать на нескольких стадиях CI/CD-пайплайна.
Пример: фича-флаг может быть включен в стейджинге и выключен в продакшене.
Для настройки состояний фича-флага можно использовать appsettings. Таким образом, мы добавим дополнительную секцию FeatureFlags
, в которой создадим свойство WeatherForecast
.
Чтобы использовать новую конфигурацию, заменим переменную forecastEnabled
значением из appsetings.
Введение стандартов с помощью пакета Feature Management
Вместо определения своих стандартов мы можем использовать реализацию Майкрософта из пакета NuGet Microsoft.FeatureManagement.AspNetCore
.
Используем следующую команду для установки пакета.
После установки пакета можно провести рефакторинг нашей собственной реализации с помощью базовой. Для этого:
- Импортируем пространство имён
Microsoft.FeatureManagement
; - Зарегистрируем службу
AddFeatureManagement
; - Внедрим
IFeatureManager
в эндпоинт; - Используем метод
IFeatureManager.IsEnabledAsync
, чтобы проверить, включена ли фича.
ASP.NET v7 представил EndpointFilter
, который можно использовать с минимальными API. Это удобно, так как вы можете с лёгкостью повторно использовать логику фильтрации и не захламлять ею ваш эндпоинт (в этом случае — проверяя, включена ли фича). Для создания многоразового фильтра эндпоинта для ваших фича-флагов можно прочитать мою статью Implementing a Feature Flag based Endpoint Filter
Конфигурация в файле appsettings.json
не требует изменений и может повторно использоваться как есть. Этот шаг немногое решает сам по себе, но даёт возможность сделать большее…
Встроенные фильтры
Помимо определённого и последовательного способа настройки фича-флагов, пакет предоставляет несколько реализаций фича-флагов (фильтров) для наиболее распространённых ситуаций.
С пакетом Feature Management мы можем включать или выключать фича-флаг (true
или false
), как делали раньше. Но у пакета также есть понятие «фильтров». У каждого фильтра есть своя схема конфигурации (в JSON), но способ проверки, включена ли фича, остаётся неизменным для всех фильтров.
В дополнение к встроенным фильтрам можно писать собственные реализации.
Доступны следующие фильтры:
PercentageFilter
для случайного включения/выключения фичи в зависимости от процента;TimeWindowFilter
для включения фичи во время заранее определённого окна с начальным и конечным временем;TargetingFilter
, для включения фичи указанному пользователю или группе пользователей (для этого фильтра тоже можно установить процент).
Для большей информации можно взглянуть на документацию.
Насколько я знаю, фильтр TargetingFilter
нельзя использовать, если используется структура минимального API. При регистрации фильтра вы получите ошибку:
Эти фильтры доступны в пространстве имён Microsoft.FeatureManagement.FeatureFilters
и должны быть зарегистрированы по отдельности.
Остальная часть кода остаётся прежней. Другими словами, это не меняет то, как мы проверяем, включен ли фича-флаг.
Как было сказано ранее, мы используем фича-флаги как раньше, но настраиваем их иначе.
Ниже показано, что тип фильтра определяется со свойством Name
. Со свойством Parameters
конфигурация фильтра установлена на фильтры процента и временного окна.
Ниже показан пример конфигурации для фильтра целевой аудитории. Вместо свойства Parameters
, фильтр настроен со свойством Audience
.
Написание кастомной реализации фильтра
Для реализации собственной логики фильтра создадим класс, реализующий интерфейс IFeatureFilter
, и зарегистрируем службу.
Интерфейс IFeatureFilter
позволяет реализовать метод EvaluateAsync
. Здесь необходимо прописать собственную логику, чтобы понимать, включена фича или нет.
Метод получает аргумент FeatureFilterEvaluationContext
, который содержит объект конфигурации. Для получения доступа к параметрам фильтра используем метод FeatureFilterEvaluationContext.Parameters.Get<T>()
.
С помощью атрибута FilterAlias
устанавливается имя фильтра. Это то же имя, которое необходимо использовать в конфигурации, чтобы соединить её с фильтром.
Использование параметров с кастомными фильтрами
Фильтр также может получать параметры, известные только во время выполнения. Например, это может быть альтернативой фильтру TargetingFilter
для минимальных API, потому что он способен получать контекст HTTP или сабсет из него.
Для создания фильтра с параметрами заменим IFeatureFilter
интерфейсом IContextualFeatureFilter
. После такого изменения метод EvaluateAsync
будет получать дополнительные параметры.
В примере ниже заголовок считывается и посылается в фильтр, но вместо заголовка мог быть HttpContext
, ClaimsPrinciple
или что-то ещё.
FeatureGate для контроллеров MVC
Эта часть доступна, только если ваше приложение построено на контроллерах и без структуры минимального API.
Вместо проверки включена ли фича в коде, вы можете использовать атрибут FeatureGate
, чтобы выключить весь контроллер или определённый эндпоинт. Параметр, передающийся атрибуту, — это имя фичи, установленное в конфигурации.
Azure Feature Management
Пока всё идёт хорошо, но можно сделать еще лучше.
У текущей реализации есть один недостаток. При изменении конфигурации необходимо перезапустить приложение, чтобы изменения вступили в силу. Это влияет на пользователей.
Если вы хотите поменять фича-флаг без перезапуска приложения, вы можете использовать функцию Feature Management от Azure. Это позволит динамически менять конфигурацию фича-флагов.
В портале Azure можно убирать определения фича-флагов, а также настраивать их фильтры. Это похоже на то, что у нас было в файле appsettings.json
, но теперь с пользовательским интерфейсом.
К примеру, посмотрите на следующий скриншот, определяющий фича-флаг WeatherForecast
в портале Azure. Ещё здесь можно заметить, что к фича-флагу добавляется ярлык, что удобно при создании групп фич.
Вид конфигурации фича-флага выглядит следующим образом:
Чтобы использовать Azure Feature Management в коде, для начала установим необходимые пакеты NuGet.
Прежде чем мы сможем использовать Azure Feature Management, понадобится настроить Azure App Configuration. Во время настройки мы подключаемся к указанному ресурсу Azure и включаем фича-флаги. Помимо этого, есть опция определения, какие фича-флаги надо зарегистрировать в зависимости от их ярлыка.
Конфигурацию Azure можно править под ваши нужды и дальше, например установить длительность кэша. Для дополнительной информации о всех вариантах посмотрите документацию.
В примере ниже мы считываем все фича-флаги без определённого ярлыка и все фича-флаги для текущего окружения. Здесь важен порядок, потому что последнее перекрывает первое. Использование такого подхода упрощает включение фич для всех окружений (фича-флаги без ярлыка), исключая продакшн (фича-флаги с ярлыком Production).
Используя Azure Feature Management, не забудьте зарегистрировать функцию управления фича-флагами и убедиться, что используются фильтры, также как и в предыдущих примерах без Azure.
В качестве последнего шага можно убрать настройки фич из файла appsettings.json
, так как теперь им владеет Azure.
Заключение
В этой статье мы начали с простого подхода к реализации фича-флага. Для этого требовалось перекомпилировать и заново деплоить приложение, чтобы изменить его поведение.
Первым шагом к лучшему решению был рефакторинг реализации посредством перемещения конфигурации фича-флага из кода в файл appsettings.json
. В результате фича-флаг стал декларативным, а приложение стало возможно повторно деплоить (с другим поведением) без повторной компиляции, облегчая процесс выключения определённых фич в указанной среде. В качестве побочного эффекта приложение стало удовлетворять критериям twelve-factor app.
Следующим шагом для ввода стандарта было использование .NET Feature Management API. Дополнительным преимуществом использования этого пакета является возможность ориентироваться на конкретных пользователей. Помимо фича-флагов для всего приложения, их можно настраивать в зависимости от различных условий. Эта функция называется «фильтром», и у Feature Management API есть три встроенных фильтра: PercentageFilter
, TimeWindowFilter
, и TargetingFilter
.
В Feature Management API мне больше всего нравится то, что нет потребности в изменении способа проверки, включен ли фича-флаг, потому что всё решается наличием конфигурации.
Наконец, для максимальной гибкости был добавлен Azure Feature Management. Вместо того чтобы хранить конфигурацию в файле appsettings.json
, фича-флаги управляются через портал Azure. Теперь не нужно перезапускать приложение, чтобы увидеть изменения, которые мы вносим в конфигурацию. После внесения этих изменений приложение автоматически обновится во время выполнения через динамическую конфигурацию.
Комментарии