Stefan introduce desarrollo guiado por pruebas en el equipo de backend de Pixel Spree y obtiene exactamente la reacción que esperaba: Mariana se inclina hacia adelante, Anton lo llama teología y Sofia mira una prueba fallida como si la hubiera insultado en lo personal. Durante cinco días calurosos en Berlín, el equipo aprende que TDD no trata de pureza. Trata de acortar la distancia entre suposición y evidencia. Para el viernes, el equipo de backend está escribiendo código más pequeño y con intención más clara, el equipo de Unity sigue poniendo los ojos en blanco y Daniel está empezando a darse cuenta, en silencio, de que las pruebas automatizadas podrían reemplazar más de su teatro de aprobaciones de lo que quisiera admitir.
Stefan escribió las tres palabras despacio para que nadie pudiera fingir que no las había visto.
RED.
GREEN.
REFACTOR.
Luego dejó el marcador y miró al equipo de backend reunido alrededor de la pizarra como si estuviera a punto de anunciar una religión o un recorte.
La sala ya estaba caliente. Principios de junio en Berlín. Ese tipo de calor que entra por las ventanas antes de que el edificio admita que necesita aire. Alguien había abierto ambos lados del piso, y la corriente traía café, bloqueador solar y humo rancio de club de quien hubiera dormido tres horas y se hubiera venido directo a trabajar desde Kreuzberg.
Mariana estaba apoyada en su escritorio de pie con los brazos cruzados y el peso sobre una pierna descalza, crop tank negro de Sepultura cortado lo bastante arriba como para mostrar la línea dura de su estómago, cut-offs lo bastante cortos como para que Daniel hubiera evitado mirar en su dirección toda la mañana. Sofia estaba sentada dos sillas más allá con la laptop abierta y una libreta que nunca recordaba usar. Anton se había acercado desde el lado de Unity y se había quedado atrás con la postura de un hombre que asiste a un sermón solo para abuchear al predicador.
“Esto”, dijo Stefan, tocando la pizarra, “es desarrollo guiado por pruebas.”
Anton soltó un resoplido.
“De verdad lo estás haciendo”, dijo. “Estás convirtiendo las pruebas en religión.”
Stefan lo miró.
“Solo si confundes ritual con retroalimentación.”
Eso le sacó una pequeña sonrisa a Mariana.
Anton cruzó más fuerte los brazos. Camiseta negra sin mangas. Pómulos afilados. La postura de un sneakerhead y la paciencia de un ruso, lo cual significaba que la paciencia existía más en teoría que en práctica.
“Explícame la diferencia”, dijo.
Stefan volvió a destapar el marcador.
“La religión te dice qué creer antes de que la realidad responda. TDD le hace primero una pregunta a la realidad.” Debajo de las palabras escribió: ¿Qué debería hacer el sistema? “Escribes una prueba fallida que describe un comportamiento. La prueba falla porque ese comportamiento todavía no existe. Luego escribes la menor cantidad de código que la haga pasar. Luego lo limpias.”
Se volvió hacia Sofia.
“¿Qué se rompe primero cuando un equipo se está ahogando?”
Sofia parpadeó. Había esperado una charla, no una pregunta.
“Eh. ¿Los despliegues?”
“Antes de eso.”
Miró el teclado como si la respuesta pudiera estar escondida bajo las teclas.
“¿La gente deja de saber qué se supone que tiene que pasar?”
“Exacto.” Stefan señaló la frase en la pizarra. “TDD obliga a hacer la pregunta antes de la implementación. No después del incidente. No durante code review. No cuando Hassan está revirtiendo algo a las 23:40 porque todos los demás ya se fueron a casa.”
Hassan no levantó la vista del escritorio, pero una comisura de su boca se movió. En Pixel Spree eso contaba como aplauso.
Stefan conectó la laptop a la pantalla. Apareció una pequeña función de backend. Cálculo de multiplicador de recompensa para un evento de fin de semana. Una función pura. Entradas dentro, resultado fuera. Ese tipo de cosa que los equipos juran que es demasiado pequeña para salir mal justo hasta que les cuesta cuarenta mil jugadores furiosos.
“Tuvimos un pico de soporte hace dos fines de semana porque los boosters de oro se apilaron mal”, dijo. “Nada catastrófico. Solo lo suficiente para envenenar un lunes. Así que empecemos por ahí.”
Abrió primero un archivo de pruebas.
“Espera”, dijo Sofia. “Todavía no escribiste la función.”
“Correcto.”
“¿Entonces cómo sabes qué probar?”
“Porque sé cuál se supone que es la regla de negocio.” Miró a Mariana. “Léeme la regla.”
Mariana se separó del escritorio y se acercó a la pantalla.
“Booster base por multiplicador del evento, con tope en tres”, dijo. “A menos que el jugador esté en un segmento principiante, entonces el multiplicador del evento no se apila.”
“Bien. Eso es un comportamiento.”
Tecleó la primera prueba en voz alta mientras la escribía. Un jugador de segmento principiante con un booster durante la semana del evento debería seguir recibiendo solo el multiplicador del booster. No ambos. La prueba falló, roja brillante en la pantalla, porque la función no existía.
“Rojo”, dijo Stefan.
Creó la función. Escribió seis líneas directas. Sin abstracciones. Sin trucos. La prueba pasó.
“Verde.”
Luego limpió dos variables duplicadas, renombró un método engañoso y acomodó la condición de una manera más clara.
“Refactor.”
El equipo vio cómo el ciclo ocurría en menos de cuatro minutos.
Mariana no se movió. Sofia frunció el ceño frente a la pantalla, no porque no estuviera de acuerdo, sino porque algo en su cabeza se estaba reordenando y le resentía el esfuerzo. Anton mantuvo los brazos cruzados.
“Eso es fácil porque es puro”, dijo Anton. “Prueba esa mierda en Unity. Timing de animación. Input buffering. Race conditions de netcode. No todo es una linda función de blog post.”
“Cierto”, dijo Stefan. “No todo es candidato para una prueba unitaria. Pero una cantidad escandalosa de tu código no es timing de animación ni game feel. Son transiciones de estado. Lógica de precios. Reglas de inventario. Serialización. Decisiones de matchmaking. Cooldowns. Curvas de recompensa. Toda la parte determinista que hoy descubren que está rota después de sacarla a producción.”
Anton no respondió.
Porque eso cayó.
Todos en el piso sabían que el dolor de Anton no era que los juegos fueran difíciles. Era que demasiada parte de la base de código de Unity hacía que las cosas simples se sintieran místicas porque ya nadie lograba separar la lógica determinista del pegamento del engine.
Daniel apareció en el muro de vidrio con el Moleskine ya abierto.
“¿Cuánto tiempo agrega esto?”, preguntó.
La pregunta le salió más filosa de lo que quería. Seguía vistiendo el uniforme de QA en el que al parecer había nacido: polo azul marino, chinos, tenis limpios, lentes, libreta, la postura de un hombre al que le habían enseñado que su seriedad debía contar como contribución incluso cuando frenaba a todos.
Mariana respondió antes de que Stefan pudiera hacerlo.
“Menos que los incidentes de producción”, dijo.
Eso arrancó unas cuantas risas bajas.
Daniel no se rió.
“Lo pregunto en serio.”
“Yo también”, dijo Mariana.
Stefan se metió antes de que se volviera una de esas discusiones estériles donde todos protegen su territorio y nadie protege el software.
“Agrega minutos ahora para quitar horas después”, dijo. “Igual que los pull requests pequeños agregan sobrecarga que elimina el infierno de las fusiones. Estás moviendo el pensamiento hacia más temprano.”
El bolígrafo de Daniel se movió una vez sobre la página.
“Muéstramelo el viernes”, dijo.
“Ese es el plan”, dijo Stefan.
Volvió a mirar al equipo de backend.
“Esta semana no necesitan conversión. Necesitan un intento honesto. Elijan un comportamiento pequeño. Escriban primero la prueba. Déjenla fallar. Luego háganla pasar. A nadie lo van a calificar por elegancia.”
Mariana ya se había girado hacia su escritorio.
“Ya sé cuál bug voy a hacer”, dijo.
“Claro que sí”, murmuró Anton.
Ella lo miró por encima del hombro, ojos brillantes, sonrisa peligrosa.
“Puedes seguir llamándolo teología desde los asientos baratos, querido. Igual lo voy a probar.”
Anton soltó una carcajada a pesar suyo.
Esa fue la primera grieta en la sala. No fe. Pero sí movimiento.
La primera vez que Mariana dijo una grosería, fue contra la prueba.
No contra el código.
Contra la prueba.
“Esto se ve al revés de una manera bien cabrona”, dijo.
Fue después de comer, con el calor empujando contra las ventanas tan fuerte que el AC ya se había rendido y toda la esquina de backend había empezado a vestirse como si la oficina en cualquier momento fuera a deslizarse dentro de un lago. Mariana había cambiado el crop tank de Sepultura por una camiseta desteñida de Motörhead que al parecer traía en la bolsa, anudada más arriba bajo las costillas. Café helado sobre el escritorio. Pies descalzos bien plantados. Pelo recogido porque el calor iba ganando.
En su pantalla estaba un bug pequeño que llevaba tres semanas queriendo matar.
El reinicio de la racha diaria de recompensas era indulgente el día siete, estricto el día ocho y completamente insano si el jugador cruzaba medianoche mientras el reloj del teléfono se desincronizaba y luego volvía a conectarse. Soporte lo había documentado dos veces. Marcus lo había escalado una vez. Nadie lo había tocado porque el arreglo vivía dentro de un pedazo de lógica de backend que todos odiaban abrir.
“Describe el comportamiento”, dijo Stefan.
“Ya lo hice. Lo describí cuatro veces en Jira, dos en Slack y una en mayúsculas después de que soporte mandó el mismo ticket otra vez.”
“No la historia. La regla.”
Miró el código. Luego el screenshot de soporte. Luego el código otra vez.
“Si un jugador reclama el día siete tarde en la noche y vuelve después de medianoche dentro del periodo de gracia permitido, la racha debería continuar. No reiniciarse.”
“Bien. Escríbelo.”
“¿El nombre de la prueba?”
“La expectativa.”
Tecleó con esa clase de agresividad que produce nombres limpios por accidente.
continues_streak_when_claim_happens_after_midnight_within_grace_period
“Jesucristo”, dijo Anton desde el grupo de al lado. “Eso no es nombre de prueba. Es un grito de ayuda.”
Mariana ni siquiera volteó.
“Si lo puedes leer, funciona”, dijo.
La prueba falló exactamente como Stefan quería que fallara. No de forma misteriosa. No por una cascada de basura de setup sin relación. Falló porque el sistema reiniciaba la racha cuando no debía.
Rojo.
Mariana se quedó quieta.
Ahí estaba. La forma del error aislada. Sin línea de tiempo de incidente. Sin arqueología de tickets de soporte. Sin hilo de comentarios de PR de seis días antes donde alguien hizo una pregunta medio en serio y la ignoraron. Solo una declaración clara del comportamiento esperado y una señal contundente de que el software no estaba de acuerdo.
“Fuck”, dijo en voz baja.
Stefan conocía ese tono. No era frustración. Era reconocimiento.
“¿Qué?”, preguntó.
Siguió mirando la prueba.
“Llevo tres años debuggeando después del hecho”, dijo. “Esta es la primera vez que el código ha tenido que responderme antes de que se ponga a mentir en producción.”
La frase era demasiado buena para interrumpirla.
Escribió el arreglo más pequeño que podía tolerar. Nada de limpieza todavía. Solo lo suficiente para que pasara. Apareció la barra verde.
Luego encontró dos condicionales viejos enredados alrededor de la normalización de zona horaria, volvió a maldecir y los refactorizó en algo que un adulto sobrio pudiera leer.
Diez minutos después tenía una prueba pasando, código más limpio y un bug que llevaba semanas cargando en la cabeza como una piedra se había vuelto de pronto más ligero.
Daniel apareció al final de la fila de escritorios sin que nadie notara cuándo había llegado.
“¿Puedo ver la prueba?”, preguntó.
Mariana parpadeó.
“¿Quieres leer la prueba?”
“Sí.”
Giró el monitor hacia él.
Daniel leyó en silencio. Una vez. Luego otra vez. El bolígrafo le golpeó leve el Moleskine, pero todavía no escribió nada.
“Esto está más claro que el ticket de Jira”, dijo.
Mariana lo miró como si de pronto hubiera empezado a hablar finlandés.
“Bueno. Sí”, dijo. “Porque la prueba tiene que ser inequívoca o falla.”
Daniel asintió una vez, casi irritado por el hecho.
“Y si QA tuviera este comportamiento escrito a este nivel antes de regresión, discutiríamos menos sobre el resultado esperado.”
“También sí”, dijo Stefan.
Los ojos de Daniel bajaron a la implementación.
“¿Cuánto tardó?”
Mariana revisó las marcas de tiempo.
“Doce minutos hasta el primer pase. Veintiuno con limpieza.”
Daniel de verdad lo anotó.
Al otro lado del piso, Katja pasó caminando con shorts negros y una camiseta de banda anudada a la cintura, lentes puestos, café en mano, registrando la escena con una sola barrida rápida. Mariana en el escritorio. Daniel leyendo una prueba. Stefan sin hablar. El grupo de backend más callado de lo normal porque todos dentro del rango auditivo fingían no escuchar.
“¿Debería actuar sorprendida?”, preguntó Katja.
“Probablemente no”, dijo Stefan.
Katja miró la pantalla, leyó el nombre de la prueba y sonrió con la precisión cansada de alguien que solo sonríe cuando un sistema tiene más sentido que hace diez minutos.
“Bien”, dijo. “Sigan.”
Siguió caminando.
Daniel se quedó un minuto más completo.
“Si esto se vuelve cargo culting, lo voy a decir”, dijo.
Mariana se recargó hacia atrás, ojos filosos.
“Si esto se vuelve cargo culting, yo lo voy a decir primero.”
Daniel asintió y se fue.
Después de que se fue, Mariana volvió a abrir el archivo de prueba y lo miró otra vez.
“¿Sabes qué es grosero?”, dijo.
“¿Qué?”
“Que esto se sienta bien. Quería odiarlo por principio.”
Stefan se rió.
“Dale hasta mañana. Entonces lo vas a odiar por mejores razones.”
“¿Como cuáles?”
“Como que te expone cuánto código todavía no entiendes.”
Se tronó los nudillos y abrió el siguiente bug.
“Perfecto”, dijo. “Exactamente mi clase de humillación.”
Para el almuerzo del martes, la palabra ya se había regado más allá del equipo de backend.
No porque alguien hubiera hecho un anuncio.
Sino porque Mariana había llamado a TDD “el primer culto útil al que me he unido” en Slack, y el mensaje había recibido diecinueve reacciones en once minutos.
Anton estaba esperando a Stefan en la azotea con una Club-Mate helada y la expresión de un hombre que ya había decidido que iba a tener razón aunque los hechos se pusieran incómodos.
La terraza estaba brutal bajo el sol del mediodía. Berlín en junio, lo bastante brillante como para desteñir los bordes de todos los edificios. Un par de productores fumaban bajo la vela de sombra. Alguien de arte se había quitado las sandalias y colgaba los dos pies de una banca como si esto fuera una casa junto al lago y no un techo de oficina sobre el tráfico del Görlitzer Park.
Anton estaba sentado sobre el muro bajo con shorts negros tan ajustados que parecían pintados, top de malla sin mangas pegado al pecho, agujetas de tenis brillando frescas y blancas. Su ropa decía antro. Su cara decía code review.
“Estuve viendo a Mariana toda la mañana”, dijo cuando Stefan se acercó. “Va más rápido porque el problema es lógica de negocio de backend. Límites limpios. Reglas deterministas. Y tú crees que esto se traduce al código de juego y todos empiezan a rezarle a la barra rojo-verde y de pronto estamos salvados. Es una pendejada.”
Stefan tomó un sorbo de café.
“Subiste para decirme que lo estoy vendiendo de más.”
“Te estoy diciendo que los desarrolladores siempre hacen esto. Descubren una práctica que funciona en un dominio y la convierten en una verdad moral universal. Seis meses después algún consultor está vendiendo evaluaciones de madurez TDD y todo el mundo se quiere morir.”
Ese era, de manera irritante, un muy buen argumento.
Stefan respetaba los buenos argumentos.
“Tienes razón sobre el modo de falla”, dijo.
Las cejas de Anton se movieron. No esperaba acuerdo tan rápido.
“TDD se vuelve religión cuando la gente deja de preguntarse qué retroalimentación necesita y empieza a defender el ritual en sí”, dijo Stefan. “A mí no me interesa el ritual. Me interesa acortar ciclos de retroalimentación.”
Mariana apareció a media frase, le robó el mate a Anton sin pedir permiso y dio un trago. Cut-offs diminutos. Tank blanco corto. Lentes de sol sobre la cabeza. El sol hacía que el tatuaje del antebrazo se viera casi azul.
“¿Sigue monologueando?”, preguntó.
“Está haciendo un punto válido”, dijo Stefan.
“Asqueroso”, dijo Mariana. “Deberíamos revisarte eso.”
Anton recuperó su bebida.
“Hago puntos válidos todo el tiempo. Nadie lo aprecia.”
Sofia llegó a la terraza al final, camiseta blanca oversize sobre shorts, la laptop todavía bajo el brazo como si no confiara del todo en que la hora de comer fuera a mantenerse no técnica.
“¿Interrumpo?”, preguntó.
“Solo una crisis filosófica”, dijo Mariana.
Sofia se sentó con las piernas cruzadas en la banca.
“Qué bueno. Yo también traigo una.”
Su voz tenía ese borde deshilachado de alguien que llevaba tres horas perdiendo una pelea con un problema diminuto y empezaba a tomárselo personal.
“Dilo”, dijo Stefan.
“Escribir primero la prueba me hace sentir estúpida.” No lo suavizó. Esa era una cosa que Gen Z hacía mejor que su generación. Se saltaban el teatro y nombraban la herida. “Sigo intentando probar la implementación porque todavía no sé pensar en comportamiento. Entonces la prueba sale basura. Entonces me odio.”
Anton la miró, luego desvió la vista, de pronto menos interesado en la pose.
Porque ahí estaba. El costo. No ideología. Reconfiguración cognitiva.
Stefan acercó una silla y se sentó para no quedar de pie sobre ella.
“¿En qué estás trabajando?”
“Cooldown de código promocional. Soporte quiere un bloqueo de una hora después de tres intentos fallidos. Llevo diez minutos escribiendo setup y acabo con una prueba que no demuestra nada.” Se frotó un ojo. “Siento que todos los demás entendieron el chiste y yo no.”
El tono de Mariana cambió al instante.
“No, babe. Eso es normal.” Asintió hacia Stefan. “Ayer me dieron ganas de aventar el monitor por la ventana durante veinte minutos. Luego hizo clic. Más o menos.”
Anton miró a Sofia por encima del borde de la botella.
“Estás tratando de construir el mundo entero antes de hacer una pregunta”, dijo. “Deja de hacerlo.”
Sofia lo miró fijo.
“¿Eso se supone que es apoyo?”
“Para Anton, sí”, dijo Mariana.
Stefan se inclinó hacia adelante.
“¿Cuál es la pregunta más pequeña que importa?”
Sofia pensó.
La ciudad zumbaba abajo. El S-Bahn a lo lejos. Alguien riéndose demasiado fuerte en la azotea vecina. Humo de cigarro cortando el bloqueador solar.
“Después de tres intentos fallidos de promo en una hora”, dijo despacio, “el cuarto intento debería ser rechazado aunque el código sea correcto.”
“Bien”, dijo Stefan. “Esa es tu prueba. Sin base de datos. Sin API. Sin objeto request. Solo la regla.”
“¿Y si el código es correcto después de que expira el bloqueo?”, preguntó Sofia.
“Esa es la siguiente prueba”, dijo Mariana.
Anton hizo un asentimiento mínimo.
“Dos preguntas. No doce.”
Sofia exhaló. Todavía no alivio. Pero sí un camino.
Se puso de pie.
“Si esto no funciona, los voy a culpar a todos personalmente.”
“Justo”, dijo Stefan.
Bajó de nuevo con la laptop bajo el brazo y un poco más de velocidad en el paso.
Anton la vio irse.
“Es inteligente”, dijo.
“Sí”, dijo Stefan.
“Por eso me encabrona cuando una técnica hace que la gente inteligente se sienta tonta.” Anton volvió a mirarlo. “Las prácticas deberían servirle al equipo. No al revés.”
“De acuerdo.”
Mariana estiró una pierna hacia el sol.
“¿Pueden dejar de darse la razón? La tensión sexual desaparece cuando rusos y alemanes se ponen razonables.”
Anton casi se atragantó con el trago.
Stefan se rió dentro del vaso de café.
Y así terminó la conversación: no con consenso, sino con una línea más limpia alrededor de la disputa real.
TDD no era sagrado.
Pero tampoco era opcional en todas partes.
El arte estaba en saber qué código merecía la pregunta antes de la implementación.
Nota del lector: A TDD se le caricaturiza de rutina como bala de plata o como ritual tedioso. Las dos caricaturas son flojas. El valor real es más estrecho y más práctico: obliga a los desarrolladores a enunciar el comportamiento esperado antes de que el detalle de implementación los seduzca a escribir más código del que el problema requiere.
El ciclo rojo-verde-refactor funciona porque comprime la retroalimentación. Una prueba fallida expone el malentendido de inmediato. Una prueba en verde demuestra un comportamiento, no corrección universal. Refactorizar después del verde evita que la deuda de diseño se acumule mientras el comportamiento sigue protegido. Bien usado, TDD no es teología. Es una forma disciplinada de hacerle preguntas más pequeñas al software.
También saca a la superficie una verdad dura: los equipos muchas veces no saben realmente cuál es el comportamiento esperado hasta que intentan codificarlo con precisión. Por eso Sofia batalla en este episodio. Su dificultad no es falta de capacidad. Es el dolor normal de pasar de hábitos centrados en la implementación a un pensamiento centrado en el comportamiento. La curva de aprendizaje es real. La ganancia también.
Pasó a las 16:02 del miércoles porque claro que pasó a las 16:02.
No después del standup matutino.
No durante la comida.
No después de una explicación de Stefan, lo cual habría sido demasiado ordenado y lo habría vuelto insoportable.
Pasó porque Sofia se enojó lo suficiente como para simplificar.
Había pasado casi todo el martes y la mitad del miércoles intentando escribir una prueba alrededor de la lógica de bloqueo del código promocional sin arrastrar medio backend a la habitación con ella. Cada vez que pensaba que ya tenía el límite, aparecía otra dependencia. Estado del usuario. Parseo de timestamps. Wrapper de API. Contador de reintentos. Invalidación de caché. Toda la familia enferma formada detrás de una regla diminuta como si todos esperaran ser alimentados.
Para la tarde del miércoles tenía medias lunas oscuras bajo los ojos y una espiral de notas descartadas en el escritorio que parecían evidencia de un procedural policiaco.
Stefan estaba en cuclillas junto a su silla, sin tocar el teclado.
“Enséñame la prueba”, dijo.
Lo hizo.
Era monstruosa. Setenta líneas de setup. Mock objects reproduciéndose en las esquinas. Una prueba que técnicamente fallaba por la razón correcta pero no le enseñaba nada a nadie.
Stefan la leyó una vez.
“Bórrala”, dijo.
Sofia se volvió hacia él como si hubiera sugerido incendiar algo.
“Llevo dos horas con eso.”
“Lo sé. Bórrala.”
No se movió.
Mariana, desde el escritorio de pie vecino, no levantó la vista de la pantalla cuando habló.
“Tiene razón. Mátala. Ya está muerta.”
Sofia tragó saliva. Hay pocas humillaciones más filosas que borrar trabajo frente a gente que respetas. No porque el trabajo sea malo. Sino porque una parte de ti supo que era malo a mitad del camino y siguió de todos modos por puro orgullo.
Seleccionó todo.
Lo borró.
El archivo vacío le devolvió la mirada.
Algo en el pecho se le aflojó y dolió al mismo tiempo.
“Okay”, dijo Stefan en voz baja. “¿Cuál es la regla? Una oración.”
Sofia miró el archivo en blanco.
“Después de tres intentos fallidos dentro de una hora, el cuarto se bloquea.”
“Bien. ¿Qué objeto es dueño de esa regla?”
“El servicio de promos.”
“Demasiado grande.”
Frunció el ceño.
“¿La policy de cooldown?”
“Mejor. ¿Qué necesita saber la policy?”
Los ojos de Sofia se movieron un poco a la izquierda, como siempre que por fin estaba pensando en vez de actuar que pensaba.
“Número de fallos. Ventana de tiempo. Hora del intento actual.”
“Eso basta.”
Empezó otra vez.
Sin mocks esta vez.
Solo una policy pequeña y una prueba:
blocks_fourth_attempt_after_three_failures_within_one_hour
Rojo.
Luego seis líneas de código.
Verde.
Luego la segunda prueba:
allows_attempt_when_previous_failures_are_outside_the_window
Rojo.
Dos líneas más.
Verde.
Se recargó hacia atrás. No dijo nada. Corrió las pruebas otra vez. Verde. Abrió la implementación. Parpadeó ante lo poco que había.
“¿Eso es todo?”, dijo.
Mariana por fin se dio vuelta.
“Cómo odio cuando esa es la respuesta, pero sí.”
Sofia soltó una risa, mitad incrédula, mitad ofendida.
“Llevo día y medio porque seguía intentando demostrar que todo el sistema funcionaba.”
“¿Y?”, preguntó Stefan.
“Y el comportamiento real solo necesitaba tres pedazos de información.” Volvió a bajar la vista al código. “Dios mío.”
Ese fue el clic.
No alegría. No dominio.
Reconocimiento.
La realización de que la mitad del dolor venía de arrastrar complejidad accidental a lugares donde no pertenecía y luego resentirte contigo misma por no poder pensar el desorden con limpieza.
Daniel pasó rumbo de vuelta de la cocina y se detuvo al ver a Sofia sonriéndole a la pantalla como si acabara de engañar a la muerte.
“¿Qué pasó?”, preguntó.
Sofia giró la laptop hacia él.
“Se hizo pequeño”, dijo.
Daniel leyó las dos pruebas. Luego el código. Luego las pruebas otra vez.
“¿Dónde está el resto?”
“No hay resto”, dijo Sofia. “Ese es el punto.”
Daniel se quedó ahí un segundo más de lo habitual.
No parecía irritado esta vez, sino inquieto de una manera más productiva.
Porque la prueba de Sofia no solo verificaba comportamiento. También lo describía con más claridad que la mitad de los criterios de aceptación que QA había recibido en todo el trimestre.
“Si los requisitos estuvieran escritos así”, dijo despacio, “QA podría automatizar más del paquete de regresión en lugar de reinterpretar tickets en cada sprint.”
Nadie se burló de él.
Fue Mariana quien respondió.
“Sí”, dijo. “Ese es todo el pinche punto.”
Daniel se acomodó los lentes.
“No todo el punto”, dijo.
“No”, dijo Stefan. “Pero sí uno de los buenos.”
Daniel asintió y siguió caminando.
Sofia lo vio irse.
“¿Acabo de enseñarle algo a Daniel?”
“No te agrandes”, dijo Mariana. “Va a recaer.”
Toda la fila de backend se rio.
Sofia volvió a mirar la pantalla. Las dos pruebas verdes estaban ahí como un pequeño acto de venganza contra cada historia inflada que le habían aventado alguna vez.
“Este es el código más limpio que he escrito desde que entré”, dijo.
Stefan se puso de pie, con las rodillas recordándole que ya no tenía treinta.
“Bien”, dijo. “Ahora escribe una más antes de irte para que no sea casualidad.”
Eso le ganó una mirada que era más sana que el elogio.
Para el viernes por la tarde, la oficina volvía a sentirse distinta.
No transformada.
Eso habría sido demasiado fácil.
Pero distinta en la forma en que se siente una habitación cuando por fin alguien abre la ventana correcta.
Katja había jalado a Stefan a la sala de juntas a las 16:50 con la misma expresión que había tenido dos lunes antes, cuando las métricas DORA aterrizaron por primera vez en su pantalla. Solo que esta vez no era angustia. Era concentración con un rastro de satisfacción al que todavía no le confiaba el nombre.
Navigator llenaba la pantalla mural.
El panel del repositorio de backend mostraba cómo se veía una semana de comportamiento cambiado cuando se traducía en números. Los tamaños de pull request se habían mantenido por debajo de cien líneas durante cuatro días seguidos. Los comentarios de review eran más cortos, pero más específicos. La frecuencia de commits había perdido su antiguo patrón de ráfagas y se había distribuido a lo largo de la jornada como si la gente realmente estuviera integrando en lugar de acaparar. Los archivos de prueba habían sido tocados en ochenta y uno por ciento de los commits de backend desde el lunes.
El lado de Unity se veía casi igual.
Ramas más grandes. Menos pruebas. Un hilo de comentarios de Anton que se leía como una pequeña guerra librada enteramente a través de anotaciones inline sobre fronteras de serialización y abstracciones falsas.
“Desparejo”, dijo Katja.
“Como estaba planeado”, dijo Stefan.
Ella bufó.
“Nada en esta empresa ha sido jamás ‘como estaba planeado’.” Hizo zoom sobre la gráfica de backend. “Pero sí. Desparejo de la forma útil. Mariana está completamente metida. Sofia cruzó de pánico a competencia el miércoles. Hassan empezó a agregar pruebas alrededor de validación de config de despliegue por su cuenta, y no esperaba eso tan pronto. Anton sigue actuando como si le hubiéramos pedido meterse a un monasterio.”
A través del muro de vidrio, Anton efectivamente estaba discutiendo con Mariana en su escritorio. No hostil. Animado. Sus manos moviéndose rápido. La sonrisa de ella más ancha con cada objeción. Sofia sentada cerca mirando a ambos como si estuviera aprendiendo dos dialectos distintos del mismo argumento.
“Va a adoptar partes de esto en cuanto pueda hacerlo sin llamarlo TDD”, dijo Stefan.
“Probablemente.” Katja apoyó una mano sobre la mesa. La camiseta de banda estaba ahora anudada a la cintura porque Berlín en junio no tenía paciencia para el decoro de oficina. Shorts negros. Chucks blancos. Los lentes deslizándose un poco por la nariz. “Más interesante es Daniel.”
Stefan miró más allá de ella hacia el área de QA.
El Moleskine de Daniel estaba cerrado.
Eso por sí solo ya contaba como fenómeno meteorológico.
Estaba hablando con uno de sus testers y señalando una pantalla, y desde esa distancia Stefan no podía leer el código, pero sí la postura. Curiosa, no defensiva.
“Esta mañana me preguntó si Navigator podía correlacionar adiciones de pruebas automatizadas con defectos escapados a lo largo del tiempo”, dijo Katja.
“Esa es una pregunta muy Daniel.”
“Y también útil. Le dije que sí, si el tagging se mantiene limpio.” Hizo una pausa. “Luego preguntó si QA debería empezar a escribir checks ejecutables de aceptación para las regresiones más costosas en lugar de esperar a que desarrollo les entregue tickets rotos en tres formatos.”
Stefan volvió a mirar la pantalla mural.
“Ahí está”, dijo.
“¿Qué?”
“El momento en que la gente de proceso descubre que en realidad no quiere más puertas. Quiere mejor evidencia.”
Katja cruzó los brazos.
“Estás orgulloso de ti mismo.”
“Un poco.”
“Asqueroso.”
Él sonrió.
En la pantalla, la actividad de Mariana resaltaba por las razones correctas. Más commits. Diffs más pequeños. Pruebas agregadas antes de los cambios de comportamiento. Un experimento revertido que se había deshecho en doce minutos porque la prueba fallida le dijo exactamente qué había entendido mal. Falla contenida lo bastante pronto para salir barata. Eso también era progreso, aunque nadie lo pusiera en presentaciones.
“Lee la nota de Sofia”, dijo Katja.
Entró a la síntesis diaria de bitácoras.
Sofia había escrito tres líneas la noche del jueves:
Yo pensaba que TDD era demostrar que era lo bastante inteligente para pensar por adelantado. No lo es. Es hacer el problema tan pequeño que dejo de fingir que entiendo más de lo que entiendo.
Stefan la leyó dos veces.
“Ese es todo el currículum”, dijo.
La boca de Katja se curvó. No exactamente una sonrisa. Aprobación con mejor estructura ósea.
“La de Mariana es más sucia”, dijo.
Abrió la siguiente nota.
Las pruebas no son religión. Son declaraciones de testigos. El código miente. Las pruebas hacen que mienta menos.
Stefan se rió tan fuerte que Katja tuvo que esperar para seguir hablando.
“No está equivocada”, dijo.
“No. Rara vez lo está cuando se enoja lo suficiente.” Katja volvió a mirar el piso de backend. “¿Y Anton?”
Abrió su nota.
Era una sola oración.
Todavía odio el sermón, pero odio más los requisitos invisibles.
Eso casi acabó con Stefan.
Katja dejó que el silencio se quedara un momento. No sentimental. Solo observador.
Afuera de la sala de juntas, el viernes se estaba desarmando como se desarman las oficinas sanas. No colapsando. Bajando de intensidad. Sillas echándose hacia atrás. Música baja. Bolsas apareciendo. Hassan ya se había ido a las 17:03. Segundo jueves en dos semanas que salía a tiempo, y ahora un viernes para empatar. Nadie entrando en pánico. Nadie encimado sobre el pipeline esperando una cuchillada sorpresa.
“¿Sabes qué cambió primero?”, dijo Katja.
“Dime.”
“No las métricas. La postura.” Asintió hacia el piso. “La gente se ve menos cazada. Mariana ya no se tensa antes de cada fusión. Sofia ya no se disculpa antes de hacer preguntas. Daniel sigue siendo Daniel, pero ahora tiene curiosidad. Hasta Anton está peleando con nosotros desde adentro de la conversación en vez de desde afuera.”
Stefan observó la sala a través del vidrio.
Ella tenía razón.
El cambio no era lo bastante dramático para ejecutivos. Todavía no. Ningún gran antes y después. Ningún hero shot. Solo ese desplazamiento casi invisible del miedo anticipado a la atención situada. Los equipos que dejan de esperar que el software los embosque piensan distinto. Hasta se paran distinto.
“¿Qué sigue?”, preguntó Katja.
Esa era la pregunta real. No si esta semana había funcionado. Sino si la próxima crisis iba a dejar que siguiera funcionando.
Stefan miró el calendario de live ops clavado al lado de la pantalla. La próxima semana, lanzamiento del evento de verano. Pico de concurrencia más grande de lo usual. Recompensas más costosas. Las mismas brechas de infraestructura por las que Daniel llevaba meses insistiendo. Ningún staging que reflejara producción. Pruebas de carga todavía teóricas.
“Lo siguiente”, dijo, “es que la realidad compruebe si el aprendizaje ocurrió a tiempo.”
Katja siguió su mirada hasta el calendario.
Le cambió la cara.
No exactamente miedo.
Reconocimiento.
“El evento”, dijo.
“Sí.”
Se quedaron en silencio un momento, mirando el mismo problema desde altitudes distintas.
Luego Katja cerró la laptop.
“Bien”, dijo. “Al menos ahora vamos a saber más rápido por qué se rompe.”
“Habla el alma de un CTO.”
“Vete al carajo”, dijo, abriendo ya la puerta.
Él la siguió de vuelta al piso.
Mariana levantó la vista de inmediato.
“¿Nos toca veredicto?”, preguntó.
Katja agarró la bolsa del respaldo de la silla.
“Sí”, dijo. “Todos están un poco menos caóticos que el lunes. No se pongan sentimentales por eso.”
Sofia se rió.
Anton levantó una mano en bendición fingida.
“Vayan en paz, hijos míos de la prueba fallida.”
“Sigues siendo un imbécil”, dijo Mariana.
“Diseño de personaje consistente”, dijo Anton.
Daniel, desde el otro lado del piso, sonrió de verdad.
Pequeño. Breve. Real.
Tal vez eso fue lo más raro que vio alguien en toda la semana.
Navigator — Katja Müller — 5 de junio de 2026, 22:11
Semana uno de adopción de TDD. Casi solo backend. El equipo de Unity orbitando la conversación como cuervos desconfiados.
Stefan introdujo rojo-verde-refactor el lunes por la mañana. Anton lo llamó religión antes de que Stefan terminara la segunda frase. Objeción justa, la verdad. El desarrollo ya tiene suficientes rituales. La distinción útil que hizo Stefan: el ritual se defiende a sí mismo. La retroalimentación cambia el comportamiento. Esa línea se quedó.
Mariana lo adoptó de inmediato. No performativamente. Prácticamente. Usó TDD en el bug de la racha diaria de recompensas que lleva semanas persiguiendo a soporte y dijo, textual: “Esta es la primera vez que el código ha tenido que responderme antes de que se ponga a mentir en producción.” Probablemente debería poner eso en una pared.
Sofia tuvo la semana opuesta. Frustración total al principio. Escribió pruebas gigantes que no demostraban nada porque estaba tratando de arrastrar todo el sistema a cada aserción. El miércoles a las 16:02 algo hizo clic. Borró un monstruo de setenta líneas, redujo el problema a una sola regla de cooldown y escribió el código más limpio que le he visto. Su confianza cambió en tiempo real.
Anton sigue escéptico, lo cual sirve. Tiene razón en que no todo el código de juego se beneficia de la misma estrategia de pruebas. El rendering y el game feel no son reglas de negocio de backend. Pero incluso Anton admitió hoy en su bitácora que odia más los requisitos invisibles que “el sermón”. Eso es progreso en idioma Anton.
La reacción de Daniel es la más interesante. Entró preguntando cuánto tiempo agregan las pruebas. Para el viernes ya estaba preguntando si QA podía automatizar pruebas de aceptación contra ejemplos explícitos de comportamiento en lugar de interpretar tickets vagos cuando desarrollo ya terminó. Puede que esté dándose cuenta de que las pruebas automatizadas pueden reemplazar parte del teatro de aprobación que construyó para crear seguridad. No creo que le guste esa conclusión, pero tampoco está huyendo de ella.
Señales de Navigator de esta semana:
- Los tamaños de pull request de backend se mantuvieron por debajo de 100 líneas toda la semana.
- Se tocaron archivos de prueba en el 81 % de los commits de backend.
- Los comentarios de review se volvieron más cortos y más específicos.
- La actividad de commits se distribuyó a lo largo del día en lugar de amontonarse en pánico de fin de sprint.
- El repositorio de Unity sigue sin cambios por ahora. El escepticismo se ve tanto en el código como en las bitácoras.
La curva de adopción es dispareja. Bien. El cambio real es disparejo.
La próxima semana es el evento de verano en vivo. Más carga de lo habitual. Sigue sin existir un entorno de staging que refleje producción. Daniel ha tenido razón con eso desde hace meses. Si el evento explota, no será porque TDD haya fallado. Será porque seguimos aprendiendo una práctica nueva mientras cargamos deuda vieja de infraestructura hacia un pico nuevo de tráfico.
Pero el equipo ahora piensa antes. Más pequeño. Más claro. Eso no basta para salvarnos de todo. Puede ser suficiente para mostrarnos exactamente dónde está la siguiente fractura.