Contrario a lo que muchos creen, desarrollar software fiable para nuestros Sistemas Complejos no es tarea trivial.
En esa área, nuestros productos tecnológicos modernos tienen millones de líneas de código, se entrelazan con bibliotecas de programas desarrolladas por múltiples fabricantes, al igual que incorporan funcionalidades de red, que habilitan servicios distribuidos y/o colaborativos para esos sistemas. Se dice fácil, pero el trasfondo es que puede llegarse a tratar con miles de lógicas y ello es un reto en el análisis y construcción de instrumentos computarizados, cuya operatividad es altamente compleja y puede verse afectada, parcial o completamente, si no se cuidan todas las aristas de tan exigente proceso.
Puede que no lo parezca pero programar sobre sistemas de control, de operación o de supervisión, en tiempo real, implica tratar con un concepciones no tangibles de lógica matemática y a menudo con abstracciones, cuyo trasfondo funcional comúnmente son modelos con alguna base algebraica. Un simple canal de datos compartido entre dos entidades de ejecución independiente y continua, plantea desafíos sobre el momento válido para realizar accesos al mismo y efectuar operaciones de lectura o escritura. A eso, en la literatura asociada se le llama sincronización y discurrir sobre las posibilidades en el tiempo, de las potenciales coincidencias, que pudieran producir resultados no deseados o inesperados, se puede hacer con sustento probabilístico .
Técnicamente, la programación de ese caso de colaboración se denomina desarrollo con tubería comunicante (“pipe”) y puede hacerse bajo esquemas del tipo, con nombre o anónimo, para comunicar datos entre procesos o hilos de ejecución. Algo que se estudia en las primeras semanas de clases de casi todos los cursos universitarios de sistemas operativos, algoritmos distribuidos o programación intermedia, pero que exige la mente siempre despierta frente a los potenciales escenarios de ejecución. Y es que el hecho de un único elemento sensible, que quede defectuoso, puede originar una falla en cascada y tumbar al sistema entero.
De hecho, parece que esa fue la raíz del fiasco del fin de semana pasado, con Crowdstrike® y Microsoft Windows®, que causó secuencias de ciclos de inicios del sistema, al igual que pantallas azules en aeropuertos, hospitales y bancos.
Al principio, los ingenieros de software de la empresa de seguridad pensaban que el problema de la actualización de software radicaba en una falla con un manejador (“driver”), que se incrustaba en el sistema de operación de la empresa de Redmond. Pero más tarde se decantaron por el manejo de la tubería con nombre (“name pipe”). Toda esta información se deduce por la lectura de algunos “blogs” especializados, pero no debe olvidarse, que uno de los pilares del negocio de Microsoft, se basa en mantener una “confidencialidad compartida” de su código fuente con socios en desarrollo y el uso de especificaciones de componentes comunes, que dificulta conocer con exactitud al sistema entero y advertir los detalles reales. Esta aproximación, así como el contenido de la licencia de uso que acompaña al producto, deja al cliente atado de manos hasta que los fabricantes le ofrezcan la solución técnica. Una orientación distinta a la del software abierto o el software libre, que pueden escapar de estos embrollos pero tienen algunos propios y otros afines.
A pesar de eso, muchos conocedores siguen preguntándose cómo una falla de tal magnitud pudo acontecer con empresas que llevan años y tienen dominio en el arte del desarrollo de software, por lo cual suponemos que los involucrados deben estar revisando hasta la médula sus mecanismos y modos de trabajo. El panorama técnico no es nada simple y es que existen muchos lados que examinar.
Así pues, desde hace tiempo existen lenguajes de programación especializados, que ayudan a evitar que líneas de código puedan ser manipuladas por errores básicos tales como escribir en áreas de memorias no autorizadas, pero en nuestros días, aún en mucha de la programación cercana al hardware y sistemas operativos predominan lenguajes como C++, incluso bajo Kits de Desarrollo, y eso exige mayor atención de parte de los programadores. Otra complejidad es la evolución de los mismos requerimientos, especificaciones y otros códigos subyacentes, lo cual incorpora el fenómeno del dinamismo durante el mismo proceso de desarrollo. Bastante literatura existe para tratar con estas y otras dificultades técnicas, pero no debe olvidarse que el desarrollo de software se encuentra en un área, a veces delgada y confusa, que se ubica entre la frontera de ser suficientemente flexible con la creatividad del programador y la de aplicar formalidad rígida, a veces rayando en lo algebraico, que reduce incoherencias y futuros problemas de compatibilidades.
Otro aspecto que debemos tener presentes es comprender la noción de “seguridad” de algunas bases de operaciones de nuestras aplicaciones y funcionalidades diarias, como es el propio sistema Windows. Como parte de su diseño, Windows deja que mucha de su protección le sea añadida por componentes externos, como por ejemplo son los programas anti-virus y anti-malware. Esto agrega una capa de resguardo ante potenciales peligros, pero hacer eso se paga con un costo en ceder control propio del sistema operativo o incrustarse tales componentes, como extensiones del mismo sistema, pero no pensadas originalmente. La paradoja radica en que esos componentes que lo resguardan, también son software y por esa naturaleza igual, pueden adolecer de las mismas debilidades que el software que pretenden proteger. Todo eso no es una dificultad simple de solventar, ya que el tema de la seguridad de sistemas y de software por décadas ha traído de cabeza a muchos investigadores y a la luz de cualquiera, está lo frágil de nuestros sistemas informáticos y de comunicaciones modernos.
A esto habría que añadir la enorme presión comercial que origina el entorno competitivo de la industria de software, donde no siempre se dispone de los plazos de tiempo ideales para verificar toda la ingeniería usada y se apela, al mínimo de calidad aceptable para liberar el producto. Teniendo como malla de protección el esquema de parches de software para correcciones y/o ajustes. Esto puede ser una solución que evite líos judiciales a los fabricantes, pero no incide como mejora sustancial en la calidad final del software. También tiene un trasfondo paradójico que apunta a que con mayor volumen de parches, la estabilidad del diseño original se empieza a resentir y la entropía en la ingeniería del producto tiende a crecer. Todo eso nos trae de nuevo al mundo probabilístico y resulta un nuevo recordatorio, de la necesidad de estimar bien sobre los mundos de posibilidades de ejecución que tratamos de gobernar.
Es así como se puede comprender que desarrollar buen software no es tan simple como muchos piensan; que creen que basta con dominar un lenguaje de programación, conocer bien un entorno de desarrollo y apelar a técnicas clásicas como desarrollo de arriba a abajo (“top down”). El asunto es mucho más complejo y hay que cumplir con todas las lecciones que se aprenden, desde las básicas y primitivas hasta las avanzadas y altamente sofisticadas. Y es que cuando desestimamos nuestras bases teóricas-prácticas, podemos presenciar contingencias a nivel mundial que perjudican directamente a miles de humanos e indirectamente, a cientos de miles o hasta millones.
Para el resto del mundo que usa la computación, no la construye, es bueno que tengan muy presente los niveles de dependencia que tenemos con nuestras tecnologías informáticas, al igual que las debilidades intrínsecas, ya que siempre hay espacio para errores, equivocaciones, sabotajes y hasta guerras en el ciberespacio. No somos inmunes a estas dificultades y a medida que los sistemas se extienden e interconectan entre sí, las amenazas y problemas aumentan en cantidad y/o volumen.
Puede que tengamos que volver a mirar más allá de lo que tenemos al frente y para eso podemos empezar revisando aquellas sentencias de investigadores reconocidos, que estudiamos en la universidad, como la doctora Nancy Leveson del Instituto Tecnológico de Massachusetts, quien expresó: “La ingeniería de sistemas de gran escala es más que una simple colección de artefactos tecnológicos: es un reflejo de la estructura, de la gestión, de los procedimientos y de la cultura de la organización de ingeniería que los creó. Suele ser también un reflejo de la sociedad en la que estos fueron creados.”
Autor: Miguel Torrealba Sánchez. Universidad Simón Bolívar. Departamento de Computación y Tecnología de la Información.
mtorrealba@usb.ve