grig-teo:~$
light
← volver a los artículos

Diseñar arquitecturas de backend que sobreviven

Diseña los estados antes que las pantallas, haz que las escrituras sean repetibles, saca los bytes de la API y da por hecho que tienes una sola máquina.

Empieza por los estados, no por las pantallas

La mayoría de los problemas de backend que he heredado no eran problemas de rendimiento. Eran desacuerdos sobre lo que un registro puede llegar a ser.

Antes de escribir una funcionalidad, ahora apunto los estados por los que puede pasar un registro y las transiciones entre ellos. En Touchstone una tarea de prueba pasa por offered, claimed, submitted, reviewed y paid. Escribir esa lista primero hizo obvia la API y dejó visibles los casos difíciles: qué pasa cuando un tester abandona una tarea que había reclamado, cuando dos testers envían la misma tarea, cuando un pago falla después de la aprobación.

Las pantallas son una consecuencia de esa lista. Mientras tanto, un esquema diseñado a partir de pantallas acaba con columnas anulables que codifican las decisiones que faltan.

Haz que las escrituras sean repetibles

Los trabajos de ingesta fallan y se reintentan. Si un reintento duplica datos, todos los números que vienen después están mal y nadie se da cuenta en semanas.

El patrón que uso es una escritura idempotente con clave sobre la identidad natural de la fila: un upsert sobre el par que debería ser único, de modo que ejecutar la misma importación dos veces produce la misma tabla. En Politrack, las publicaciones y los comentarios llevan como clave sus identificadores de plataforma; una nueva ejecución actualiza el texto y sigue.

Cuesta un índice único y unas pocas líneas. Te ahorra la clase de error que tarda un día en encontrarse y destruye la confianza en los datos.

Saca los bytes de la API

Los archivos de evidencia son el otro error recurrente. Un informe con una grabación de pantalla no debería subirse a través del servidor de aplicaciones, ni guardarse en la base de datos.

En Touchstone los agentes piden una subida prefirmada, ponen el archivo directamente en el almacenamiento de objetos y luego envían la referencia. La API nunca toca el cuerpo, el worker lo lee del almacenamiento cuando necesita analizarlo y la grabación se sirve mediante una URL firmada que caduca.

La misma forma vale para cualquier producto con archivos de usuario: la API gestiona permisos y metadatos, el almacenamiento gestiona los bytes.

Da por hecho una sola máquina

Mi propia plataforma se ejecuta en un único VPS: Next.js, NestJS, Postgres, MinIO, una caché de nginx y un modelo local para los respaldos. Esa restricción es útil. Cuando la memoria es finita encuentras la consulta que materializa un millón de filas, y cuando el disco es finito te das cuenta de que nadie ha purgado nunca los logs.

De ahí salieron dos costumbres. Todo camino caro tiene un límite, y cada noche se produce una copia de seguridad que alguien ha restaurado de verdad. Mantengo un procedimiento de restauración escrito y lo ensayo, porque una copia que nunca se ha restaurado es un archivo, no una copia de seguridad.

Los despliegues deberían ser aburridos

El objetivo es un despliegue en el que no pase nada sorprendente: una compilación reproducible, una migración que se pueda ejecutar dos veces, una vuelta atrás y un health check que falle de forma ruidosa. La emoción en un despliegue es un informe de error esperando a que lo escriban.

Eso impresiona menos que un diagrama de arquitectura distribuida, y es lo que mantiene un producto en pie un año sin un equipo pendiente de él.

Diseñar arquitecturas de backend que sobreviven | grig-teo