Durante años el despliegue y el lanzamiento fueron la misma cosa: merge a main, build a producción y esperar que nada expliquara. El problema es que desplegar código y exponer funcionalidad son decisiones distintas. Un deploy puede ser perfecto y aun así la feature puede ser un desastre para los usuarios. Los feature flags separan ambas decisiones: el código llega a producción apagado y se enciende cuando tú decides, para quien tú decides.
Esta separación es la base de la entrega progresiva: liberar a un 5% de usuarios, observar métricas, subir al 25%, validar, y así hasta el 100%. Y si algo falla, un kill switch apaga la feature en segundos, sin rollback ni redeploy.
1. Deploy ≠ Release
Con flags, cada merge a main llega a producción en estado latente. Esto habilita trunk-based development real: ramas de vida corta, integración continua frecuente y cero ramas long-lived que pudran. El código incompleto se integra detrás de un flag apagado; la feature se "relea" más tarde con un cambio de configuración.
- Deploy: mover código a producción. Frecuente, aburrido, automatizado.
- Release: exponer la funcionalidad a usuarios. Controlado, gradual, reversible.
2. Evaluación con fallback: el flag nunca debe tumbar la app
Un flag es una dependencia más, y toda dependencia puede fallar. Si el proveedor de flags no responde, tu aplicación debe degradar al valor por defecto, no colgarse. La regla: cada llamada de evaluación tiene timeout corto y fallback explícito.
// Evaluación de un flag con fallback seguro
function isEnabled(flag, ctx) {
try {
return client.getBooleanDetail(flag, ctx).enabled;
} catch (err) {
// Si el proveedor cae, el flag vuelve a su estado por defecto
return defaults[flag] ?? false;
}
}
if (isEnabled('checkout-v2', { userId, region })) {
return renderCheckoutV2();
}
return renderCheckoutV1();
El valor por defecto debe ser el comportamiento seguro: para un flag de riesgo, false; para un kill switch que protege de una dependencia externa, probablemente el comportamiento anterior al cambio.
3. Rollout progresivo por porcentaje
El patrón central de la entrega progresiva es el percentage rollout: el flag activa la feature para un porcentaje de usuarios que crece según lo que digan las métricas. La clave técnica es el bucketing determinista: el mismo usuario debe caer siempre en el mismo bucket, en cualquier instancia y en cualquier momento.
// Rollout progresivo por porcentaje (bucketing estable)
function inRollout(flag, userId) {
const cfg = config.get(flag); // { enabled, percentage }
if (!cfg?.enabled) return false;
// Hash determinista: el mismo usuario siempre
// cae en el mismo bucket, en cualquier réplica.
const bucket = hash(flag + ':' + userId) % 100;
return bucket < cfg.percentage; // 5 -> 25 -> 50 -> 100
} - Hash determinista: sin él, un usuario ve la feature y luego no; el soporte lo sufre.
- Segmentación: además del porcentaje, filtra por región, plan o internal users antes del rollout público.
- Criterios de avance: error rate, latencia p95 y conversión definidos antes de subir el porcentaje, no después.
4. Kill switches: el seguro de vida de las features
No todo flag sirve para lanzar features nuevas. Un kill switch envuelve una dependencia frágil o un cambio de comportamiento sensible y permite desactivarlo al instante. Es la diferencia entre un incidente de 2 minutos y uno de 40: el rollback de un flag es un cambio de configuración; el rollback de un deploy implica recompilar, re-desplegar y rezar para que la migración de datos no estorbe.
5. La deuda de los flags es real
Los feature flags son como los parámetros de configuración: se acumulan. Cada flag vivo duplica caminos de ejecución que alguien debe mantener y probar. La disciplina que evita el caos:
- Nombre y dueño: cada flag declara qué feature es, quién lo creó y cuándo expira.
- Fecha de caducidad: si un flag lleva 90 días encendido al 100%, el siguiente ticket es eliminarlo.
- Auditoría: un inventario periódico de flags activos, con alertas para los abandonados.
- Tipos separados: no mezcles flags de release (temporales) con flags de configuración (permanentes) en el mismo sistema ni en la misma convención de nombres.
Resumen
Los feature flags convierten el lanzamiento en una decisión reversible y gradual en lugar de un acto de fe. Desacoplan deploy de release, hacen viable el trunk-based development y te dan un kill switch cuando las métricas dicen basta. Empieza con un solo flujo crítico, mide, y elimina cada flag en cuanto cumpla su misión: la entrega progresiva no es una herramienta, es un hábito de ingeniería.