← maurobernal.com.ar

Feature Flags en .NET: Separando el Deploy del Release con Microsoft.FeatureManagement

Uno de los cambios más importantes que tuve en mi forma de trabajar en los últimos años fue aprender a separar el despliegue del lanzamiento. Hasta ese momento, cada vez que terminaba una feature la subía a producción directamente. Si algo salía mal, había que hacer rollback de todo. Con los Feature Flags, eso cambió completamente: el código puede estar en producción, pero inactivo. Lo activás cuando querés, para quien querés, sin tocar el deploy. En .NET esto se implementa con Microsoft.FeatureManagement, y en este artículo te muestro cómo funciona.

¿Qué son los Feature Flags y por qué importan?

Los Feature Flags (también llamados Feature Toggles) son interruptores que habilitan o deshabilitan funcionalidades en tiempo de ejecución. Su valor principal no es técnico sino estratégico: permiten que el equipo de desarrollo haga merge continuo a la rama principal (Trunk-based development) sin bloquear a nadie, mientras el código de la nueva feature espera desactivado hasta que esté listo para salir.

Esto los diferencia del versionado de APIs, que apunta a mantener contratos estables para distintos consumidores. Los Feature Flags apuntan a estrategias de CI/CD: lanzamientos progresivos (Canary releases), pruebas A/B y acceso gradual a nuevas funcionalidades. Y lo más importante: su estado se modifica en caliente, cambiando el appsettings.json o variables de entorno, sin recompilar ni redesplegar.

1. Evaluación Básica: El Interruptor On/Off

La forma más simple de Feature Management. Un flag booleano que habilita o deshabilita una ruta de código. Existe principalmente para resolver el problema de los feature branches de larga duración: en lugar de mantener una rama separada durante semanas y sufrir un merge doloroso, el código convive en la rama principal desactivado, esperando su momento.

Gracias a la recarga dinámica de IConfiguration en .NET, cambiar el valor en el archivo de configuración actualiza el comportamiento de la app instantáneamente, sin reiniciarla.

Configuración en appsettings.json:

{
  "FeatureManagement": {
    "NewPaymentGateway": false
  }
}

Implementación en C#:

using Microsoft.FeatureManagement;

// Registro en Program.cs:
// builder.Services.AddFeatureManagement();

public class PaymentService
{
    private readonly IFeatureManager _featureManager;

    public PaymentService(IFeatureManager featureManager)
    {
        _featureManager = featureManager;
    }

    public async Task ProcessPaymentAsync(Order order)
    {
        // Se evalúa en tiempo de ejecución.
        // Cambiar el flag en appsettings.json actualiza este comportamiento sin reiniciar la app.
        if (await _featureManager.IsEnabledAsync("NewPaymentGateway"))
        {
            await ProcessWithStripeAsync(order); // Nueva pasarela
        }
        else
        {
            await ProcessWithLegacySystemAsync(order); // Sistema anterior
        }
    }
}

La primera vez que usé esto en un proyecto real, cambié el comportamiento de la pasarela de pago en producción cambiando un false por true en un archivo de configuración. Sin deploy, sin downtime, sin nervios.

2. FeatureGate: Bloqueando Endpoints Completos

A veces no alcanza con un condicional dentro de la lógica de negocio. Si la feature expone un endpoint nuevo, queremos que ese endpoint directamente no exista mientras el flag esté apagado. El atributo [FeatureGate] intercepta la petición HTTP en el pipeline de ASP.NET Core y devuelve automáticamente un 404 Not Found si el flag está desactivado. La lógica de negocio queda limpia, sin condicionales.

using Microsoft.AspNetCore.Mvc;
using Microsoft.FeatureManagement.Mvc;

[ApiController]
[Route("api/[controller]")]
public class ReportsController : ControllerBase
{
    // Este endpoint solo existe si "AdvancedReporting" es true.
    // Si está apagado, responde 404 automáticamente.
    [HttpGet("advanced")]
    [FeatureGate("AdvancedReporting")]
    public IActionResult GetAdvancedReport()
    {
        return Ok(new { Message = "Reporte avanzado generado exitosamente." });
    }
}

Útil para exponer funcionalidades premium, features en beta o endpoints que todavía están en desarrollo pero ya mergeados a main.

3. Feature Filters: Reglas Dinámicas y Canary Releases

Los flags booleanos globales son el punto de partida, pero las situaciones reales suelen ser más complejas. ¿Qué pasa si querés activar una feature solo para el 10% del tráfico? ¿O solo durante ciertos horarios? ¿O solo para usuarios internos? Ahí entran los Feature Filters.

El más directo para Canary releases es el filtro de porcentaje. En lugar de un booleano, definís una regla:

{
  "FeatureManagement": {
    "RedesignedUI": {
      "EnabledFor": [
        {
          "Name": "Percentage",
          "Parameters": {
            "Value": 25
          }
        }
      ]
    }
  }
}

El 25% de las peticiones verán la nueva UI. El 75% restante, la versión anterior. Sin tocar el código.

using Microsoft.FeatureManagement;
using Microsoft.FeatureManagement.FeatureFilters;

// Registro en Program.cs incluyendo el filtro:
// builder.Services.AddFeatureManagement().AddFeatureFilter<PercentageFilter>();

public class UIController : Controller
{
    private readonly IFeatureManager _featureManager;

    public UIController(IFeatureManager featureManager)
    {
        _featureManager = featureManager;
    }

    public async Task<IActionResult> Index()
    {
        if (await _featureManager.IsEnabledAsync("RedesignedUI"))
        {
            return View("Index_v2"); // 25% del tráfico
        }

        return View("Index_v1"); // 75% del tráfico
    }
}

Con este patrón podés hacer un lanzamiento progresivo real: empezás con el 5%, observás métricas, subís a 25%, luego a 50%, y cuando estás seguro activás al 100%. Todo sin un solo redeploy.

¿Cuándo usar Feature Flags vs. versionado de API?

Es una confusión frecuente. La regla práctica que uso:

  • Feature Flags → cuando el cambio es interno o progresivo y querés controlar cuándo se activa en producción sin cambiar el contrato público de la API.
  • Versionado de API → cuando el cambio rompe el contrato y tenés consumidores externos que necesitan tiempo para adaptarse.

No son excluyentes: podés usar ambos en el mismo proyecto para propósitos distintos.

Próximos pasos

Lo que vimos acá es la base. El ecosistema de Microsoft.FeatureManagement va más lejos:

  • Custom Feature Filters: habilitar features según el Tenant de la base de datos, el rol del usuario o cualquier lógica de negocio propia.
  • Azure App Configuration: centralizar todos los flags en un servicio externo, modificarlos desde un panel sin tocar archivos de configuración y con soporte para targeting (activar por usuario específico, grupo o región).

¿Querés que profundice en alguno de estos dos temas en un próximo artículo? Dejalo en los comentarios.

Comentarios

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

Este sitio usa Akismet para reducir el spam. Aprende cómo se procesan los datos de tus comentarios.