4dim / Notas

Dos copias de la misma verdad divergen: 11 contra 4

Una cabecera escrita dos veces tenía once temas en un lado y cuatro en el otro. La lista blanca de nginx que daba 404 a cada ruta nueva, el service worker que pudo filtrar datos entre inquilinos, y el comentario que mentía. La regla que sale de todo eso.

Once contra cuatro

Si tu web pública y tu panel de clientes son dos programas distintos, esta nota cuenta lo que les pasa con el tiempo y por qué acabamos juntándolos en uno solo.

Durante meses, 4dimntion.com fueron dos programas sirviendo una sola web. El sitio público era HTML ensamblado con scripts y servido por nginx, el programa que atiende las visitas. La consola era una aplicación Next.js. La cabecera y el raíl de navegación estaban escritos dos veces: una en el HTML fuente y otra en JSX, generada de la primera con una búsqueda por patrones.

Cuando por fin unificamos, comparamos. El mapa de temas visuales retirados sirve para que quien tenía guardado un tema antiguo no se quede sin tema. Tenía once entradas en un lado y cuatro en el otro, y nadie lo había notado.

Quien llegaba por la portada con un tema antiguo se quedaba sin tema aplicado. Quien llegaba por la consola, no. Dos copias de la misma cosa, y ya decían cosas distintas.

La lista blanca de nginx

nginx tenía una lista de comienzos de ruta que pasaban a la aplicación: /login, /start, /panel, /connection… Lo que no estuviera en la lista caía en el sitio estático, o sea en un 404, el código de página no encontrada.

Una ruta nueva de Next compilaba y respondía perfectamente en el computador de quien la escribía. En producción daba 404 hasta que alguien se acordaba de añadir su location a mano. Pasó más de una vez.

La solución no fue una lista mejor. Fue quitar la lista. nginx pasa todo a la aplicación, y quien decide qué rutas existen es Next, que es el único que lo sabe. Cuando dos sistemas tienen que coincidir en algo, manda el que tiene la respuesta buena, y el otro no intenta copiarla.

El service worker: de lista negra a lista blanca

La misma trampa, con consecuencias peores. El service worker es un programa que vive dentro del navegador y guarda copias de la web para que cargue rápido. El nuestro guardaba «todo excepto» una lista de rutas de la consola.

Cuando la consola y el sitio pasaron a ser la misma aplicación, esa lista de excepciones tendría que crecer con cada ruta nueva. Olvidarse de ampliarla no daría un error. Daría la página de un negocio, guardada en el navegador, servida a un negocio distinto. Una fuga de datos entre clientes causada por una lista que alguien no actualizó.

Se invirtió. Ahora guarda «nada excepto» una lista de recursos públicos marcados con su huella. Lo que se olvide queda fuera de la copia, que es el lado seguro del olvido.

Ante una lista mantenida a mano, la pregunta no es si está bien hoy. Es qué pasa el día que alguien se olvide de actualizarla. Si la respuesta es «una fuga», la lista tiene que ser de lo permitido, no de lo prohibido.

El comentario que mentía

Un comentario del código afirmaba que cierto disparador de la base de datos «solo atendía a lo que entra», es decir, los mensajes del cliente. Dos rutas de envío se fiaron de ese comentario. Repetían a mano la actualización que el disparador, según él, no hacía.

Leyendo el disparador con cuidado, sí la hacía: miraba quién había escrito el mensaje, no hacia dónde iba. El comentario estaba equivocado, y el resultado eran cientos de escrituras repetidas por cada campaña de quinientos destinatarios.

Un comentario es una copia de la verdad escrita en otro idioma. Diverge igual.

Las formas que toma

  • La lista de tablas obligatorias del chequeo de salud, la revisión automática que dice si el sistema está entero. Nadie la actualizaba cuando una migración creaba una tabla. Hoy se comparan las migraciones aplicadas con los archivos de migración.
  • Dos columnas para el rol de un usuario, el texto viejo y la clave nueva, que un disparador mantiene iguales. El código escribe las dos a propósito, por si un día el disparador no está. El comentario reconoce que tener dos ya era el problema.
  • Un $5 escrito a mano en una consulta con parámetros numerados. Es correcto hasta que alguien añade otro filtro más arriba. Entonces falla al ejecutarse, no al compilar, y deja la bandeja en blanco. Hoy el número del parámetro lo calcula una función.
  • La regla de acceso a bandejas, «dueño = todas, resto = las de su rol», que se calcula en una sola función y se reutiliza. Una tercera lectura escrita aparte en SQL sería la que siguiera contando la regla vieja el día que cambie. Un filtro que miente sobre permisos es peor que no tener filtro.

Qué hacer entonces

  • Buscar las cosas escritas dos veces: una lista y su copia, un valor y su constante, una regla y su comentario. Cada par es una divergencia esperando.
  • Decidir cuál de las dos es la verdad y hacer que la otra la lea, en vez de copiarla.
  • Invertir la lista que no se pueda eliminar, para que el olvido falle del lado seguro.
  • Desconfiar del comentario y leer el código que describe.
  • Dejar que decida el que sabe cuando dos sistemas deben coincidir, como nginx y el router, o la app y el service worker, y quitarle al otro la opinión.

Esta nota sale de nuestro trabajo en Software a medida.

← todas las notas