El software nunca fue perfecto y jamás lo será. ¿Pero esto nos da una licencia para crear basura? El ingrediente faltante es nuestra renuencia a cuantificar la calidad.

Boris Beizer (n. 1934), ingeniero de software y autor estadounidense.

Después de pandemias, avispones asesinos y conflictos raciales estallando del otro lado de la frontera, durante el mes de Junio nos volamos la barda con un sismo de magnitud 7.5 que sacudió el centro y sur de México, pero que afortunadamente, sólo resultó en un número pequeño de decesos e infraestructura dañada. Como dice el meme que está circulando en Internet: «2020 – Escrito por Stephen King y dirigido por Quentin Tarantino.»

Ahora que estamos regresando a la «nueva normalidad«, en el centro de desarrollo de software al que pertenezco estamos preparándonos para crecer durante los próximos meses, de tal forma que recuperemos el tiempo perdido debido al distanciamiento social del trimestre pasado. Entre varias iniciativas, la más importante consiste en cambiar nuestra estrategia de servicio, pasando de ser una fábrica de software que compite mediante precios bajos, a reinventarnos en un centro de excelencia en el que los ingenieros sean expertos en las tecnologías y productos que manejamos. Esto significa entre otras cosas, definir cuidadosamente los roles que tendremos de ahora en adelante, así como pensar en los roadmaps de entrenamiento de cada perfil.

Así, seguiremos teniendo los roles conocidos por todos: desarrolladores, analistas de negocio, arquitectos de soluciones e ingenieros de pruebas (también conocidos como testers), pero todos deben alcanzar un nivel de senior o semi-senior antes de que termine el Otoño. Para este post me enfocaré un poco en estos últimos: aquellos especialistas que pertenecen a la así denominada área de QA y testing, es decir, profesionales que saben realizar pruebas manuales y conocen herramientas de seguimiento de incidencias como Jira, pero que ya se están pasando a un esquema de automatización; en el que entienden y manejan herramientas como Selenium y Ranorex.

Pic: The Career Path of a Software Tester: An Infographic ~ Federico Toledo @ abstracta

Trayectoria profesional de un ingeniero de pruebas. Esto es lo que sucede en el área del ‘testing’: con tiempo y práctica, nos convertimos en mejores evaluadores y podemos aspirar a mejores puestos, salarios más altos, más responsabilidades, tareas más desafiantes y más capacitación. Siempre continuamos aprendiendo y, finalmente, nuestras capacidades se vuelven mayores de lo que exige nuestra posición. (Fuente: Federico Toledo @ abstracta)

Lo que causó un poco de sorpresa durante esta planeación preliminar de perfiles, es que prácticamente el 40% de los ingenieros van a ser QA/testers. Sobre todo, porque trabajamos bajo un esquema ágil, usando desarrollo basado en pruebas (Test-Driven Development – TDD), en el que supuestamente los mismos programadores están escribiendo sus propias pruebas, por lo que los testers ya no son necesarios.

Bueno sí, pero en realidad, no; en el desarrollo de software, siempre es necesario contar con un grupo independiente de ingenieros que no sufran del sesgo cognitivo que implica probar su propio código, pues es bien sabido que casi todos los desarrolladores prueban el happy path, y es muy raro aquél que realiza «destrucción creativa» sobre su propio código. Así es como me topé con el corto, pero interesante artículo mostrado a continuación, en el que el autor describe por qué incluso si nos adherimos completamente a las metodologías ágiles, es importante tener testers como parte del equipo:

Se suponía que el desarrollo basado en pruebas eliminaría la necesidad de pruebas independientes. Por desgracia, esto no es suficiente.

El desarrollo basado en pruebas (TDD) se ganó la reputación de hacer que el software sea más robusto. ¿Eso significa que podemos despedir a los testers? Spoiler: No.

El desarrollo basado en pruebas es un método para escribir software en pequeños fragmentos. Comenzamos con una prueba, luego escribimos código funcional para hacer que la prueba pase y finalmente refactorizamos el código para dejarlo limpio. La idea de TDD fue propuesta por Kent Beck a principios de la década de 1990, como parte de Extreme Programming, una metodología de desarrollo de software ágil.

A veces, TDD se resume en «Rojo, Verde, Refactoriza». Las interfaces de muchos frameworks de prueba, como JUnit (para Java) y NUnit (para .NET), muestran luces rojas cuando las pruebas fallan y luces verdes cuando pasan las pruebas. Sin embargo, hay otro paso a considerar. Debemos pensar en el comportamiento deseado y crear un pequeño fragmento de código, generalmente de unas cinco líneas, para implementarlo.

Según lo propuesto por Beck, en TDD nunca escribimos código funcional hasta que tenemos una prueba fallida. Sin embargo, se necesita práctica para aprender a escribir las pruebas primero (en lugar de después del hecho); los desarrolladores a menudo tienen problemas para cambiar su forma habitual de trabajo. Escribir las pruebas antes del código funcional simplemente se siente mal. Te acostumbras, aunque puede llevar meses; para entonces comienza a sentirse bien.

El mayor beneficio de TDD es que elimina el miedo a romper nuestro código. A medida que agregamos pruebas unitarias y código funcional, también creamos una biblioteca de pruebas de regresión que ejecutamos con frecuencia. Cuando agregamos una nueva función, corregimos un error o refactorizamos para limpiar el código, ejecutamos las pruebas nuevamente para asegurarnos que no se rompió nada. O al menos se confirma que no violamos ninguna de las pruebas que hemos escrito.

¿Cuál es la aportación de los testers?

Los gerentes de software a veces se ven tentados a eliminar o reducir los departamentos de control de calidad del software cuando los codificadores adoptan TDD, con el argumento de que los programadores también están escribiendo pruebas. Esa decisión generalmente es un error, porque los testers proporcionan valor más allá de las pruebas unitarias de los desarrolladores.

Las pruebas unitarias son solo uno de los tipos de pruebas necesarias para cubrir adecuadamente el código moderno. Los desarrolladores de TDD rara vez escriben pruebas de integración de extremo a extremo. Pueden evitar escribir pruebas unitarias que requieren una configuración significativa o que dependen de otros componentes de software, como una base de datos poblada.

Los testers dedicados tienen más probabilidades que los codificadores de tomarse el tiempo para realizar pruebas exploratorias (ad-hoc), las que pueden encontrar errores que no fueron imaginados durante el desarrollo del código. Los testers también llegan al producto con nuevos ojos en comparación con los codificadores que han estado inmersos en el software durante largas horas.

Además, los desarrolladores de software a menudo no están interesados ​​en configurar herramientas de integración continua/despliegue continuo (CI/CD) o en organizar las pruebas del equipo en una prueba de regresión completa. Los testers consideran que todo eso es parte del trabajo. Los desarrolladores no pueden participar en la implementación de shift-left testing más allá de TDD. Para estas pruebas, los testers pueden recopilar información, ayudar con la gestión de requisitos y ayudar a definir los criterios de aceptación, antes de completar una sola prueba o una línea de código funcional.

¿Qué errores encuentran los testers que TDD no logra encontrar?

La seguridad es un área de pruebas amplia e importante que normalmente no se aborda escribiendo pruebas unitarias. Los testers buscan fallas de seguridad con herramientas de prueba de vulnerabilidad automatizadas, evaluaciones de seguridad manuales, pruebas de penetración, auditorías de seguridad y revisiones de seguridad.

Es difícil para los desarrolladores escribir pruebas unitarias para probar las interfaces de usuario. En cambio, los testers utilizan herramientas de automatización específicas para los entornos de aplicaciones compatibles, como navegadores, aplicaciones de escritorio y aplicaciones móviles.

Los desarrolladores pueden tener dificultades con los errores que dependen del hardware, ya que la forma dominante de trabajar es que un codificador trabaje en una sola máquina. Los departamentos de control de calidad a menudo recopilan salas llenas de computadoras y dispositivos variados, así como imágenes de muchas versiones de sistemas operativos. Una forma alternativa de probar en muchos modelos de dispositivos diferentes es utilizar un servicio de pruebas de fuentes múltiples.

Si bien TDD puede en teoría detectar errores en casos extremos, se les llama «casos extremos» (edge cases) por una buena razón. Cuando un codificador diseña las pruebas para un punto de función, los casos extremos pueden pasar desapercibidos en el momento. Los testers tienen más probabilidades de encontrarlos que los codificadores que escribieron el software.

Del mismo modo, las fallas cruzadas a veces pueden escapar al escrutinio de las pruebas unitarias. Pueden surgir fácilmente cuando un programador no comprende la interfaz o las condiciones de entorno del módulo de otro programador. Los errores entre módulos a menudo se encuentran durante las pruebas de extremo a extremo y las pruebas ad-hoc.

En resumen, aunque hay mucho que decir sobre TDD como práctica de desarrollo, generalmente no proporciona una cobertura completa de pruebas sobre nuestro código. Para eso, todavía necesitamos testers.

Para quien escribe los casos de prueba, tiene sentido seguir las pautas establecidas. Estas pueden ayudar.

Martin Heller. Testers vs. TDD. (Functionize, 2020)

Así que, sí: nosotros dependemos de un gran número de ingenieros de pruebas que nos apoyan no sólo en la ejecución de éstas, sino también en la generación de reportes y dashboards con métricas, coordinación de equipos y planes de pruebas así como definición de mejores prácticas y establecimiento de iniciativas de mejora continua.

En fin, el mayor problema de la calidad es que el resultado de implementarla es prácticamente invisible para el cliente. Cuando la organización invierte en el desarrollo de software, todos los stakeholders pueden ver los resultados de inmediato: hay una pieza de software con la que pueden jugar, un código fuente para revisar o una base de datos para diagramar. Con las pruebas, internamente tenemos un plan y scripts que podemos ejecutar, pero el cliente no los considera como entregables, incluso si éste los usa para llevar el seguimiento de defectos. A los clientes no les importa si realizamos pruebas de automatización o pruebas de seguridad; ellos sólo quieren saber que el producto final funciona correctamente.

Sin embargo, teniendo en cuenta los muchos efectos negativos de una pieza de software defectuosa – desde perder la confianza del cliente hasta la posibilidad de una acción legal contra nosotros – es mejor mantenernos del lado seguro de las cosas. Y qué mejor que tener un grupo de personas capacitado y motivado que trabaje para alcanzar el anhelado estado de «cero defectos», logrando satisfacer las necesidades del cliente y atrayendo una cantidad considerable de ingresos a la empresa. Después de todo:

Cientos de metodologías han ido y venido; los paradigmas han cambiado, pero los requisitos son siempre los mismos: hazlo bueno y hazlo rápido.

— Anónimo.