El control de calidad para muchas compañías no pasa de ser una buena intención, incluso para aquellas que tienen implementado algún sistema de control de calidad. El problema de la calidad del software es tan antiguo como los mismos computadores, En 1975, Fred Brooks ya se refería a la naturaleza del problema de manera magistral en su libro “The Mythical Man-Month” y en su archi-citado paper “No Silver Bullet” (1995). En 1992, Bruce Sterling introducía el “concepto” de vulnerabilidad (de naturaleza humana, no mitificado como hoy en día) en su libro “The Hacker Crackdown” enunciando una relación entre las pruebas y la calidad de un software, y el peligro de los parches ó “mejoras”. Tomaremos estas dos visiones como enfoque para este articulo.
El software es (y lo será por siempre) construido por humanos, los que programan usando un lenguaje (de programación). Vale la pena detenerse un segundo y analizar la aburrida y obvia frase anterior. Los humanos cometemos errores, de hecho la gran mayoría de las catástrofes son producto de errores humanos, y el uso de lenguajes (idiomas) no esta libre de errores. El correcto uso de un lenguaje (idioma) requiere un estudio acabado de todas sus características, reglas, y por cierto mucha practica. Aun así, no será raro encontrar a un hispanoparlante fracasando una y otra vez en el uso de preposiciones del idioma ingles y a un anglosajón diciendo cosas como “La perro me masco el brazo”. Probablemente la frase anterior será comprendida perfectamente por cualquier hispanoparlante, pasando por alto los errores gramaticales, es decir estaría “correcta” y se aceptaría sin mayores reparos cumpliendo así el objetivo de comunicar. Sin embargo, si esa frase es escuchada por un medico, este reaccionaria en pánico al comprender que su brazo fue partido y triturado por un perro…cuando realmente solo fue un mordisco insignificante. Es decir, los errores en el uso de un lenguaje en algunos casos son inaceptables, simplemente los errores no se toleran, ya que incluso podrían comprometer la seguridad, vida de las personas ó ser un desperdicio de recursos, como en este ejemplo.
Ahora, volviendo al software y los lenguajes de programación (los usuarios –humanos- seguirán siendo los mismos) nos encontramos con escenarios parecidos. Existen sistemas (software) que tienen la connotación de “misión critica”, son aquellos sistemas que tienen estrictos y exigentes niveles de servicio, como por ejemplo; muchos 9 (parte decimal, después del entero 99) de up-time, restricciones de tiempo de respuesta (1 a 10 segundos), etc. Por alguna extraña razón, en muchos casos quienes definen estos requerimientos lo hacen lejos de los desarrolladores, si tenemos suerte participa el arquitecto. Y es en este punto donde empieza el problema; el eslabón perdido.
El software es construido lejos de la realidad -en el país de las maravillas- los desarrolladores nunca se enteraron de los niveles de servicios, por que no era tema de ellos; “Ese es un problema de infraestructura tecnológica, yo solo me preocupo de que este “programa” haga lo que tiene que hacer y no se caiga…y además, será el equipo de calidad (QA) quien se encargue de asegurar eso”. Y las compañías crean un proceso de desarrollo de software bajo ese paradigma.
El equipo de calidad, validara que el software haga lo que tiene que hacer, el foco estará en el negocio, punto y aparte. Ahora, el como lo hace es un problema de “otro”, que si tenemos suerte fue algo que alguna vez paso por la mente de un diseñador y/o arquitecto, sin embargo nadie diseña los programas ¿no?…claro! quien va diseñar un programa no tiene sentido!…de ahí la fama de Google de rechazar programadores, que no saben nada de diseño e implementación de algoritmos.
Veamos el siguiente caso: Un simple caso de prueba, donde se quiere obtener un reporte acerca de evidencia de vida extraterrestre en las nebulosas planetarias M27, M57 y NGC 7009. Es un software de carácter científico, en extremo complejo. El astrónomo ingresara su numero de empleado y el sistema le reportara información relevante acerca de su ultima “orden de exploración”. El sistema se conectara a 14 bases de datos de los distintos observatorios repartidos por el mundo, extraerá información, realizara complejos cálculos matemáticos y entregara un increíble resumen de tan solo 3 líneas desplegados en una linda interfaz enriquecida de una increíble aplicación Web construida con JEE. El Astrónomo y el equipo de QA se Irán tranquilos a sus casas, independiente de si encontraron vida extraterrestre o no.
Sin embargo los DBA de los 14 observatorios reportaran conexiones abiertas y abandonadas. Por su parte el administrador del servidor de aplicaciones reportara una serie de “Memory Leaks”. Las conexiones abandonadas no afectaron el caso de prueba, y si algún caso de prueba fallo producto de un “memory leak” simplemente se atribuyo el problema a una situación paranormal (tipo poltergeist) que fue resuelta con un simple reintento y/o reinicio del servicio (hasta del servidor) concluyendo finalmente que ese servidor se encuentra escaso de memoria.
Para validar esto ultimo, el equipo de QA decide hacer una prueba de stress al software, que simplemente es algo bárbaro (entiéndase algo incivilizado, en ningún caso genial) similar a probar un vehiculo todo terreno en la playa, a orillas del mar, que además de innecesario lo único que consigue es empeorar las cosas. Finalmente, se consigue comprobar de manera empírica que hay un problema con los programas, así lo corroboraron los 14 DBAs que tuvieron que construir scripts para cerrar conexiones abandonadas y el administrador del servidor de aplicaciones quien tuvo que “depurar” la maquina virtual del servidor de aplicaciones para constatar peaks críticos de creación de objetos que no se justifican para un programa que simplemente emite un reporte, complejo, pero reporte al fin y al cabo.
Los desarrolladores por su parte, calificaron de “inútil” los resultados y pruebas obtenidas por el equipo de QA, sumados al trabajo de los DBA y el administrador del servidor de aplicaciones, “de que sirve un log y un pantallazo!” exclamaron. Se vieron forzados a replicar el problema, generaron un nuevo servidor de desarrollo (conocidos como: preproducción, pruebas, auditorias, C3PO, R2D2, H1N1, entre otros), e instalaron las herramientas de profiling y monitoreo.
Al cabo de 4 semanas, el software contaba con un parche que solucionaba el problema.
Para el problema de conexiones abandonadas, solo fue necesario cerrar las conexiones en el código correspondiente al manejo de la excepción “NoHayVidaExtraterrestreException”, el que no era posible reproducirlo con un “Test de Prueba Unitario”, el desarrollador no podía “forzar” a que el programa se fuera por ese “camino”. El problema de “memory leaks”, era producto de una concatenación de String dentro del ciclo que recolectaba datos (millones) de áreas cubiertas por la exploración de las nebulosas. Solo fue necesario hacer uso de la clase StringBuilder en reemplazo de la concatenación de String. Ahora se recuerda con cariño al programador de ese código, quien hizo su practica (pasantia) cuando ni siquiera sabia programar.
El método de resolución de defectos en el software, descrito anteriormente (la historia) deja serias dudas con respecto a la efectividad del método, sin embargo no deja lugar a dudas del desastre en términos de eficiencia. El presidente de la compañía, no sonrío por mucho tiempo al enterarse del problema de boca de un astrónomo quien se quejo por el pésimo servicio que su compañía le prestaba. Peor fue cuando se entero del método empleado en la solución. El intento del Gerente de Desarrollo de tranquilizarlo (o conformarlo) contándole que estos errores eran comunes y conocidos en la industria, que de hecho estaban documentados en la CWE (398 y 404) no hizo mas que conseguir que el presidente le recomendara tener su curriculum vitae actualizado, quizás le seria útil, en el corto plazo.
La historia continua….
El Gerente de Desarrollo, sabia que tenia que hacer algo y en un momento de inspiración se le ocurrió una idea bárbara (ídem definición anterior). Implemento dentro del proceso de calidad (QA) la función de revisión de código (Code Review), después de 8 meses de búsqueda, consiguió contratar a 4 expertos en programación, con 10 años de experiencia en JEE, que representaron algo así como el 60% de presupuesto del departamento de Desarrollo. La calidad del software se elevo notablemente, así como también el tiempo necesario para tener un producto final. El equipo de Revisión de Código fue bautizado como “los cuello de botella” y su mala fama les llevo a ser los responsables del fracaso de la implementación de un método ágil de desarrollo de software. Con el paso del tiempo –y la presión- el equipo de Revisión de Código, empezó a bajar su efectividad y eficiencia, por consiguiente la calidad del software. Ya no era divertido encontrar errores, aseguraron dos de los miembros del equipo de Revisión de Código que renunciaron la compañía.
No era factible buscar otros expertos, no había tiempo ni ánimos para pedir presupuesto, seria necesario reconocer que la Revisión de Código, al final no fue una buena idea. Como la manzana de newton fue el “OWASP Top 10” que llego a sus manos, donde fácilmente aprendió que la solución no eran “Pruebas de Penetración” sus problemas iban mucho mas allá de la seguridad. El desafío estaba en automatizar el trabajo de quienes revisaban el código.
Fue así como el Gerente llego a las soluciones de Análisis Estático, que son una especie de compiladores sofisticados que ven mas allá de lo evidente, eso que los desarrolladores mas expertos en un mal día, no son capaces de ver, ni mucho menos prevenir. Un analizador estático hace que los desarrolladores construyan un mejor software, entregándoles información valiosa acerca de los defectos encontrados, eleva el nivel y hace eficiente el trabajo del equipo de QA. Todo el proceso de desarrollo (y por lo tanto toda la compañía) se ve beneficiado. No es una solución de alquimia, se trata de automatizar –y hacerlo a tiempo- la detección de defectos. Los desarrolladores no son muy creativos, los defectos que generan son siempre los mismos, las herramientas de análisis estático no descubren defectos, los buscan.
Al incorporar una solución de analizador estático al proceso de desarrollo, la compañía contaba con un sistema de detección temprana de defectos, ahora los defectos serán detectados en la etapa de desarrollo, incluso antes de QA. Estos últimos podrán seguir poniendo foco en el negocio, en las pruebas funcionales sin preocuparse de la cobertura sobre el código fuente de las pruebas, los analizadores estáticos lo hacen en un 100%. Ahora tendrán la certeza de estar probando un software de mejor calidad.
El uso del analizador estático, les permitió conocer que las fugas de memoria (Memory Leaks) y conexiones abandonadas (Resource Leaks) estaban presentes en mas programas de lo que ellos pensaban, la detección tardo un par de horas y meses de trabajo de varias personas como; Desarrolladores, Analistas de QA y Administradores de Bases de Datos y Servidores Aplicaciones. Las horas ahorradas eran fácilmente traducidas a dinero ahorrado. Los astrónomos felicitaban al presidente de la compañía y el Gerente de Desarrollo podía dejar en el olvido el actualizar su curriculum.
Por Juan Carlos Herrera
Software Security Advisor & Founder
Ushiro Security