El problema de la configuración
Un problema muy frecuente, pero con muchas soluciones muy malas
Hace poco vi en Twitter a alguien preguntando por una alternativa a Firebase, para poder almacenar información de configuración de una aplicación.
Los que le respondían le nombraban distintas tecnologías, desde Memcached y Redis hasta Amazon AWS AppConfig. Pero nadie trataba de indagar cuál era el problema a resolver.
Imaginen por un momento que él solamente quería guardar un par de parámetros que cambian muy poco. Quizás la solución era simplemente tener un par de valores que se reciben como parámetro en la línea de comando, o en una variable de entorno. No lo sabemos, porque nadie preguntó.
La persona que preguntaba era uno de estos “tech influencer”, e interactuaba de una forma algo extraña, lo que me hizo dudar si realmente estaba resolviendo un problema, o estaba recogiendo información de sus seguidores para armar una lista de herramientas sobre las que hablar más adelante.
Independiente de quién haya realizado la petición inicial, lo que notamos en este caso es una práctica, por desgracia muy común hoy en día, de muchos “ingenieros” e influencers de redes sociales. Enamorarse de soluciones, y como el mítico martillo dorado, aplicar esa misma solución una y otra vez, independiente del problema.
Recuerdo el caso de un equipo que puso parámetros en una tabla en la base de datos y las consultas frecuentes a esta tabla provocaban una contención horrible (para qué hablar de los usuarios que se quedaban esperando a que una consulta a la tabla de parámetros se desbloqueara, para poder seguir trabajando). He visto soluciones peores, como crear micro servicios específicos para leer configuraciones, y cada vez que alguien hacía algo como GetParameter(Key)
generaba una llamada a un endpoint, una y otra vez, sin siquiera una simple caché.
El problema de la configuración tiene muchas aplicaciones, desde simplemente leer parámetros hasta la implementación de Feature Flags. Es uno de esos problemas que es fácil de enunciar, pero no es fácil de solucionar, aunque en principio parezca que sí.
El enunciado suele ser el siguiente:
Necesitamos un almacenamiento del tipo (llave, valor) de modo que guardemos en este configuraciones que usaremos en nuestro programa.
Las preguntas que debes hacer inmediatamente son:
de cuantas configuraciones distintas hablamos
con qué frecuencia se cambiarán estas configuraciones
quién cambiará estas configuraciones
que tan rápido se deben reflejar en el comportamiento del sistema
cuál es la interfaz de programación que esperas tener
Esta última pregunta es vital, porque si te equivocas en todas las anteriores, al menos si defines una buena interfaz de programación para usar esto, vas a poder evolucionar con soluciones cada vez más complicadas.
Veamos esto con un ejemplo.
Tienes que calcular un recargo en el precio basado en un límite, el recargo a aplicar y el límite. Estos valores se cambian entres 1 a 2 veces en el año.
Entonces implementas esto:
const limite = 10_000_000
const recargo = 10
...
if costo < limite {
valor = valor * recargo / 100.00 + valor
}
Esto tiene varios problemas, pero el primero es que cada vez que estos parámetros cambian tienes que recompilar el programa, y volver a instalar la aplicación. Si este código ocurre en el servidor, no es tan “doloroso”, pero si está en una aplicación cliente, estás en serios problemas.
Acá viene la clave de definir la interfaz clara para acceder a tus parámetros:
const limite = GetParameter("limite")
const recargo = GetParameter("recargo")
if costo < limite {
valor = valor * recargo / 100.00 + valor
}
Eso es un avance, porque puedes implementar la obtención de parámetros con cualquier tecnología subyacente, y no necesitas recompilar tu programa, ni redistribuir nada. Pero tiene un problema, los valores se leen una sola vez (normalmente cuando el programa inicia). Eso es problemático, así que vas a querer cambiar por algo así:
if costo < GetParameter("limite") {
valor = valor * GetParameter("recargo") / 100.00 + valor
}
Esto es más dinámico, te podría permitir cambiar estos parámetros en cualquier momento y los valores siempre estarían actualizados. Sin embargo, no tan rápido, pequeño saltamontes. Que pasa si el administrador tiene que cambiar los dos parámetros al mismo tiempo, y esto ocurre cuando se están calculando cientos o miles de facturas. Tendrás miles de errores potenciales de cálculo. Así que te gustaría que la gestión de parámetros maneje este problema de concurrencia.
Quizás es mejor tener algo de este estilo:
if costo < config.GetParameter("limite") {
valor = valor * config.GetParameter("recargo") / 100.00 + valor
}
Y probablemente config
implementa algo de este estilo para actualizar parámetros:
config.BeginUpdate()
config.SetParameter(“limite”, 2_000_000)
confg.SetParameter(“recargo”, 15)
config.EndUpdate()
Config
puede ser un objeto, un módulo, etc. Lo importante es que nos aísla de los detalles de implementación.
El factor crítico ahora es el costo de la llamada a config.GetParameter()
y es lo que hace que este problema sea tan interesante.
Si les interesa distintas formas de resolver esto dale un like a este artículo y si hay suficientes likes, o comentarios, exploraremos diversas maneras de resolver este problema.
Súper interesante cómo abordas el problema, ves los detalles en la implementación y haces notar los casos de borde.
Porfa, continúa en otro post. Quedé metido jaja
Se me vino a la mente el IVA