Entender el problema >>> solución
El problema de la configuración, parte final
Es momento de cerrar esta miniserie sobre el problema de la configuración.
Este asunto fue inspirado, como les conté en la primera parte, por una pregunta en X (Twitter) de un tech influencer, que quería ver herramientas alternativas a Firebase para almacenar la configuración de una aplicación.
Establecimos en ese momento que el problema se puede enunciar de este modo:
Necesitamos un almacenamiento del tipo (llave, valor), que nos permita guardar en este las configuraciones que usaremos en nuestro programa.
También dijimos, en la segunda parte, que tenemos estos tipos de configuraciones:
Secretos: corresponden a valores críticos que no deben ser divulgados, por contener información crítica, como las credenciales de conexión a la base de datos, API keys, llaves de cifrado, etc.
Parámetros no funcionales, que son usados internamente por el programa, por ejemplo, la URL de un servicio, o la ruta de cierto directorio donde se almacenan ciertos archivos.
Parámetros funcionales o de negocio, por ejemplo ciertos valores que pueden alterar algunos cálculos, o restricciones legales como impuestos, tasas, aranceles, etc. Acá también se incluyen los “feature flags”, que definen si cierta funcionalidad va a activarse y cuáles serán sus parámetros de operación.
Con la excepción de los secretos, el almacenamiento de los parámetros es algo fácil de resolver. Pero, debemos considerar al menos los siguientes puntos:
¿de cuántas configuraciones distintas hablamos?
¿con qué frecuencia se cambiarán estas configuraciones?
¿quién cambiará estas configuraciones?
¿qué tan rápido se deben reflejar en el comportamiento del sistema?
¿cuál es la interfaz de programación que esperas tener?
Si consideras que esto hay que resolverlo usando Firebase, porque este producto implementa un base de datos de diccionario (llave, valor), entonces no has pensado suficiente impacto que tendrá esto en términos de gestión de infraestructura, de latencia, y un montón de otras consideraciones.
La solución adecuada depende de tu problema específico.
Muchas veces basta con tener la configuración en variables de entorno, las que se pueden persistir en archivos.
Un ejemplo de esto es el de “dot-env”, que se encuentra implementado en muchos lenguajes como Javascript y Python, en este caso las variables se almacenan en archivos que tienen este simple formato:
VARIABLE=VALOR
Típicamente, el archivo se llama .env
, y los valores dentro del archivo pueden ser “sobreescritos” al setear variables de entorno. En este caso el flujo que implementan las bibliotecas “dot-env” es primero adoptar el valor de una variable de entorno, y si no existe, entonces tomar el valor desde el archivo.
Esto está muy bien para unos pocos parámetros funcionales, que no cambian mucho. Pero no es muy seguro, sobre todo si colocamos secretos en los archivos. Además un error muy común es que el archivo de configuración lo colocan en el repositorio de código, y de este modo termina filtrándose. Sin embargo, un archivo de ejemplo puede ser útil que esté en el repositorio.
Java tiene los archivos de properties, que pueden ser incluidos en los binarios, y pueden ser sobreescritos usando el parámetro -D
de la JVM, incluso se puede tomar el valor desde las variables de entorno, usando este mecanismo.
Si quieres puedes almacenar las variables en uno motor de base de datos, relacional o no. Si vas por este lado, aumentas la seguridad, y la gestión centralizada (los archivos de configuración y las variables de entorno, requieren del uso intensivo de buenas herramientas de CI/CD para funcionar bien en un entorno altamente distribuido).
El costo de usar bases de datos es que aumentas la latencia e incluso puedes poner en riesgo la disponibilidad del servicio de configuración. Es por eso que en general las soluciones de gestión de configuración tienen un caché en memoria de los valores.
Como la gestión de la configuración es algo que al principio parte simple, y se complica con el tiempo, la mejor manera es aislar el problema, usando algunas primitivas básicas (como GetValue
y SetValue
) y aislando el medio de almacenamiento de los parámetros del resto de la aplicación.
En los siguientes diagramas hay una propuesta de cómo puedes crear tu propio “gestor de configuraciones”:
Usamos un diccionario (hashmap o algo similar) para guardar los valores en memoria. Estos valores se respaldan usando una capa de persistencia, que puede ser cualquier cosa, archivos .env, archivos XML, JSON, .properties, o cualquier formato ad hoc, e incluso puede ser una base de datos de cualquier tipo (incluido Firebase). Lo importante es que no tienes que tomar la decisión al principio. Al aislar esa capa de persistencia puedes medir el impacto de la misma en términos de rendimiento y gestión.
Y esta es la lección más relevante de todo esto, y que las personas que participaban en el hilo con el tech-influencer, no entendían. No hay que partir de la solución, ni de la tecnología o herramienta a usar. Hay que entender el problema primero, y si no lo entiendes bien, toma una estrategia que te permita aislar ese problema para poder tratar de manera iterativa y experimental distintas soluciones.
¿Te gustó? Entonces te invito a compartir este artículo con tus amigos o colegas usando el botón que sigue:
Y si no lo has hecho, te invito a suscribirte:
Nos vemos la próxima semana.