El equipo ejecuta su primera prueba de carga masiva sobre el nuevo entorno de staging multirregión y simula 150.000 personas jugadoras concurrentes. Cuando las réplicas de base de datos empiezan a desincronizarse bajo la carga, Hassan y Sofia deben encontrar una forma de convivir con la consistencia eventual sin romper la experiencia de juego. Stefan les ayuda a entender que la consistencia no es una decisión binaria, sino un trade-off de diseño que debe manejarse cerca del dominio.
La sala de operaciones estaba fría. El aire acondicionado emitía un zumbido grave y constante que casi se tragaba los sonidos lejanos del tráfico berlinés del otro lado de la ventana.
Sofia se acomodó las gafas. En los cristales se reflejaban las líneas verdes y blancas de la configuración de la prueba de carga.
—Configuré los scripts de Locust para simular 150.000 personas usuarias concurrentes —dijo, con ese filo de nervio que siempre le aparecía antes de un despliegue importante—. Vamos a subir a razón de 1.000 por segundo, repartidas entre tres gateways regionales: Frankfurt, Virginia y Singapur. Pero me preocupa el desfase de replicación, Hassan. Con semejante volumen de escrituras, las réplicas se van a quedar atrás.
Hassan asintió despacio, marcando un ritmo con los dedos sobre el escritorio. —Sí. Y eso no es un bug, Sofia. Es física. Una escritura hecha en Frankfurt tarda en cruzar el Atlántico hasta Virginia. Y tarda todavía más en cruzar el Pacífico hasta Singapur. La pregunta no es si van a retrasarse. La pregunta es cómo reacciona nuestra aplicación cuando pasa.
—La UI de matchmaking de Anton espera respuestas síncronas —dijo Sofia, abriendo el controlador en C# en su segundo monitor—. Si la réplica de US-East todavía no tiene el estado actualizado de la persona jugadora cuando el servicio consulta, el emparejamiento se hará con datos viejos. Alguien entrará a un lobby con objetos que ya no tiene. O peor: el estado no va a coincidir y se va a cortar todo.
Stefan apareció en la puerta con una taza de café recién hecho. Llevaba diez minutos observándolos a través del vidrio, mirando esa colaboración silenciosa y enfocada que había reemplazado la energía frenética y caótica del mes anterior.
—Qué cosa hermosa la paridad de staging, ¿no? —dijo Stefan, entrando y apoyándose en el rack de servidores—. Hace tres semanas habríamos corrido esta prueba en producción un sábado por la mañana y pasado el domingo revertiendo bases de datos. Ahora estamos teniendo una discusión de diseño un lunes antes de que una sola línea llegue a producción.
—Hermosa sí es —admitió Sofia, y una sonrisa pequeña se abrió paso entre la ansiedad—. Pero también da miedo. Si esto falla, Lukas va a volver a preguntar si valía la pena el presupuesto de la Operational Realism Initiative.
—Lukas quiere estabilidad —dijo Stefan—. Y estabilidad no significa un sistema que jamás toca los límites físicos. Significa un sistema que se comporta de manera predecible cuando esos límites llegan. Lanza la prueba, Sofia. Veamos por dónde se resquebraja la base de datos.
Sofia miró a Hassan. Él le devolvió un solo gesto de asentimiento, sereno.
—Bueno —dijo ella, con los dedos suspendidos sobre Enter—. Soltamos la tormenta.
La prueba llevaba veinte minutos corriendo.
Con 50.000 personas usuarias, el sistema estaba estable. Con 100.000, la CPU de la base de datos en Frankfurt había subido al 75%, pero las réplicas de lectura de Virginia y Singapur seguían aguantando.
Entonces el tráfico alcanzó el objetivo de 150.000.
—La latencia de replicación está subiendo —dijo Hassan, ahora con la voz tensa—. Frankfurt a Virginia está en 450 milisegundos. Frankfurt a Singapur está picando en 1,2 segundos.
—Estamos viendo fallos de matchmaking en la región de Singapur —dijo Sofia mientras en su terminal seguían cayendo errores—. Se empareja a la gente, pero cuando el servidor del juego consulta el inventario en la réplica de Singapur, devuelve 404. La actualización todavía no llegó.
—¿Y eso cómo se siente del lado de quien juega? —preguntó Stefan, inclinándose sobre el hombro de Sofia.
—Como un desastre —dijo Sofia, abriendo un cliente de prueba en su tablet—. Mira. Compro un booster pack en Frankfurt. La transacción termina y mi saldo de oro baja. Pero enseguida entro a un lobby de torneo alojado en Singapur. La réplica de Singapur todavía cree que tengo el saldo viejo y ningún booster pack. La UI muestra el booster, pero cuando intento equiparlo, el servidor lo rechaza. La app se congela.
—Consistencia eventual —murmuró Stefan—. La base de datos es consistente… eventualmente. La experiencia de juego es inmediata.
—No podemos usar replicación síncrona —dijo Hassan, sin apartar la vista de la pantalla—. Si obligamos a Frankfurt a esperar la confirmación de Singapur antes de devolver cada escritura como exitosa, la latencia de escritura se va a 300 milisegundos por transacción. El juego se va a sentir torpe para todo el mundo.
—Entonces estamos atrapados —dijo Sofia, dejando caer los hombros—. Si usamos replicación asíncrona, los datos están viejos y la app se rompe. Si usamos replicación síncrona, la red es lenta y el juego se vuelve injugable.
—Solo estás atrapada si asumes que la base de datos tiene que resolver el problema —dijo Stefan.
Sofia se giró hacia él con el ceño fruncido. —¿Cómo así? Los datos viven en la base de datos.
—El estado se guarda en la base de datos —corrigió Stefan—. Pero las reglas del negocio viven en tu aplicación. ¿Por qué le estás pidiendo a una réplica vieja en Singapur que valide una transacción que acaba de ocurrir en Frankfurt?
Sofia lo miró un segundo largo. La arquitectura entera empezó a correrle por la cabeza.
—Porque… porque el servicio de matchmaking es regional. Consulta la réplica más cercana para ahorrar latencia.
—¿Y si el servicio de matchmaking supiera qué escrituras son críticas? —preguntó Stefan.
Los ojos de Sofia se abrieron. Giró otra vez hacia la pantalla, con los dedos ya corriendo hacia la IDE. —No necesitamos hacer consistente toda la base de datos. Solo necesitamos que las propias escrituras de la persona jugadora sean consistentes para esa misma persona.
—Se llama consistencia Read-Your-Own-Writes —explicó Sofia, apuntando con el marcador al pizarrón.
Mariana estaba recostada en la silla, con un pretzel mordido en una mano, escuchando con esa intensidad callada que se le instalaba en la cara cuando algo importaba de verdad.
—Si una persona jugadora hace una escritura crítica, por ejemplo comprar un ítem o entrar a un torneo, escribimos en la base de datos primaria de Frankfurt —dijo Sofia—. Pero además colocamos un token de sesión temporal en el cliente con la marca de tiempo de esa escritura. Durante los siguientes cinco segundos, cualquier lectura que venga de ese cliente se salta la réplica regional y va directo a la primaria. Cuando pasan esos cinco segundos y sabemos que la replicación ya se estabilizó, volvemos a la réplica regional.
—Es brillante —dijo Mariana, dándole otro mordisco al pretzel—. Mantiene la latencia de lectura baja para el 99% de la gente que solo navega por la UI, pero garantiza consistencia para quien acaba de gastar dinero o entrar a una cola. Esa persona nunca ve datos viejos.
—¿Y la CPU de la base de datos? —preguntó Hassan, acercándose desde su escritorio—. Si con picos de carga 150.000 personas usuarias se saltan las réplicas y golpean la primaria, igual la vamos a reventar.
—No —dijo Sofia, señalando el diagrama—. Porque el token de sesión solo se coloca en escrituras críticas. Las lecturas normales, cargar el leaderboard, revisar la tienda, ver perfiles de otras personas, siguen yendo a las réplicas regionales. Esas no necesitan consistencia fuerte. Si alguien ve un leaderboard medio segundo tarde, ni se entera. Pero si ve que su oro retrocede, abre un ticket de soporte.
Stefan los observó desde cierta distancia, y en el pecho se le acomodó esa sensación tranquila de orgullo que siempre perseguía cuando un equipo por fin cruzaba la línea. Ese momento en el que dejan de tratar la tecnología como una caja mágica que o funciona o no funciona, y empiezan a entender la física de su sistema para diseñar alrededor de sus límites.
—Entonces escribimos primero las pruebas —dijo Mariana, empujando la silla hacia delante—. Tenemos que demostrar que este enrutamiento por token de sesión funciona. Vamos a escribir una prueba que simule un segundo de retraso de replicación y verifique que una lectura con token fresco devuelve el estado actualizado, mientras que una lectura con token vencido devuelve el estado viejo.
—Yo me encargo del middleware —dijo Sofia. Ahora su voz sonaba firme. La ansiedad había desaparecido por completo—. Hassan, ¿puedes configurar el balanceador para que respete los headers de enrutamiento de sesión?
—Dalo por hecho —dijo Hassan, con una sonrisa rara en su cara.
—Cero errores —susurró Sofia.
Miró el monitor como si todavía no terminara de creer lo que estaba viendo.
El tráfico se mantenía plano en 150.000 personas usuarias concurrentes. La latencia de replicación entre Frankfurt y Singapur seguía rozando 1,1 segundos, pero el servicio de matchmaking estaba funcionando sin fallos.
—El enrutamiento de sesión está aguantando —dijo Hassan, señalando las métricas del balanceador—. Solo el 4% de las lecturas está yendo a la base primaria. Todo lo demás lo están resolviendo las réplicas regionales. La CPU de la primaria se mantiene estable en 42%.
—Lo logramos —dijo Sofia, girándose hacia Mariana, que acababa de entrar a la sala—. La prueba pasó. La carga no nos quebró.
—Lo lograste tú, Sofia —dijo Mariana, dándole una palmada en el hombro—. Tú diseñaste el modelo de consistencia y escribiste las pruebas que demostraron que funcionaba. Eso es desarrollo backend.
Sofia se sonrojó. Se le mezclaron la vergüenza y el orgullo en la cara. —No habría podido sin tu entorno de pruebas. Ni sin el entorno de staging de Hassan.
—Ese es justamente el punto de un equipo —dijo Stefan, avanzando un paso—. Cuando tienes paridad de staging, no necesitas héroes. Necesitas un grupo disciplinado de desarrolladores que mire los mismos datos, entienda las restricciones y diseñe una solución en conjunto.
Lukas entró con su tablet en la mano. Miró los monitores y luego la cara de Sofia.
—Estuve corriendo el cliente de prueba desde mi oficina —dijo Lukas, con un tono bajo, casi reverente—. Compré diez booster packs seguidos mientras cambiaba la VPN entre Singapur, Tokio y Nueva York. La UI fue impecable. Ni un congelamiento. Ni un desajuste de estado. Simplemente… funcionó.
Miró a Katja, que había aparecido detrás de él en la puerta.
—Seis semanas —le dijo Lukas—. Apenas vamos por la segunda semana de la Operational Realism Initiative y ya resolvimos el mayor riesgo técnico del roadmap de Q3.
—No lo resolvimos trabajando más rápido, Lukas —dijo Katja, con esa autoridad serena que había recuperado durante el último mes—. Lo resolvimos trabajando mejor. Dándole al equipo tiempo y herramientas para entender la física de su sistema en vez de obligarlo a adivinar.
Lukas asintió despacio. —Empiezo a ver la diferencia.
Se volvió hacia Sofia. —Gran trabajo, Sofia. De verdad.
Cuando Lukas salió, Sofia soltó un suspiro largo y lento, como si lo llevara guardando desde el lunes por la mañana.
—Creo que necesito una cerveza —dijo.
—Yo invito —dijo Hassan, tomando ya la chaqueta.
—La entrada de Sofia en el log de esta noche fue increíble —dijo Katja, tomando un sorbo de vino.
—Léemela —dijo Stefan, recostándose en la silla.
Katja abrió el portátil y buscó la síntesis diaria de Navigator.
Yo antes creía que la consistencia era una configuración de base de datos, había escrito Sofia. Activas la replicación síncrona y la base te garantiza la verdad. Pero esta semana demostró que la verdad es una decisión de diseño. La base de datos no puede resolver la velocidad de la luz. Solo la aplicación puede decidir qué verdades vale la pena esperar y cuáles podemos permitirnos conocer después. TDD no solo nos ayudó a escribir código. Nos ayudó a definir los límites de nuestra realidad.
Stefan sonrió y miró la luz dorada reflejada en el canal. —Ahí está todo el programa en un solo párrafo. Ya no es solo una desarrolladora. Es una arquitecta.
—Lo es —dijo Katja en voz baja—. Y Hassan se fue a las 17:00. Un viernes. En semana de prueba de carga.
—Capaz esa sea la métrica más importante de todas —dijo Stefan—. Un equipo que puede correr una prueba de carga de 150.000 personas usuarias el jueves y salir a tiempo el viernes es un equipo que confía en su sistema. No está esperando que el software le tienda una emboscada.
—Todavía nos quedan cuatro semanas de iniciativa —dijo Katja, mirándolo—. ¿Qué sigue?
—Lo que sigue —dijo Stefan— es Daniel. Viene observando estas corridas exitosas de staging y ya se dio cuenta de que sus listas manuales de regresión se están volviendo obsoletas. Va a pelear por conservar sus compuertas manuales, Katja. No porque sea malintencionado, sino porque esas compuertas son la forma en que define su valor dentro de la empresa.
Katja suspiró y la sonrisa se le apagó un poco. —Las restricciones humanas siempre son más difíciles que las físicas, ¿no?
—Siempre —dijo Stefan, levantando la copa—. Pero al menos ahora tenemos los datos de nuestro lado.
Katja chocó su copa con la de él. —Por la física.
—Por la física —dijo Stefan.
Navigator — Katja Müller — 3 de julio de 2026, 18:30
Segunda semana de la Operational Realism Initiative.
Ejecutamos nuestra primera prueba de carga masiva sobre el nuevo entorno de staging multirregión, simulando 150.000 personas usuarias concurrentes. El entorno de staging hizo exactamente aquello para lo que lo construimos: expuso los límites físicos de nuestra replicación de base de datos.
Bajo carga pico, el retraso de replicación entre Frankfurt y Singapur llegó a 1,2 segundos. Eso provocó desincronización severa de estado y fallos de la aplicación dentro del matchmaking regional.
Sofia lideró la solución arquitectónica. En vez de intentar obligar a la base de datos a resolver la velocidad de la luz, diseñó un modelo de consistencia Read-Your-Own-Writes. Al enrutar lecturas críticas directamente a la base primaria mediante tokens temporales de sesión y dejar que las lecturas no críticas siguieran en las réplicas regionales, mantuvo baja la latencia de lectura y garantizó consistencia exactamente donde importaba.
La segunda prueba de carga del jueves fue un éxito impecable. Cero errores bajo 150.000 personas usuarias concurrentes, con la CPU de la base primaria estable en 42%.
Señales de Navigator esta semana:
- El 100% de los commits de backend incluyó archivos de prueba, con Sofia y Mariana haciendo pairing sobre las pruebas del middleware de consistencia.
- La estabilidad del entorno de staging llegó al 100% durante la corrida final de la prueba de carga.
- Las horas registradas por Hassan se mantuvieron estables en 40 esta semana. No hizo falta trabajo nocturno ni de fin de semana.
- Lukas expresó una confianza alta en el progreso del equipo después de probar él mismo el cliente.
Demostramos que el realismo operativo no distrae de la entrega de funcionalidad. Es su base. Resolvimos nuestro mayor riesgo técnico en la segunda semana porque teníamos las herramientas para ver la verdad.
La próxima semana nos toca enfrentar las restricciones humanas. Daniel ya prepara sus listas manuales de regresión para el sistema de torneos. Tenemos que demostrarle que la evidencia automatizada es más segura que las compuertas manuales.