Hola a todos! Ya llevamos una serie de artículos dedicados a la implementación de Feature Flags. Entre otras cosas, vimos como utilizar algunos filtros condicionales que el framework nos provee y cómo aplicar middlewares y filtros MVC.

En el post de hoy veremos uno de los requerimientos más utilizados y sin los cuales los Feature Flags no serían tan poderosos: Feature Flags personalizados.

Contexto

Cuando analizamos los Feature Flags condicionales vimos como podemos aplicar algún tipo de lógica, que puede ser una ventana de tiempo (TimeWindowFilter) o un porcentaje de peticiones (PercentageFilter), para activar o desactivar funcionalidades. Claro quu si bien agregan valor, no son suficientes.

En ocasiones necesitamos tener un mayor control sobre como determinar si una funcionalidad se encuentra activa o no, incluso podemos necesitar consultar servicios externos o una base de datos.

Requerimiento

Como parte del desarrollo de nuestra estrategia de expansión de nuestro negocio eCommerce, queremos ofrecer una lista de productos especialmente seleccionado con un descuento especial promocional. Este descuento estará disponible solo los días viernes.

Implementación

Armar nuestro propio filtro requiere implementar la interface IFeatureFilter, la cuál define solo el método EvaluateAsync. Aquí podremos escribir nuestra lógica de negocio y retornar un valor booleano indicando si la funcionalidad se encuentra activa o no:

public interface IFeatureFilter : IFeatureFilterMetadata
{
    Task<bool> EvaluateAsync(FeatureFilterEvaluationContext context);
}

Los pasos necesarios para completar nuestro filtro son:

  1. Implementar la interface IFeatureFilter
  2. Registrar el filtro
  3. Agregar la configuración
  4. Modificar la vista

IFeatureFilter

La idea de nuestro filtro es retornar true si el día de la semana es viernes, de lo contrario retornar false. Para hacerlo un poco más flexible, vamos a parametrizar el día de la semana de forma que podamos utilizarlo para otras promociones.

Crearemos una clase WeeklyOffersFeatureFilter e implementaremos la interface IFatureFilter. El código debería verse mas o menos así:

[FilterAlias("WeeklyOffersFilter")]
public class WeeklyOffersFeatureFilter : IFeatureFilter
{
    public Task<bool> EvaluateAsync(FeatureFilterEvaluationContext context)
    {
        var dayOfWeek = context.Parameters.GetValue<string>("DayOfWeek");
        var result = DateTime.Now.DayOfWeek.ToString() == dayOfWeek;

        return Task.FromResult(result);
    }
}

Analicemos los aspectos importantes de nuestro filtro:

  • [FilterAlias("WeeklyOffersFilter")]:
    Este atributo es necesario para indicarle al framework el nombre del filtro a utilizar. Es decir, “para el Feature Flag WeeklyOffers utilizar el filtro cuyo alias es WeeklyOffersFilter. Tiene que ser el mismo que utilizaremos en la configuración en el archivo appsettings.json.
  • context.Parameters.GetValue<string>("DayOfWeek"):
    Mediante el contexto podemos leer los parámetros establecidos en la configuración. En este caso estamos obteniendo el parámetro "DayOfWeek".
  • result:
    Simplemente comparamos el día de la semana actual contra el parámetro.

Registrar el filtro

Como siempre, solo tenemos que registrarlo utilizando el método de extensión AddFeatureFilter<>() en la clase Startup:

public class Startup
{
    public void ConfigureServices(IServiceCollection services)
    {
        // ...

        services.AddFeatureManagement()
            .AddFeatureFilter<WeeklyOffersFeatureFilter>();
    }

    public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
    {
        // ...
    }
}

Configuración

Finalmente necesitamos generar una nueva configuración en el archivo appsettings.json:

{
  // ...
  "FeatureManagement": {
    "WeeklyOffers": {
      "EnabledFor": [
        {
          "Name": "WeeklyOffersFilter",
          "Parameters": {
            "DayOfWeek": "Friday"
          }
        }
      ]
    }
  }
}

Lo mas importante aqui es la linea 7, donde indicamos el nombre del filtro a utilizar, que tiene coincidir con el valor del atributo [FilterAlias("WeeklyOffersFilter")] que utilizamos cuando implementamos la interface.

Vista

El único paso que nos queda pendiente es modificar la vista, esto ya lo hemos hecho en post anteriores. En nuestro caso modificamos la vista del menú principal (_Layout.cshtml) para incluir una nueva entrada cuando nuestro Feature Flag WeeklyOffers se encuentre activa.

<feature name="WeeklyOffers">
  <li class="nav-item">
    <a asp-controller="Home" asp-action="NewFeature">
        Ofertas semanales
    </a>
  </li>
</feature>

Conclusión

Poder implementar filtros personalizados nos da mucha flexibilidad a la hora de habilitar funcionalidades. Por ejemplo, si nuestra funcionalidad depende de otro servicio que puede no estar funcionando o no estar activo aún, podríamos ejecutar un recuest a dicho servicio y devolver true si y solo si el request es exitoso.

En el próximo post veremos como combinar Feature Flags con Azure App Configuration para guardar nuestras configuraciones de forma centralizada y segura.