Category: Agile

Hacer Unit Test != Aplicar TDD

Cada nuevo proyecto involucra el tener que interactuar con nuevos grupos de trabajo, nuevas personas y nuevos retos, pero recientemente algo que me ha  llamado mucho la atención es el hecho de que varias personas dicen conocer acerca de ciertas metodologías de desarrollo de software, no es que yo me considere una eminencia en todas las materias, pero si cuando no tengo mucha idea sobre un tema, primero escucho y después investigo de que trata.

Volviendo al inicio (“bottom line”), en una reciente plática con un equipo de trabajo, se estaba discutiendo el tema de las pruebas unitarias y el cómo se van a emplear en el proyecto, algunos mencionaron que nunca las habían empleado, otros habían solo leído o escuchado sobre de ellas y otros decían que tenían amplia experiencia y que incluso habían aplicado TDD (Test-Driven Development)…interesante punto!

Cuando les pedía a los que “habían” empleado TDD comentarán sobre sus experiencias y utilidad, surgieron los siguientes puntos:

-          Comentaban que su tiempo de implementación alargaba en tiempo de desarrollo del proyecto.

-          Que se hacía complicado cumplir con las coberturas de código.

-          Al final terminaban haciendo muchas pruebas unitarias.

-          Que el IDE ya generaba automáticamente las pruebas y aplicaba el TDD…..?

Después de escuchar los comentarios no pude evitar comentar: hacer pruebas unitarias NO es aplicar TDD!, decirle a un Wizard que tome nuestros componente y automáticamente genere las pruebas unitarias NO es TDD!. Muchas veces no se logran comprender los verdaderos beneficios (o desventajas) de aplicar tal o cual práctica ó nos mal acostumbramos al flujo de trabajo que sigue cierta herramienta y creemos que así es como esta se aplica (todo gracias a la mercadotecnia!).

TDD es una práctica que se encuentra enfocada en aplicar dos principios básicos: Escribir primero las pruebas unitarias  y Refactoring de código. Para la definición de las pruebas unitarias se requiere tener claramente definidos los requerimientos (punto importante!), y una vez que se tengan claros aplicar los siguientes puntos:

a)      Tomar un requerimiento (con su respectivo caso de uso) que sea factible de iniciar su implementación o que sea más representativo.

b)      Definir la prueba unitaria con un nombre que describe el requerimiento.

Ejemplo:  IniciarSesiónConTokenDeSeguridadTest().

c)       Verificar que la prueba falla, se supone que en un principio esta se encuentra vacía y no tiene código.

d)      Implementar la prueba unitaria, es decir empezar a codificar a fin de realizar la implementación que cumpla con el propósito de la prueba unitaria.

e)      Ejecutar la prueba unitaria y verificar que funcione.

f)       Aplicar refactoring del código a fin de eliminar redundancias y reducir la implementación.

g)      Opcionalmente detectar posibles comportamientos que no se encontraban claramente especificados en el requerimiento implementado.

Revisando los puntos anteriores, el uso de este tipo de prácticas permite reducir la cantidad de errores y principalmente, permite al desarrollador confiar en su código al momento de la implementación de las pruebas unitarias, además de que las pruebas permiten mostrar el avance del trabajo y poder  demostrar escenarios de comportamiento que nuestros usuarios puedan revisar de forma simple.

Como toda práctica tiene sus ventajas y desventajas, por lo que su uso debe de estar condicionado a la experiencia de quienes lo van a implementar y se encuentren a gusto con trabajar de este modo. En mi caso lo he aplicado y me ha funcionado bastante bien, pero como siempre en gustos (y prácticas) se rompen géneros!

¿Qué valor aporta mi trabajo?

Durante la semana pasada el tema recurrente con el que me he visto involucrado es: ¿En verdad lo que estoy desarrollando genera algún valor?, ¿Cuánto tiempo va ser útil lo que se entregue del proyecto?

Lo anterior son una serie de preguntas que en la mayoría de los casos, toman relevancia en los momentos finales del proyecto,  en la entrega del resultado o más aun cuando nuestro cliente dice: “Esto que están entregando no es lo que esperábamos”, clásico pero muy cierto y recurrente.  

Casi siempre se tienda a caer en ambigüedades como querer emplear tecnologías “tan innovadoras” y “tan de moda” llenas de términos “rimbombantes” con tal de impresionar al cliente, es decir un típico escenario de proyecto  “buzzword compliance”: “Si implementamos SOA 2.0 vamos a apuntalar a los equipos de trabajo y capitalizaremos en valor de la empresa”, “Deberíamos subir nuestros servicios a la nube para así migrar todas las aplicaciones para que sean RIA al 100% y sean compatibles con Web 2.0“.

Otro escenario común es cuando en un proyecto nos asignan una pieza “compleja” un: “Generador  de notificaciones asíncronas mediante scheduler para ambiente mutithreading”, el cual debe de finalizarse el 2500 horas, donde dicha pieza fue definida en la etapa de arquitectura del proyecto por el “master architect” de soporte a pre-venta. Después de leer la especificación uno le indica al “manager”: Oye pero el requerimiento indica que el programa solo debe de mandar un correo al administrador cuando llegue un nuevo registro en la base de datos, que no basta con definir un job y ahorrarnos ese tiempo?….les parece familiar? o como decimos por acá, “para que tanto brinco estando el suelo tan parejo”.

Existen aspectos “primordiales”, antes de diseñar o codificar una pieza de software que es importante reflexionar:

a)      ¿Cuál es la finalidad del funcionamiento de esta pieza y quienes la van a utilizar?

b)      ¿Es necesario esta pieza dentro del “todo” del proyecto?

c)       ¿Están definidos y son claros los contratos de los componentes?

d)      ¿Es necesaria TODA la funcionalidad que estoy pensando implementar?

De tal forma que cuando se entregue nuestra pieza esta permita ser medida en función de los requerimientos e integración con los demás componentes, así como la funcionalidad comprendida sea única y estrictamente necesaria, recordar el YAGNI,  y de paso ahorrar tiempo de corregir nuestros errores, perdón mejor dicho “refactoring del código para mejorar performance” suena mejor.

En resumen es importante siempre entregar un resultado que al final genere un “valor” y que cumpla con las expectativas de nuestros usuarios o clientes finales, que los haga sentirse conformes con su inversión y lo consideren como algo “valioso” y “útil” o simplemente “vale la pena su costo”, es importante tener en cuenta que en términos de software es difícil cuantificar su valor.

.Net Unit Test: Realizar pruebas unitarias de clases internas

En algunos escenarios de implementación de .Net se hace uso de clases de tipo Internal, es decir clases que solo pueden ser accedidas por miembros del mismo ensamblado, por lo que al momento de definir las pruebas unitarias de nuestras clases, estas no pueden acceder a la definición de las clases internas debido a sus restricciones. Para solucionarlo se debe agregar el atributo InternalsVisibleTo en el archivo AssemblyInfo.cs del proyecto, de la siguiente forma:

//Se agrega el atributo en AssemblyInfo.cs
[assembly: InternalsVisibleTo("MyProjectTest")]

Para el caso en que el ensamblado se encuentre firmado, se debe de obtener la clave pública del archivo .snk con el que se realizó la firma, para obtener la clave se ejecuta la siguiente instrucción desde línea de comandos:

sn -tp myKeyFile.snk

en donde el resultado del comando pueder ser algo similar a:

Public key is

0021000004800000920000000602000000240000525341310004000001000100cfb8bc23b86a08
e70d021dd53d3b0293e716e71015870bdcc58a0231a4228618851a83e06077f5a44f42beb2baf3
56ad2d345521a96b0081ed0f25f9227523e3625eda524efe1cf2e1e5e41f3693a76ec52347684b
8129a4bb2d5fc49681adf33da0eecc4f81f011af4539d12abe1b4e760b5ce32d766db1012d4402
8381f0b7

Por último se agrega la información de la clave pública a la etiqueta InternalsVisibleTo, de la siguiente forma:

[assembly: InternalsVisibleTo("MyProjectTest, PublicKey =0021000004800000920000000602000000240000525341310004000001000100cfb8bc23b86a08
e70d021dd53d3b0293e716e71015870bdcc58a0231a4228618851a83e06077f5a44f42beb2baf3
56ad2d345521a96b0081ed0f25f9227523e3625eda524efe1cf2e1e5e41f3693a76ec52347684b
8129a4bb2d5fc49681adf33da0eecc4f81f011af4539d12abe1b4e760b5ce32d766db1012d4402
8381f0b7")]

Una vez finalido lo anterior ya se podrá realizar referencias a las clases internas desde el proyecto de pruebas definido en el atributo InternalsVisibleTo, bastante útil este atributo en mi caso me ha sacado de bastantes apuros.

Git on Windows

Reciente he empezado a emplear GIT como herramienta personal de control de versión en MacOSX, ya que considero que una de las buenas prácticas para realizar nuestro trabajo y aquellos proyectos de tipo personal, es siempre tratar de emplear una herramienta de Control de Versiones (nunca se sabe cuando el gato se comerá nuestro código).

Platicando con otros colegas sobre los diferentes herramientas de control de versiones  y GIT,  les intereso mucho el tema, hasta que  surgieron las siguientes preguntas : ¿Porqué cambiar Subversion?, ¿ Pero …funciona en MS Windows?…. interesante!

Primero mi intención no es decir cual es mejor que la otra, las dos son opciones bastante útiles y han demostrado su eficacia, así que más que basarse en recomendaciones, así como las metodologías, es cuestión de gustos!

Pasando a la segunda pregunta, en mis primeros días con Git recuerdo haber leído sobre algunos esfuerzos para emplearlo en SO Windows, y unos de los proyectos que más avance tiene en ese tema es msysgit, el cual permite proporcionar el ambiente necesario para la ejecución en MS Windows.

Por default Git proporciona una herramienta visual llamada Git GUI, pero es una versión bastante limitada y en ocasiones no “muy amigable de usar” y en ocasiones usar Git desde línea de comandos puede ser todo una “ciencia oscura”, por lo cual otra herramienta útil para cuestiones de integración con el SO y consulta visual es TortoiseGit, un versión basada en la excelente herramienta para Subversion TortoiseSVN.

Incluso he realizado pruebas de instalación y uso de las herramientas en Windows 7 y funcionan a la perfección, recomiendo a quienes les interese dar un “test-drive” con Git, una vez que lo conozcan seguro les agradará o al menos con el fin de conocerlo y criticarlo.

Applying agile methodologies: Software art

En esto días me he encontrado leyendo algunos artículos (Post1,Post2) de Marco Dorantes, en donde describe el desarrollo de software y las implicaciones de la adopción de metodologías agiles en los proyectos en los cuales trabajamos día con día y que al final terminan siendo todo MENOS AGILES!.

Desde mi perspectiva y experiencia, el éxito o fracaso de la adopción de metodologías agiles depende en gran grado de las cuestiones culturales o  ”costumbres, manías” que hayamos fomentado durante nuestra vida laboral y dado el “proceso de desarrollo de software“, que más que un proceso es un “arte“, a pesar de que mucho insistan en cuadrarlo con un proceso de producción o manufactura. Entonces ¿cómo alinear el proceso con una cuestión artística?  Existen variedad de metodologías y parte de sus mejores resultados en que los integrantes del equipo, implicados en el desarrollo (los “cerditos” como define Ken Schwaber),  partan de criterios comunes de confianza y compromiso de forma que todos tengan conciencia de que el adoptar la metodología A o B dependerá “solo de ellos” el éxito al final del camino, es como algo parecido en el futbol  independientemente de la estrategia de juego (4-4-2, 3-5-2), al final quienes ganan o pierden son los jugadores!.

Ahora en cuestiones de resultados, en mi caso ha funcionando perfectamente la combinación del uso de SCRUM, como proceso de control de la evolución de software y TDD como mecanismo de desarrollo y refactoring, al final resulta bastante ágil y permite mostrar resultados inmediatos así como reportar avance. Pero comento mucho depende de los gustos y afinidades, al final solo nuestro “arte” prevalecerá!.

WordPress Themes