miércoles, 25 de septiembre de 2019

Test Driven Development: ¡Además mejora el diseño!

Se puede escribir el código de las aplicaciones pensando que lo único importante es que se construya en el menor tiempo posible y con el menor coste. Esta forma de proceder, ha quedado patente durante los 70 años que se lleva escribiendo software, que lleva a aplicaciones que son difíciles de mantener, y el mantenimiento de las aplicaciones es, a menudo, una etapa de larga duración en el ciclo de vida de las aplicaciones.

Para que sea fácil arreglar los errores que surjan en las aplicaciones (webs, apps, microservicios, apis, etc.) es necesario que el software esté bien diseñado. Son muy peligrosos los códigos espagueti llamados así porque todo está enmarañado como en un plato de espaguetis. En estos casos los cambios de cualquier tipo son muy peligrosos porque son muy propensos a errores. Es difícil buscar errores o donde se hacen las cosas si se trata de modificar una funcionalidad. También es difícil de prever las consecuencias de modificar una parte de código, en cuanto a las consecuencias que esto tendrá en el resto del sistema.

Por todo esto la técnica de desarrollo Test Driven Development (TDD) puede venir a ayudar. TDD es una forma de desarrollo que por sus características mejora dos aspectos muy importantes del código: se tienen que construir y ejecutar constantemente las pruebas unitarias automatizadas y el diseño de los sistemas construidos mediante esta técnica tiende a ser "bueno".

Tener pruebas unitarias es bueno porque nos sirven de red de seguridad de nuestro código. Cuando cambiamos algo, podemos comprobar si las pruebas unitarias se siguen ejecutando con éxito. En caso contrario tenemos una alarma que detecta que algo en el cambio no ha ido bien.

Que el diseño sea "bueno" hace que los desarrolladores puedan comprender mejor el código y este pueda ser modificado con más versatilidad.

Existen numerosas aproximaciones para hacer buenos diseños en ingeniería del software. Hay recomendaciones generales y otras enfocadas a algún paradigma de programación en particular. Algunos consejos generales para un buen diseño son:
  • Poco acoplamiento y mucha cohesión. Dos principios fundamentales de la ingeniería del software
  • No hagas lo que no necesitas: You Ain't Gonna Need It (acrónimo YAGNI.
Para más información ver el artículo de Martin Fowler's disponible en http://martinfowler.com/bliki/Yagni.html.
  • Reutiliza el código Don't Repeat Yourself (Acrónimo DRY) 
  • Keep it simple, stupid. Keep it simple, stupid (Acrónimo KISS)
  • Algunos principios para la programación orientada a objetos son los principios SOLID. Solid es un acrónimo formado con las palabras: Single responsability, Open-Close, Liskov substitution, Interface segregation y Dependency inversion. 

Con el objetivo de demostrar que TDD es una técnica de programación que ayuda a obtener buenos diseños de código, Alex García y Viktor Farcic en su libro Test-Driven Java Development, presentan una Kata TDD basada en el juego Conecta4.

La Kata consiste en hacer dos desarrollos del mismo juego, uno sin seguir TDD y otro siguiendo esta técnica de programación. El código de ambos desarrollos se puede descargar en  https://bitbucket.org/vfarcic/tdd-java-ch05-design.git

Conecta 4 es un juego de 2 jugadores en el que se dispone de un tablero de 7 columnas por 6 filas. Los jugadores juegan por turnos introduciendo sus fichas por la parte de arriba de cada columna. Las fichas se amontonan en las columnas. Gana el jugador que consigue colocar 4 fichas de su color en línea, ya sea vertical, horizontal o diagonal. Para más datos sobre las reglas del juego https://es.wikipedia.org/wiki/Conecta_4

Analizando el código descargado de bitbucket de ambas versiones se aprecia que efectivamente el diseño es distinto. Ambas implementaciones se resuelven en una clase escrita en Java, pero los métodos difieren. Para ilustrar esto se muestran los dos figuras siguientes. Una muestra los métodos empleados en la Kata no TDD


La  otra muestra los métodos empleados en la Kata TDD

Análisis de las diferencias entre las Katas

En las figuras se muestra mediante diagrama de secuencia los métodos que tiene cada una de las clases. Las flechas a la derecha representan las llamadas entre métodos.
 
La kata TDD resuelve con 9 métodos frente a la no TDD que se resuelve con 6. Este hecho ya tiene un aroma de mejor diseño. ¿Por qué? Pues por qué esto indicar que cada método hace menos cosas y por lo tanto es más sencillo. Pero detallando más ¿Qué tiene el diseño de connect4TDD que le hace mejor que el de connect4?
  • La modularización de las funciones se ha hecho adecuadamente esto cumple el principio "single responsability". Los métodos tienen una única misión cuya funcionalidad está bien encapsulada. Por ejemplo, hay un método checkPositionToInsert() que se encarga de comprobar si hay espacio en la columna para una nueva ficha. En la versión que se hizo sin TDD este método no existía y por lo tanto esta responsabilidad estará incluida en algún método que además hará más cosas o sea tendrá más responsabilidades.
  • Los métodos que hacen menos cosas cumplen el consejo KISS-Mantén el código lo más sencillo posible. Al tener más métodos cada uno tendrá menos funcionalidades que abordar y será más sencillo.
  •  Cumple el consejo YAGNI- No lo pongas si no lo necesitas, al implementar el código tras implementar la prueba unitaria, solo se codifica lo estrictamente necesario para que la prueba se ejecute con éxito. No hay código superfluo.
  • En el conector de Connect4TDD se ha incluido un argumento tipo PrintStream para especificar cúal es el canal de salida. De esta forma si se quiere hacer uso de la clase para mostrar el tablero por un PrintStream distinto a System.out se puede hacer simplemente indicando el canal al construir el objeto de la clase Connect4TDD. Esto se puede entender cómo un desacoplamiento de Connect4TDD y el canal de salida. Sin ser exactamente inyección de dependencias, está relacionado con este principio.

Conclusiones 

Emplear la técnica TDD mejora el diseño de las aplicaciones y proporciona aplicaciones que se pueden probar de forma automatizada. 

En el canal DevOps es fundamental de disponer de pruebas automatizadas para optimizar el trabajo de los equipos de desarrollo y operaciones. Esta técnica pone pues una primera piedra para realizar mejorar que consiguen que las áreas de tecnologías de la información sean más productivas y por consiguiente más competitivas.


No hay comentarios:

Publicar un comentario