Aunque las tecnologías avancen, aunque las velocidades de computación se multipliquen y aunque aparezcan algoritmos cada vez más sofisticados, en el mundo del software, probablemente como en cualquier otra disciplina humana, al final existen una serie de criterios comunes, una serie de principios o buenas prácticas que son aplicables de forma generalizada y que muchas veces, al final son casi mera experiencia y mero sentido común.
Por motivos profesionales que no vienen al caso, estoy revisitando la teoría referente a la Ingeniería del Software, una disciplina que ya podemos considerar veterana y sobre la que, de hecho, poco se publica ya, si no es en su vertiente Agile. Y en esa labor estoy leyendo el voluminoso libro 'Software Engineering. Global Edition' de Ian Sommerville, bien organizado y escrito, pero que aporta pocas sorpresas porque, en efecto, la Ingeniería de Software, no sé si disfruta o sufre ya de una cierta estabilidad.
Ocho buenas prácticas de Ingeniería Software
Y me voy a detener en un punto del libro en que señala ocho líneas maestras o buenas prácticas de diseño y desarrollo para conseguir la fiabilidad ('reliability') de un sistema software. Son estas:
- Control de la visibilidad de la información: Nos aconseja que la información, es decir, las variables, tengan la menor visibilidad posible, primando las variables locales antes que las globales, y dentro de las locales, que su ámbito sea lo más limitado posible. Una buena práctica tradicional donde las haya, que elimina acoplamientos entre componentes favoreciendo la modularidad y que, además, disminuye la probabilidad de que un componente, inadvertidamente, altere el valor de una de forma perjudicial para otra parte del software.
- Chequear la validez de todas las entradas: Es decir, nunca suponer que los datos van a tener el formato o rango correctos. Si un dato debe ser numérico o fecha, comprobar que es así antes de trabajar con ese dato. Si un dato debe estar comprendido en un cierto rango, por ejemplo, ser mayor que cero, comprobar que es así antes de utilizarlo. Esto es farragoso y aumenta, es cierto, el tiempo de desarrollo e incluso, ligeramente, el de ejecución, pero convierte al software en mucho más robusto y vale la pena sin dudarlo.
- Proporcionar un manejador para todas las excepciones: Una regla fundamental de robustez es capturar todos los errores y excepciones y darles un tratamiento, lo más específico posible pero, en cualquier caso, algún tipo de tratamiento que evite que el sistema, simplemente 'se caiga' o que el usuario o un administrador no puedan saber lo que ha ocurrido.
- Minimizar el uso de construcciones propensas a error: En software, como en muchas otras actividades humanas, quizá mucho más que en otras actividades humanas, lo más sencillo funciona mejor. Esta recomendación, algo ambigua, va en el sentido, precisamente, de utilizar los tipos de datos, estructuras, algoritmos, etc más sencillos posible y con menor probabilidad de error. Se nos proporciona como ejemplo la recomendación de, en lo posible, usar números enteros en lugar de números decimales en coma flotante, ya que estos segundos generan muchos errores, por ejemplo, por redondeos. Otra construcción que se desaconseja es el uso explícito de memoria dinámica, algo que ha dado muchísimos quebraderos de cabeza, por ejemplo, a los programadores en C o C++.
- Proporcionar capacidades de rearranque: Se trata de que, ya que a pesar de todas las precauciones, en ocasiones el software falla, quizá en medio de una transacción o procesamiento largo, al menos dar la capacidad de rearrancar y retomar el trabajo donde se encontraba, para lo cual es necesario de alguna forma registrar la información intermedia y tener medios para recuperarla tras el rearranque.
- Comprobar las fronteras de matrices: Se trata de, cada vez que trabajemos con un matriz o vector, comprobar que cualquier índice de acceso a un elemento concreto, está dentro de los límites previstos. Si tenemos un vector de 100 elementos, no podemos acceder al elemento 200 ni, por supuesto a un índice negativo. Particularmente peligroso es el acceso al primer y último elemento de la matriz porque, según el lenguaje de programación, el primer elemento puede tener como índice 0 o 1 y es fácil equivocarse. Un acceso fuera del rango puede llevar a acceder a zonas de memoria no permitidas provocando errores serios.
- Incluir 'timeouts' en llamadas a componentes externos: En ocasiones, los sistemas externos fallan, tardan demasiado o son las propias comunicaciones las que fallan o van lentas. Y pueden fallar sin dar un error explícito. Por eso, no conviene esperar indefinidamente a que se complete la invocación a un servicio o sistema externo sino que se debe introducir un temporizador que, caso de vencerse, eleve la excepción correspondiente o provoque el tratamiento de error que proceda.
- Nominar a todas las constantes que representan valores reales: La idea es doble. Por un lado, no incluir 'a fuego' un valor en el código, sino ponerlo en función de una variable o constante y usarlo referenciando a esa variable o constante. Pero además, la directriz lo que sugiere es que cualquier elemento de la vida real, incluso aunque no preveamos que vaya a cambiar, lo convirtamos en una variable o constante. Así, por ejemplo, podríamos incluir como constante el tipo básico del IVA. De esta forma,ningún valor queda en piedra en el código sino que es siempre una constante o variable. Y además, si a pesar de nuestras expectativas, el valor de ese elemento de la vida real, en este caso el tipo básico del IVA, cambia, el software puede modificarse por una simple configuración, sin actualizar el código.
Y, sin embargo, las ocho directrices están plenamente vigentes.
Buenas prácticas en robotización software
De hecho, ahora que personalmente dedico bastante energías al mundo de la robotización software y, específicamente, al RPA (Robotic Process Automation), incluyendo ya muchas horas de formación a alumnos de empresas o jóvenes en busca de primer empleo, comparo estas directrices con las que se aplican en el mundo de la robotización...y hay una enorme, casi total, coincidencia.
También disponemos de ámbitos de variables que se aconseja sean locales, también se capturan excepciones, también se insta a procesar todos los errores y protegerse ante datos con formato incorrecto o fuera de rango (aunque en el caso de RPA esa labor con frecuencia viene dada ya desde sistemas externos), también se dispone de rearranque, también hay constantes en ficheros de configuración... Incluso, el líder del mercado UiPath, dispone de una plantilla, el Robotic Enterprise Framework una de cuyas misiones es, precisamente, ayudar a crear robots que ya traen de serie algunos de estos elementos como el tratamiento de ciertas excepciones, el rearranque o un trazado básico).
Y es que los robots software son, eso, software.
Y software llevamos ya muchos años construyéndolo, y algo hemos aprendido.
El sentido común
Al final, aunque la tecnología evoluciona, aunque hay nuevos sistemas, nuevas herramientas y nuevos algoritmos, la experiencia es la experiencia y el sentido común es el sentido común.
Y el sentido común es, o debería ser, universal y casi eterno.