Hola devs, hace poco estando en pleno vuelo me puse a investigar sobre aeronáutica y es que muchos ingenieros de software olvidan que nuestra profesión está ligada también a esta rama de la ingeniería y este mundo, además de divertido, es genial. Así que prendamos turbinas y arranquemos.
En el mundo del desarrollo web o de aplicaciones móviles existe un meme muy conocido: "Nunca despliegues a producción un viernes". Nos hace gracia porque sabemos que, si algo sale mal, probablemente pasaremos el fin de semana corrigiendo errores bajo la presión de clientes molestos o servicios caídos. Es estresante, pero, en la mayoría de los casos, nadie pierde la vida porque un microservicio de comercio electrónico falle.
Ahora cambiemos completamente de escenario.
Imagina que estás a 10.000 metros de altura, cruzando el Atlántico a unos 900 km/h dentro de un avión comercial. El piloto automático mantiene el rumbo mientras el avión atraviesa una zona de turbulencia. En ese instante, el software encargado de controlar las superficies de vuelo o de gestionar el funcionamiento de los motores no puede permitirse un reinicio inesperado, una condición no contemplada o un error provocado por una combinación lógica que nadie probó.
En la aviación comercial, el software no se mide por la cantidad de funcionalidades que incorpora, sino por el nivel de riesgo asociado a un posible fallo. Por eso, actualizar un sistema de vuelo no consiste en hacer un git push o desplegar un nuevo contenedor. Antes de que una nueva versión llegue a un avión, puede pasar meses o incluso años atravesando procesos de desarrollo, verificación, validación y certificación extremadamente rigurosos.
¿Cómo se consigue que ese software alcance niveles de confiabilidad tan extraordinarios?
Una parte importante de la respuesta está en DO-178C, el estándar internacional utilizado para el desarrollo y certificación del software embarcado en aeronaves civiles, del cual planeo explicarte más a detalle en este artículo.
No todo el software tiene la misma importancia
Sería absurdo aplicar el mismo nivel de exigencia al software que muestra las películas del sistema de entretenimiento a bordo que al software encargado de mantener estable el avión durante el vuelo.
Por eso, antes de desarrollar un sistema, se realiza un análisis de seguridad que determina cuál sería el impacto de un fallo. A partir de ese análisis se asigna un Design Assurance Level (DAL) y DO-178C establece el nivel de rigor que deberá seguir el desarrollo del software correspondiente.
Los niveles DAL, o para entenderlo mejor, los niveles de criticidad del software, son los siguientes:
Nivel A (Catastrófico)
Un fallo podría provocar la pérdida del avión y de vidas humanas.
Ejemplos: determinadas funciones de control de vuelo (fly-by-wire) o componentes críticos del FADEC (Full Authority Digital Engine Control).
Nivel B (Peligroso)
El fallo produciría una degradación importante de la seguridad, aumentaría considerablemente la carga de trabajo de la tripulación o podría ocasionar lesiones graves.
Aquí están determinados sistemas de navegación, algunas funciones de gestión del vuelo o sistemas de alerta cuya pérdida dificultaría significativamente la operación de la aeronave.
Nivel C (Mayor)
El fallo reduce de forma significativa el margen de seguridad o incrementa el trabajo de los pilotos, aunque la aeronave sigue siendo controlable.
Aqui están determinadas funciones de comunicación, algunos sistemas de monitoreo de la aeronave o ayudas a la gestión de cabina de vuelo.
Nivel D (Menor)
El fallo produce inconvenientes menores o reduce ligeramente el confort de la operación.
Ejemplo: Sistemas de iluminación de cabina, funciones auxiliares de información para la tripulación o determinados sistemas de confort.
Nivel E (Sin efecto sobre la seguridad)
Un fallo no tiene consecuencias para la seguridad del vuelo.
Por ejemplo, aquí están el sistema de entretenimiento a bordo (IFE, In-Flight Entertainment), las pantallas donde los pasajeros ven películas o determinadas aplicaciones de información para los pasajeros, como LATAM Play, para que te hagas una idea, estimado dev.
A medida que aumenta el nivel de criticidad, también aumenta de forma considerable el esfuerzo necesario para demostrar que el software es correcto. En un sistema DAL A prácticamente cada línea de código debe poder justificarse mediante uno o varios requisitos previamente definidos. No existe espacio para la improvisación ni para desarrollar funcionalidades "por si acaso".
Cuando el 100 % de cobertura no es suficiente
Muchos equipos consideran que alcanzar un 80 % o 90 % de cobertura de código en sus pruebas unitarias representa un excelente resultado.
En software aeronáutico crítico, eso apenas sería el punto de partida.
Para los sistemas DAL A, DO-178C exige un criterio de cobertura estructural denominado MC/DC (Modified Condition/Decision Coverage).
Supongamos que tenemos una condición como esta:
if (SensorA_Ok && (SensorB_Altitud > 5000 || ModoManual_Activo))
No basta con comprobar que el if entra una vez y no entra otra.
MC/DC exige demostrar que cada condición individual puede modificar por sí sola el resultado final de la decisión, manteniendo constantes las demás condiciones siempre que sea posible.
En otras palabras, hay que diseñar casos de prueba específicos que demuestren que cada parte de la expresión lógica influye realmente en el comportamiento del software.
Puede parecer un proceso extremadamente costoso, y lo es. Sin embargo, reduce enormemente la probabilidad de que existan caminos lógicos ocultos que nunca fueron ejercitados durante las pruebas.
En DO-178C el código muerto no tiene cabida
En muchos proyectos es habitual dejar métodos antiguos, variables que ya nadie utiliza o funcionalidades deshabilitadas "por si algún día vuelven a hacer falta".
En un proyecto certificado bajo DO-178C eso simplemente no es aceptable.
El dead code no está permitido porque no puede asociarse a ningún requisito del sistema ni justificarse durante la certificación. Además, incrementa innecesariamente la complejidad del software y dificulta demostrar su cobertura estructural y su trazabilidad.
La filosofía es sencilla: si una línea de código no existe por una razón claramente definida y verificable, no debería formar parte del producto final.
La trazabilidad lo conecta absolutamente todo
Uno de los conceptos más impresionantes de DO-178C es la trazabilidad.
Cada requisito debe poder seguirse a lo largo de todo el ciclo de desarrollo:
- Requisito del sistema.
- Diseño.
- Código fuente.
- Código objeto generado.
- Casos de prueba que verifican ese comportamiento.
Si en una auditoría alguien pregunta por qué existe una determinada línea de código, el equipo debe ser capaz de demostrar exactamente qué requisito la originó y qué pruebas verifican su funcionamiento.
Ese nivel de disciplina puede parecer excesivo para una aplicación empresarial, pero transmite una enseñanza muy valiosa: cuanto más crítico sea un sistema, más importante resulta entender por qué existe cada pieza del software.
Lecciones para nuestros sistemas backend
Si bien la probabilidad de que desarrolles software certificado para un Airbus o un Boeing es baja, la mentalidad que hay detrás de DO-178C puede mejorar considerablemente cualquier sistema empresarial.
Clasifica tus componentes según su criticidad
No todo merece el mismo nivel de pruebas.
El servicio que procesa pagos con tarjeta o realiza transferencias bancarias debería recibir un nivel de validación, monitoreo y revisión mucho mayor que el módulo que genera reportes estadísticos.
Elimina el código innecesario
Cada línea adicional aumenta el coste de mantenimiento, dificulta las revisiones y puede convertirse en una fuente futura de errores.
Menos código suele significar menos problemas.
Invierte en trazabilidad
Logs estructurados, IDs de correlación, documentación de decisiones arquitectónicas y requisitos bien definidos reducen enormemente el tiempo necesario para investigar incidentes en producción.
Cuando un sistema falla bajo presión, la trazabilidad vale mucho más que la memoria del desarrollador que escribió ese código hace tres años.
Te recomiendo que leas este artículo sobre observabilidad.
Conclusión
El software aeronáutico no es extraordinariamente confiable porque sus ingenieros nunca cometen errores.
Lo es porque todo el proceso está diseñado asumiendo precisamente lo contrario: que los errores humanos son inevitables.
Por eso existen múltiples capas de revisión, requisitos rigurosos, pruebas estructurales avanzadas, trazabilidad completa y procesos de certificación extremadamente exigentes antes de que una sola línea de código llegue a un avión.
La próxima vez que sientas la tentación de omitir pruebas, aprobar un Pull Request complejo sin revisarlo a fondo o introducir cambios importantes sin evaluar sus riesgos, recuerda la filosofía detrás de DO-178C.
Probablemente tu software no controle un avión a 10.000 metros de altura. Pero construir sistemas robustos siempre empieza con la misma pregunta: ¿Qué ocurriría si este código fallara en el peor momento posible?
Así que la próxima vez que alguien intente presionar para desplegar un cambio crítico sin probarlo un viernes por la tarde, recuérdale que el código pertenece a la aplicación, pero la responsabilidad del entorno es nuestra. Al final del día, crack, la diferencia entre un picador de código y un ingeniero de software es saber qué pasa si tu sistema falla en el peor momento posible.
Ya sabes qué hacer... sí, compartir!
