21 readsFeature flags · Fintech · Arquitectura

Una feature flag que mueve dinero no puede fallar abierta

Una feature flag que mueve dinero no puede fallar abierta

Los payouts dejaron de despacharse.

No hubo excepción. No hubo alerta. No hubo una sola línea roja en los logs. El job corría cada minuto, encontraba las órdenes que tocaba, entraba en la función que las despacha y salía sin hacer nada. Un no-op perfecto, repetido durante horas, con métricas de ejecución impecables: el proceso "funcionaba".

La causa estaba en una línea que preguntaba si una feature flag estaba activa. La key que consultaba había sido renombrada semanas antes en una limpieza de catálogo. Nadie tocó el job. Simplemente, la flag que preguntaba ya no existía, y una flag que no existe devuelve su valor por defecto.

El default es una decisión, aunque no la escribas

Todo sistema de feature flags responde algo cuando le preguntas por una key desconocida. Ese algo es una decisión de diseño, y casi siempre se toma por omisión: alguien eligió false porque parecía lo prudente, o true porque no romper era la prioridad, y esa elección quedó enterrada en una utilidad que nadie vuelve a mirar.

El problema es que "lo prudente" no significa lo mismo en todas partes.

Piensa en dos flags del mismo sistema. Una decide si se muestra una pestaña en el menú. La otra decide si se despachan pagos a proveedores. Si ambas responden lo mismo ante una key ausente, una de las dos está mal.

Nosotros teníamos las dos, y aprendimos cada lado por separado.

El lado que falla cerrado

En el BackOffice, las entradas del menú se resolvían contra un manifiesto de flags. Cuando el catálogo se reorganizó, unas cuantas entradas quedaron apuntando a keys que ya no estaban. Como el default era false, treinta y dos nodos de menú desaparecieron de la interfaz.

Nadie perdió dinero. Pero durante un tiempo hubo módulos completos que existían, estaban desplegados y funcionaban, y eran invisibles: no había forma de llegar a ellos porque el menú los consideraba apagados. El equipo de operaciones reportó "se perdieron pantallas", y la búsqueda empezó, como siempre, por el sitio equivocado: el código de las pantallas.

Fallar cerrado fue lo correcto —una pestaña que no debería verse es peor que una que falta—, pero el fallo fue silencioso, y esa es la otra mitad del problema.

El lado que no puede fallar abierto ni cerrado

Con el dinero, ninguna de las dos respuestas sirve.

Si la flag falla abierta, un despacho que debía estar detenido se ejecuta. Pagas dos veces, o pagas algo que estaba en revisión.

Si falla cerrada, ocurre lo de arriba: el dinero deja de moverse y el sistema te dice que todo va bien. Las órdenes se acumulan, los clientes esperan, y tus paneles siguen verdes porque técnicamente nada falló.

La conclusión a la que llegamos es incómoda pero simple: en un camino de dinero, una flag ausente no es un valor por defecto, es un error. No debe resolverse, debe gritar. Preguntar por una key que no existe significa que el código y el catálogo se han desincronizado, y eso no es una condición de negocio: es un bug de despliegue.

Desde entonces, las flags que gobiernan movimiento de dinero se validan al arrancar contra el catálogo. Si una key no existe, el arranque falla ruidosamente en vez de degradar en silencio. Es mucho mejor no desplegar que desplegar un sistema que ha dejado de mover dinero sin decírselo a nadie.

Tres reglas que salieron de esto

Una flag no apaga un servicio de negocio. Costó entenderlo: si quieres dejar de ofrecer un método de pago, eso es un estado del catálogo (is_active), no una feature flag. Las flags gobiernan código nuevo frente a código viejo; los catálogos gobiernan qué ofrece el negocio. Mezclarlos te deja sin saber por qué algo no aparece: ¿está desactivado, o hay una flag apagada en algún sitio?

Las flags con hijos se apagan en cascada. Si apagas un módulo pero sus submódulos siguen encendidos, quedan huérfanos: rutas vivas sin entrada, permisos que conceden acceso a pantallas inalcanzables. La flag padre tiene que arrastrar a las hijas.

El cobro nunca es apagable. Ninguna flag puede dejar una operación sin su comisión aplicada. Si el camino nuevo aún no sabe cobrar, el camino nuevo no se enciende. No hay estado intermedio en el que el producto funcione pero deje de cobrar: eso no es un rollout parcial, es regalar el servicio.

La pregunta que hago ahora

Cuando reviso un sistema con feature flags, ya no pregunto cuántas hay ni si están documentadas. Pregunto una sola cosa:

¿Qué pasa exactamente cuando el código consulta una flag que ya no existe?

Si la respuesta es "devuelve false", pregunto qué controlan las flags. Si alguna toca dinero, el siguiente descuadre ya tiene fecha: aparecerá el día que alguien haga limpieza en el catálogo, y no habrá ni un error en los logs para explicarlo.

Share

Comments

No comments yet. Be the first.

Never published. I only use it to reply to you.

Comments are reviewed before they appear.