Skip to content
SP StackPractices
intermediate Por StackPractices

Feature Flags — Release Progresivo y Experimentación Segura

Guía práctica sobre feature flags: patrones de implementación, rollouts progresivos, kill switches, integración con A/B testing y gestión del ciclo de vida de feature flags a escala.

Nota para desarrolladores hispanohablantes: Esta guía incluye ejemplos y convenciones de nomenclatura adaptadas a equipos que trabajan en español. Cuando existen diferencias significativas en terminología técnica entre el inglés y el español, se indican explícitamente para facilitar la comunicación en equipos multiculturales.

Overview

Los feature flags (también llamados feature toggles) desacoplan el despliegue del release. Permiten desplegar código a producción mientras mantienen funcionalidades ocultas, luego habilitarlas gradualmente para usuarios, regiones o porcentajes específicos. También sirven como kill switches para deshabilitar instantáneamente funcionalidades problemáticas sin redeploy.

Esta guía cubre tipos de flags, patrones de implementación, estrategias de rollout y mejores prácticas operacionales.

When to Use

  • Quieres desplegar funcionalidades incompletas sin exponerlas a usuarios
  • Necesitas lanzar funcionalidades gradualmente para monitorear impacto
  • Quieres hacer A/B testing de funcionalidades con usuarios reales
  • Necesitas kill switches de emergencia para funcionalidades críticas
  • Manejas branches de larga duración y quieres mergear código más temprano

Core Concepts

ConceptoDescripción
Feature FlagUn check condicional que habilita o deshabilita un camino de código
Kill SwitchUn flag que deshabilita instantáneamente una funcionalidad en producción
Rollout ProgresivoAumentar gradualmente el porcentaje de usuarios que ven una funcionalidad
Flag DirigidoUn flag habilitado para usuarios, grupos o regiones específicas
Vida del FlagEl período desde creación hasta remoción permanente del código
Deuda TécnicaFlags viejos acumulados que saturan código y configuración

Feature Flag Types

TipoCaso de UsoVida
Flag de releaseOcultar funcionalidades incompletas durante desarrolloCorta (días a semanas)
Flag de experimentoA/B testing y decisiones basadas en datosMedia (semanas a meses)
Flag operacionalCircuit breakers, límites de rate, modos debugLarga (meses a permanente)
Flag de permisoControl de acceso a funcionalidades por tier de usuarioPermanente
Kill switchDeshabilitación de emergencia para funcionalidades riesgosasCorta (removido después de estabilización)

Step-by-Step Feature Flag Implementation

1. Elegir un Sistema de Feature Flags

Decisión build vs buy:

OpciónMejor ParaEjemplos
Open-sourceAuto-hospedado, control totalUnleash, Flagsmith, Flipt
SaaSConfiguración rápida, features enterpriseLaunchDarkly, Split, Optimizely
Build customCasos simples, integración estrechaConfig en-app + base de datos
Archivos de configFlags estáticos, sin cambios en runtimeYAML/JSON configs
# Ejemplo: Sistema simple de feature flags custom
from dataclasses import dataclass
from typing import Optional
import hashlib

@dataclass
class FeatureFlag:
    name: str
    enabled: bool
    rollout_percentage: float = 100.0
    target_users: Optional[list[str]] = None

class FeatureFlagManager:
    def __init__(self):
        self.flags = {}
    
    def register(self, flag: FeatureFlag):
        self.flags[flag.name] = flag
    
    def is_enabled(self, flag_name: str, user_id: str = None) -> bool:
        flag = self.flags.get(flag_name)
        if not flag:
            return False
        
        if not flag.enabled:
            return False
        
        # Verificar usuarios dirigidos
        if flag.target_users and user_id:
            return user_id in flag.target_users
        
        # Rollout basado en porcentaje
        if flag.rollout_percentage < 100 and user_id:
            hash_value = int(hashlib.md5(f"{flag.name}:{user_id}".encode()).hexdigest(), 16)
            user_bucket = hash_value % 100
            return user_bucket < flag.rollout_percentage
        
        return True

# Uso
ffm = FeatureFlagManager()
ffm.register(FeatureFlag("new-dashboard", enabled=True, rollout_percentage=10))

if ffm.is_enabled("new-dashboard", user_id="user-123"):
    show_new_dashboard()
else:
    show_legacy_dashboard()

2. Implementar Rollout Progresivo

Aumentar exposición gradualmente mientras monitoreas:

# Ejemplo: Etapas de rollout progresivo
ROLLOUT_STAGES = [
    {"name": "dev-team", "percentage": 0, "target_users": ["dev1", "dev2", "qa1"]},
    {"name": "1-percent", "percentage": 1, "target_users": None},
    {"name": "10-percent", "percentage": 10, "target_users": None},
    {"name": "50-percent", "percentage": 50, "target_users": None},
    {"name": "full-release", "percentage": 100, "target_users": None},
]

def advance_rollout(flag_name: str, current_stage: int):
    if current_stage < len(ROLLOUT_STAGES) - 1:
        next_stage = ROLLOUT_STAGES[current_stage + 1]
        update_flag(flag_name, 
            rollout_percentage=next_stage["percentage"],
            target_users=next_stage["target_users"]
        )
        print(f"Avanzado {flag_name} a etapa: {next_stage['name']}")
    else:
        print(f"{flag_name} ya está al 100%")

Progresión de rollout:

  1. Solo internos: Habilitar para equipo de desarrollo (0% + usuarios target)
  2. Usuarios beta: Habilitar para early adopters amigables (0% + lista beta)
  3. 1% rollout: Exponer a 1% del tráfico
  4. 10% rollout: Monitorear métricas a pequeña escala
  5. 50% rollout: Validar a volumen significativo
  6. 100% rollout: Release completo
  7. Remover flag: Limpiar código condicional

3. Agregar Kill Switches

Deshabilitar instantáneamente funcionalidades sin desplegar:

# Ejemplo: Patrón de kill switch
def process_payment(order):
    # Kill switch para procesamiento de pagos
    if not feature_flags.is_enabled("payment-processing-v2"):
        return process_payment_v1(order)
    
    try:
        result = process_payment_v2(order)
        return result
    except Exception as e:
        # Auto-fallback si nueva versión falla
        if feature_flags.is_enabled("payment-auto-fallback"):
            return process_payment_v1(order)
        raise

Mejores prácticas de kill switch:

  • Cada nueva funcionalidad obtiene un kill switch por defecto
  • Documenta qué funcionalidades tienen kill switches en tu runbook
  • Practica drills de kill switch trimestralmente
  • Configura alertas cuando un kill switch se active
  • Asegúrate de que los kill switches tengan latencia mínima (cachear valores de flags)

4. Monitorear Rendimiento de Flags

Rastrear métricas para funcionalidades con flags:

MétricaPor Qué Importa
Latencia de evaluación de flagEvaluaciones lentas agregan overhead de request
Tasa de error por estado de flagDetectar si funcionalidades habilitadas causan errores
Engagement de usuarioComparar uso de funcionalidad entre grupos on/off
Impacto en conversiónMedir efecto de negocio de la funcionalidad
Viejez de flagIdentificar flags que han estado activos por mucho tiempo
# Ejemplo: Dashboard de monitoreo de flags
panels:
  - title: "Tasa de Evaluación de Feature Flags"
    query: 'rate(feature_flag_evaluations_total[5m])'
  - title: "Kill Switches Activos"
    query: 'feature_flag_enabled{name=~".*-kill-switch"}'
  - title: "Viejez de Flags"
    query: 'time() - feature_flag_last_modified > 7776000'  # 90 días

5. Gestionar Ciclo de Vida de Flags

Los flags no deberían vivir para siempre:

# Ejemplo: Workflow de limpieza de flags
# 1. Identificar flags estancados (habilitados por >30 días sin cambios)
# 2. Verificar que funcionalidad es estable y completamente adoptada
# 3. Crear ticket para remover flag del código
# 4. En código: remover condicional, mantener solo rama true
# 5. Remover flag de configuración
# 6. Desplegar limpieza
# 7. Verificar que no hay regresiones

Reglas de ciclo de vida:

  • Establecer fechas de expiración en flags de release y experimento (30-60 días)
  • Revisar todos los flags mensualmente en standup de ingeniería
  • Archivar flags removidos en un changelog para propósitos de auditoría
  • Nunca remover un flag antes de confirmar que la funcionalidad es estable

Best Practices

  • Mantén flags simples. Un flag por funcionalidad, no condicionales anidados.
  • Default seguro. Si el sistema de flags cae, default al comportamiento probado.
  • Evalúa flags una vez por request. Cachear el resultado para evitar lookups repetidos.
  • Prueba ambos caminos. Los tests unitarios deben cubrir estados habilitado y deshabilitado.
  • Documenta propósito del flag. Cada flag necesita un owner, descripción y fecha de expiración.
  • Evita interdependencias de flags. Combinar flags crea complejidad combinatoria.

Common Mistakes

  • Dejar flags en código indefinidamente. Flags estancados crean deuda técnica y código muerto.
  • Usar flags para control de acceso permanente. Usa RBAC apropiado para permisos de larga duración.
  • Evaluar flags en bucles calientes. Las evaluaciones de flag en bucles ajustados dañan rendimiento.
  • Estado de flag inconsistente entre servicios. Asegúrate de que los flags estén sincronizados en sistemas distribuidos.
  • Olvidar probar el camino deshabilitado. El camino default es lo que la mayoría de usuarios ven.

Variants

  • Configuración dinámica: Más amplia que flags — incluye umbrales, límites y parámetros de funcionalidad
  • Flags contextuales: Flags que varían por hora del día, geografía o tipo de dispositivo
  • Flags multi-variante: Flags con múltiples estados (testing A/B/C/D)
  • Flags del lado del cliente: Evaluados en browser/mobile para variaciones de UI

FAQ

Q: ¿Cuál es la diferencia entre un feature flag y un toggle de configuración? Los feature flags son de corta duración y ligados a caminos de código. Los toggles de configuración son settings operacionales de larga duración.

Q: ¿Cómo manejo feature flags en un sistema distribuido? Usa un servicio de flags centralizado con caching. Evalúa flags al inicio del request y propaga a través de contexto.

Q: ¿Pueden los feature flags ralentizar mi aplicación? Sí, si se evalúan frecuentemente. Usa caching en memoria, evaluaciones batch, y evita checks de flag en bucles ajustados.

Q: ¿Cuándo debería remover un feature flag? Tan pronto como la funcionalidad sea estable y completamente lanzada. Apunta a remoción dentro de 30 días del release completo.

Conclusion

Los feature flags son esenciales para la entrega continua moderna. Te permiten desplegar con confianza, lanzar gradualmente y reaccionar instantáneamente a problemas. Trata los flags como andamiaje temporal, no arquitectura permanente, y límpialos agresivamente para mantener tu codebase saludable.