El caso Ariane es un perfecto ejemplo de lo que un bug es capaz de hacer a gran escala, por eso lo uso en mis charlas, pero aquí lo explicaré con más detalles. Empecemos, cracks.
El 4 de junio de 1996, la Agencia Espacial Europea lanzó el Ariane 5 en su vuelo inaugural. Era el sucesor del exitoso Ariane 4 y representaba años de desarrollo e investigación. Sin embargo, apenas 37 segundos después del despegue, a una altitud cercana a los 3.700 metros, el cohete comenzó a desviarse bruscamente de su trayectoria y, un segundo después, se autodestruyó en una gigantesca bola de fuego.
El programa Ariane 5 había supuesto una inversión superior a 4.300 millones de dólares, y su primer lanzamiento terminó en desastre.
Cuando el comité de investigación analizó lo sucedido, no encontró un fallo en los motores, ni una explosión del combustible, ni un problema estructural. El origen de todo estaba en el software de navegación. Un error que, aunque ocurrió en un cohete espacial, tiene una enseñanza que cualquier desarrollador backend debería conocer.
Anatomía del bug: una conversión numérica fuera de rango
Gran parte del software del sistema de navegación del Ariane 5 fue reutilizado del Ariane 4. Era código probado durante años y había demostrado ser extremadamente fiable.
Dentro de ese software existía una rutina que calculaba un valor relacionado con la velocidad horizontal del cohete respecto a la plataforma de lanzamiento.
En el Ariane 4, esa velocidad nunca alcanzaba determinados valores físicos, por lo que los ingenieros concluyeron que convertir ese dato en un entero de 16 bits con signo era completamente seguro.
El problema fue que el Ariane 5 era un cohete completamente distinto.
Su aceleración era considerablemente mayor y, aproximadamente en el segundo 36 del vuelo, ese valor superó el rango máximo que podía almacenar un entero de 16 bits con signo (32.767).
Cuando el software intentó realizar la conversión, se produjo una excepción por conversión numérica fuera de rango.
El supuesto que había sido válido durante años dejó de ser cierto.
El efecto dominó
Lo que ocurrió después es una lección magistral sobre cómo una pequeña decisión de diseño puede desencadenar un fallo catastrófico.
Al producirse la excepción, el sistema de navegación principal dejó de funcionar.
Aquella conversión no estaba protegida porque los ingenieros habían demostrado, basándose en el comportamiento del Ariane 4, que esa situación nunca podía producirse. El coste de validar esa operación continuamente se consideró innecesario.
Para aumentar la fiabilidad, el cohete disponía de un segundo sistema de navegación completamente redundante.
Pero había un problema.
Ejecutaba exactamente el mismo software. Oops...
Apenas un instante después sufrió la misma excepción y también dejó de funcionar.
A partir de ese momento, las computadoras de vuelo comenzaron a interpretar información de diagnóstico del sistema como si fueran datos válidos de navegación. Como consecuencia, ordenaron un giro extremo de las toberas de los motores para intentar corregir una desviación que en realidad no existía.
Las fuerzas aerodinámicas terminaron superando los límites estructurales del cohete y el sistema automático activó la autodestrucción por motivos de seguridad.
Todo ocurrió en apenas unos segundos.
Lecciones de trinchera para el desarrollo backend
Aunque probablemente nunca programemos el software de un cohete espacial, las decisiones que provocaron este accidente siguen apareciendo todos los días en aplicaciones empresariales, aquí te listo algunas lecciones en base a mi experiencia y la muchos otros ingenieros que he podido recopilar:
Reutilizar código no es el problema; reutilizar supuestos sí
El software del Ariane 4 funcionaba perfectamente.
Lo que cambió fue el contexto.
Los ingenieros asumieron que las condiciones físicas seguirían siendo las mismas y reutilizaron una decisión de diseño que ya no era válida.
En el backend ocurre constantemente.
Por ejemplo, elegir un INT porque "nunca vamos a superar esa cantidad de registros", asumir que un archivo "jamás pesará más de 100 MB" o pensar que un identificador "siempre cabrá en un entero".
El código puede seguir funcionando exactamente igual durante años… hasta que el negocio crezca y, cuando crezca lo suficiente, tú ya estarás ocupado en otras cosas, o quizá ni estés en la empresa, jajaja, así que es muy fácil que se te pase por alto, completamente.
Diseña pensando que los límites cambiarán
Los requisitos cambian.
Los volúmenes aumentan.
Los usuarios hacen cosas que nadie esperaba.
Elegir correctamente los tipos de datos, validar los rangos de entrada y desconfiar de los supuestos del pasado suelen costar mucho menos que corregir un sistema cuando esos límites dejan de cumplirse.
La redundancia no corrige errores de lógica
Uno de los aspectos más interesantes del accidente fue que el Ariane 5 disponía de un sistema redundante.
Sin embargo, ambos ejecutaban exactamente el mismo software.
Cuando el primero falló, el segundo repitió exactamente el mismo error.
En arquitectura de software ocurre algo parecido.
Tener varias instancias de una API detrás de un balanceador de carga mejora la disponibilidad frente a fallos de infraestructura, pero si todas ejecutan el mismo bug, todas fallarán exactamente igual.
La redundancia protege frente a fallos de hardware.
No protege frente a errores de diseño, toma nota crack.
Saquemos conclusiones devs...
El Ariane 5 no explotó porque reutilizó código.
Explotó porque reutilizó supuestos que habían dejado de ser válidos.
Y esa es una lección que sigue plenamente vigente casi treinta años después.
Cada vez que asumimos que un número nunca crecerá, que un usuario nunca hará determinada acción o que una condición "jamás podrá ocurrir", estamos tomando una decisión de diseño basada más en nuestras expectativas que en la realidad.
La ingeniería de software consiste precisamente en prepararse para el día en que esas expectativas dejen de cumplirse.
Y ahora que ya conoces la historia, crack, compártela con tu equipo. Porque a veces un supuesto incorrecto puede costar mucho más que una línea de código.
Créditos de imagen de portada:
