domingo, octubre 19, 2008

TDD desde una perspectiva arquitectural

La semana pasada di una conferencia por teléfono para todos los arquitectos que trabajan para proyectos internos de IBM y que con planes de utilizar metodologías ágile y/o ya están utilizando. Fue una linda y desafiante experiencia debido a que había gente de muchas partes del mundo (USA, Francia, India, Sudamerica, etc), nunca había dado una charla técnica en inglés (sacando las presentaciones de arquitectura de la aplicación) y yo pongo un 4, creo que aprobé, pero tengo mucho que mejorar. Independientemente de esto, creo que lo más interesante que quiero comentar en el post es sobre las influencias que tiene TDD en lo arquitectural, esto es el resultado a una pequeña investigación que vengo haciendo para APIT sobre Arquitecturas y Metodologías Agiles. El contenido básicamente fue el siguiente.

Facts acerca de TDD
  • TDD se compone de, Unit Test, Test Automation, Test First y Enfoque iterativo con refactoring
  • TDD es una técnica de diseño y es utilizada por Desarrolladores (Código).
  • TDD incrementa la calidad en el código facilitando el cambio en el software
  • TDD reduce defectos y permite tener un testeo de regresion constante
  • El manejo de dependencias es la parte más dificil de TDD
Requerimientos no funcionales impactados por TDD
Como siempre digo, las decisiones arquitecturales habilitan los atributos de calidad, pero obviamente no siempre los garantizan, hay otros aspectos y decisiones que entran en juego y el arquitecto no siempre puede manejar. Pero inevitablemente, la Arquitectura es la principal responsable de garantizarlos, y como arquitectos debemos buscar las formas, y TDD es una de ellas, con lo cual considero que TDD permite lograr los siguientes atributos de calidad:
Maintainability: Siguiendo las guías de Feathers, primero haciendo fallar el test case y luego corregirlo, la mantenibilidad se vuelve un detalle, lo mismo pasa con lo simple que queda el código y con la no necesidad de perder tiempo en un debugger. No nos olvidemos del regression test aca.
Extensibility / Modifiability: Esto es básico, como excelente técnica de diseño, al tiempo de aplicarla la productividad aumenta y el código queda mucho mas simple.
Reliability: Tiene que ver con la robustez en lo que respecta a las reestructuraciones o cambios en la arquitectura, un codigo que se construyo utilizando TDD, difícilmente sea complicado de modificar a cambios inesperados
Geographic (including Localization): TDD es una excelente técnica de comunicación, para equipos distribuidos es fundamental, tener bien claro y definido cual es el comportamiento esperado, no se paga con mastercard
Time: Ya hablé de la Productividad que trae aparejada el Test First, aca hay un paper que habla de los estudios que aumenta la productividad, hasta que lo leí fue solo un feeling mio y personal, ahora se ve que está probado.

Decisiones Arquitectónicas para Soportar TDD
Ahora, como (re) diseñamos nuestra arquitectura para soportar el uso de TDD, bueno, lo encaré desde el punto de vista de "Tácticas y Principios de Diseño" y "Estilos Arquitectónicos y Diseño Estratégico":
Tácticas y Principios de Diseño
  • Separation of Concerns.
    Una correcta separación de módulos, permite un mejor manejo de la complejidad y también permite el reuso del lado de los Test Cases (que no es poco)
  • Separación de la interface de la implementación.
    Hace falta explicar esto? Bueno, principalmente es para el manejo de dependencias y el trabajo en paralelo

  • Design by Contract
    Dos técnicas complementarias en el bajo nivel, desde un punto de vista arquitectural, definir los pre/post conditions entre módulos es básico
  • Informacion hiding
    Previene cambios no deseados
  • Prevent Ripple Effects
    Con 8 tipos de dependencias entre módulos, nos ayuda a no tener dependencias ocultas entre módulos, esto es muy importante, muchas veces hay modulos que dependen en variables de contexto y está oculta, TDD ayuda a evitarlo.
Estilos Arquitectónicos y Diseño Estratégico
Mas allá de cosas específicas, hay estilos arquitectónicos que ayudan muchísimo al uso de TDD en aplicaciones empresariales, estos son algunos:
  • Inversion of Control/Dependency Injection
    Aca no hay nada que discutir, por excelencia permite permite el uso de TDD, sumado a esto la separación de interface de la implementación.
  • Hierarchical Layers
    Estilo super conocido, con un modelo sencillo de dependencias, permite el coverage de una layer solo mockeando una layer inferior. Obviamente este patrón tiene cosas malas aparejadas, como la dificultad por encontrar las abstracciones y la modificabilidad.
  • Domain Driven Design
    Un estilo muy interesante para dominios complejos, se lleva muy bien con el Dependency Injections y la Iteratividad.
  • Transaction Scripts
    Modelo sencillo, en donde se puede lograr una completa de cada servicios a testear.
Acá estuve hablando como 30 minutos, es un poco difícil plasmarlo en un post, pero obviamente es la parte más interesante de la charla (al menos para mi)

Quejas de otros profesionales para implementar TDD y como solucionarla
No siempre es fácil convencer el uso del TDD, hay muchas quejas que hay que afrontar, aca puse las que fui recolectando, en algún otro post voy a poner lo que dije verbalmente, así que por ahora se lo dejo a uds para que piensen :)
Project Managers
  • Toma mucho tiempo para escribir test y termina impactando en la productividad.
  • Me siento mal por dejar afuera del proyecto a Testers y gente de QA
Architects
  • No me importa TDD, es una técnica de bajo nivel para programadores
  • No es necesario to test drive el código, la arquitectura cubre todas las posibilidades
Application Developers
  • Toma mucho tiempo en correr los test cases
  • No es mi trabajo testear mi código
  • Pero compila!
  • A mi me pagan por escribir código, no para escribir tests
  • Las dependencias son difíciles de manejar y toman mucho tiempo
Esto es todo, espero que les guste y espero feedback! realmente quiero escribir un paper con esto

2 comentarios:

Pablo dijo...

Hola Gustavo, me gusta la forma de encarar el tema y espero ansioso para leer tu paper sobre el tema!

Dentro del feedback (y sin saber si ya lo estas incluyendo)... estaria bueno marcar la diferencia entre el unit testing y otros tipos de testing (component testing, integration testing o functional testing) ya que el hecho de usar TDD no indica que no podamos/debamos tener un continuous building corriendo integration/component testings y ademas tener un equipo de testing funcional 'tradicional' para testear otros aspectos.

Por otro lado, el tema de aplicar TDD no solo como técnica sino ademas hacer el switch en la cabeza para confiar en la nueva filosofia adpotada.

Saludos!
Pablo

Gustavo Andrés Brey dijo...

Pablo, como siempre, gracias por el feedback!
Con respecto al paper, estoy en tratativas para publicarlo en InfoQ, mi sitio favorito que me mantiene actualizado, ojalá logra algo con ellos :)
Buen punto con respecto a los otros testings, totalmente te acuerdo, un CI podría tener otros tipos de testings automáticamente corriendo también, y sería glorioso que abra y cierre defects/bugs :P pero quizá ahi ya deje de ser un CI y se comience a llar Continous Testing Server, o alo por el estilo ya que apunta a otra cosa, quizá ya exista.
Y TDD si, es completamente un cambio (para mejor en muchos casos) de filosofía y mentalidad de los desarrolladores, no hay lugar a duda, es un tema interesante de investigar tambien.

Saludos,