Prefacio: ¿Por qué las funcionalidades rompen los lanzamientos?
\nCada desarrollador al menos una vez se ha encontrado en una situación donde una nueva y brillante funcionalidad ya está lista, pero no se puede lanzar. Ya sea porque no pasó el QA completo, porque marketing aún no preparó los banners, o simplemente porque da miedo presionar el botón "Deploy" un viernes por la noche. En ese momento, normalmente empezamos a escribir if, cambiar BuildConfig o, peor aún, comentar el código.
¿Le suena familiar? Bienvenido al mundo de los feature flags (o feature toggles). No es solo "otra cosa arquitectónica". Es su salvavidas, que le permite desplegar código en producción, pero activarlo solo para unos pocos elegidos. En este artículo, analizaremos cómo implementar feature flags en proyectos Kotlin, desde soluciones simples hasta sistemas avanzados. Y sí, habrá mucho código.
\n\n¿Qué es un Feature Flag y por qué lo necesita?
\nUn Feature Flag (también conocido como feature toggle) es un interruptor de software que permite activar o desactivar una funcionalidad sin cambiar el código ni realizar un nuevo despliegue. Imagine que puede subir un nuevo algoritmo de recomendaciones a producción, pero hacerlo activo solo para el 5% de los usuarios. O activarlo solo para empleados de la empresa para pruebas internas. Genial, ¿verdad?
\nAquí hay varios escenarios donde los feature flags son indispensables:
\n- \n
- Lanzamientos canary: Despliega una nueva funcionalidad en el 1% de los servidores, monitorea errores y aumenta gradualmente el porcentaje. \n
- Pruebas A/B: Verifica qué versión de la UI convierte mejor, sin copiar todo el proyecto. \n
- Interruptor de apagado: Si la nueva funcionalidad empieza a consumir mucha memoria o causa un error, simplemente la desactivas con un movimiento (o una solicitud API). \n
- Separación del lanzamiento y el despliegue: El código está subido, pero la funcionalidad "duerme" hasta la fecha X. \n
En Kotlin, que se usa activamente tanto para backend (Ktor, Spring Boot) como para aplicaciones móviles (Android), los feature flags se vuelven especialmente relevantes debido al tipado estricto y los requisitos de limpieza del código.
\n\nArquitectura: Cómo no convertir las banderas en espaguetis
\nEl error más grande de los principiantes es esparcir if (flag.isEnabled()) { ... } else { ... } por todo el proyecto. Esto lleva a que después de un mes no puedas entender qué ramas de código están vivas y cuáles están muertas. Necesitamos gestión de funcionalidades, no interruptores caóticos.
Una buena arquitectura se basa en el principio de inversión de dependencias. Su código de negocio no debe saber de dónde proviene el valor de la bandera (de un archivo, base de datos o servicio externo). Simplemente pregunta: "Oye, FeatureFlagService, ¿la funcionalidad new_checkout está activada?"
Consideremos dos enfoques: uno simple (para proyectos pequeños) y uno avanzado (para microservicios y Kubernetes).
\n\n1. Enfoque simple: Configuración y Enum
\nSi necesita empezar rápidamente y no está construyendo un sistema con un millón de solicitudes por segundo, puede arreglárselas con un simple enum class y un archivo de configuración (por ejemplo, application.conf para Ktor o application.yml para Spring).
Creemos un enum de todas las funcionalidades:
\nenum class Feature(val key: String) {\n NEW_PAYMENT_FLOW("feature.new-payment-flow"),\n DARK_MODE("feature.dark-mode"),\n SMART_SEARCH("feature.smart-search")\n}\nAhora el servicio que lee la configuración:
\nclass FeatureFlagService(private val config: Map<String, Boolean>) {\n\n fun isEnabled(feature: Feature): Boolean {\n return config.getOrDefault(feature.key, false)\n }\n\n // Para pruebas A/B se puede añadir aleatorización\n fun isEnabledForUser(feature: Feature, userId: String): Boolean {\n if (!isEnabled(feature)) return false\n // Hash simple para dividir en grupos\n val group = userId.hashCode() % 100\n return group < 50 // 50% de los usuar