Archivo de la etiqueta: TDD

Resumen de la Mesa redonda de TDD con Cartuja .NET

Ayer desde Cartuja .Net hicimos una mesa redonda sobre TDD y la conversación fue muy, pero que muy ilustradora sobre todo para mí.

Aquí mi resumen:

Tras hablar sobre las últimas novedades que habían aparecido en la comunidad .NET tras las presentaciones de #vsconnect y conseguir centrarnos, comenzamos con una explicación sobre qué es TDD muy corta, apenas 30 segundos:

"TDD consiste en que cuando vamos a escribir código, hacer primero un test que falle para el código que queremos escribir, luego el mínimo código que hace que el test se ponga verde, y refactorizar el código que hemos escrito"

Seguimos con la duda que yo tengo sobre ese ciclo, y es que, como ya comenté en otro post, el ciclo es incompleto, falta una primera fase de "pensar" antes incluso de escribir ese primer test.

Es decir, tomar muchas veces papel y lápiz, y dibujar la "arquitectura" que creemos debe ser. Una vez que tenemos separadas las responsabilidades que el sistema debe tener, cogemos una de esas clases y podemos empezar a aplicar TDD sobre esa clase.

Suele ocurrir que al escribir ese test y escribir el código se encuentran dependencias que antes no se habían tenido en cuenta. Es decir, responsabilidades ocultas y suele generar en otra clase que tendremos que mockear para poder seguir avanzando en el ciclo de TDD y avanzando en el nuestro trabajo.

Y aquí llego la primera disputa sobre el concepto de que "la arquitectura emerge". Tras un rato de dialogo sobre eso, saqué la conclusión de que esa arquitectura que emerge no es la arquitectura del sistema completo, sino la arquitectura del contexto en el que está centrado ese test.

Mi conclusión particular sobre este punto, es que aplicando TDD nos obligamos a pensar en responsabilidades, nos obligamos a seguir el principio de una única responsabilidad y esto, paso a paso, test a test, nos ayuda a averiguar si aquella arquitectura que teníamos en la cabeza, que dibujamos con papel y lápiz en un primer momento es adecuada o no. Como corolario podemos decir que si nos resulta difícil seguir avanzando en ciclos cortos de test-code-refactor, hay que replantearse esa arquitectura ya que parece que esa elección no es adecuada, y eso es bueno, ya que al menos hemos encontrado una forma de no hacerlo.

Tras unas cuantas experiencias que compartimos, buenas y malas, continuamos con la conversación sobre las bonanzas del testing, integración continua, TFS, Team City, programación defensiva, y un largo etcétera. Todos estamos de acuerdo sobre las ventajas, sabemos que es bueno hacer test. Hasta que alguien nos hizo caer en la cuenta de que desde hacía un buen rato no estábamos hablando sobre TDD sino de testing. Así que recondujimos la conversación con el tema de la práctica y la maestría.

Obviamente no es lo mismo empezar a aplicar TDD que llevar tiempo aplicándola. La famosa curva de aprendizaje es en realidad así:

Tenemos un nivel de productividad (verde) y cuando empezamos hay una bajada de productividad importante y empezamos el camino de la práctica hasta que volvemos a alcanzar el mismo nivel de productividad que teníamos antes. En realidad esto pasa con todas las tecnologías y técnicas que aprendemos a lo largo de nuestra carrera, y es en esa parte de la curva cuando optamos por abandonar o seguir con el camino que hemos iniciado.

El problema con TDD es que para mentes como yo, ese proceso es duro y es muy fácil desistir y abandonar, el lado oscuro siempre nos tienta, es más fácil, más rápido y más seductor no seguir por el camino de TDD.

Continuamos con la pregunta de ¿hay que hacer TDD siempre? En el camino del aprendizaje, nos vamos dando cuenta de que es descabellado hacer TDD en todo. En ese camino se aprende a ser pragmático y a ajustarse a las necesidades del proyecto y del momento en el que estamos trabajando. Pero sobre todo, se aprende en ese camino a diseñar. TDD no es sólo una herramienta de testing, es mucho más, es una herramienta de diseño. En el camino de maestría de TDD se aprende sobre todo a diseñar, y con el tiempo se consigue empezar a acertar en esa primera "arquitectura" que pintamos en un papel. Normalmente los problemas que resolvemos suelen ser parecidos, y vamos mejorando esa arquitectura que dibujamos al principio.

Como última ventaja que le veo a TDD es que cuando no tenemos claro cómo solucionar un problema, TDD ayuda a encontrar una solución, empezando a escribir ese primer test de aquello que queremos programar pero no tenemos claro cómo hacerlo. Conseguimos tener un diseño desacoplado, abierto a la extensión y cerrado a la modificación, etc.… De esta forma cuando averiguamos qué es lo que hay que hacer nos es más sencillo modificar esa arquitectura.

Después de todas las experiencias que vimos, es curioso que siempre los que suelen ir a este tipo de eventos, y tu que estás leyendo esto, son siempre profesionales que buscan formas de hacer mejor su trabajo.

Quiero dejaros algunos nombres y libros que surgieron en la conversación, se que me falta alguno, así que si te acuerdas déjamelo en los comentarios:

Muchas gracias a Cartuja .NET por reunir a todos los que allí nos juntamos, ha sido una tarde muy agradable y tengo la sensación de que todos nos quedamos con ganas de más.

Estoy deseando ver la visión de cada uno que asistió, bien en los comentarios de este humilde blog o con referencias a los blogs de los que allí nos juntamos. No quiero señalar http://javiersuarezruiz.wordpress.com/, http://www.variablenotfound.com, http://cartujadotnet.es/

Se me olvidó comentar que mañana es el de Global CodeRetreat http://globalday.coderetreat.org/

En Madrid lo tienen preparado: http://madridcoderetreat.wordpress.com/

Si podéis verlo seguro que os gustará.

[Mindcamp 2014] How I met testing

En Mayo me invitaron a la Mindcamp 2014, Un evento que se viene celebrando de año en año.

Quería compartir la charla que di sobre cómo conocí el mundo del testing y cómo desde entonces duermo mejor.

Espero que os guste y no dejéis de ver los videos de las demás charlas de la Mindcamp, hay auténticas joyas

El enésimo post sobre el Singleton (UPDATE 1)

La cosa es que el Singleton hace dos cosas:

- Se asegura de que sólo haya una instancia del objeto.

- SomeStuff()

El problema de hacer dos cosas es que viola la S de los principios Solid: Single Responisability Principle. Y esto hace que no sea fácilmente testeable.

Cuando quiero hacer que sea testeable quito el Singleton y lo sustituyo por una factoría, una clase estática y una clase que hace la funcionalidad de SomeStuff.

Aquí tenéis un ejemplo simple:

public static class Singletons
 {
     private static Factoria fact = new Factoria();

     public static void HazLoTuyo()
     {
         fact.GetUnicaInstancia().DoStuff();
     }
 }

 public class Factoria
 {
     private Clase unicaInstancia;

     public Factoria()
     {
         unicaInstancia = new Clase();
     }

     public Clase GetUnicaInstancia()
     {
         return this.unicaInstancia;
     }
 }

 public class Clase
 {
     public Clase()
     {
     }

     public void DoStuff() { }
 }

De esta manera puedo testear la clase Clase sin preocuparme de que sólo hay una instancia de ella en el sistema.

Es por esto que me asalta la duda, ¿no será el Singleton un antipatron?

¿Cómo lo veis vosotros?

[Update 1]

Gracias a los comentarios voy a ir actualizando el post con algunas conclusiones y dudas que se me plantean.

Resumiendo un poco los comentarios, cuando sólo queremos una instancia de nuestra clase Clase (definida más arriba) suele ser buena idea usar un inyector de dependencias y registrar nuestra clase para que el inyector nos devuelva siempre la misma instancia.

De esta manera "invertimos el control" de la instanciación de nuestra clase, y podemos testearla de manera aislada.

¿Pero que pasa si no queremos meter un inyector de dependencias por el motivo que sea?

Podríamos meter una clase parecida a esta:

 public class ClaseFachada
 {
     private static Clase clase = new Clase();

     public static void DoStuff()
     {
         clase.DoStuff();
     }
 }

De esta manera podemos usarla en nuestro código de esta forma:

ClaseFachada.DoStuff();

Como si fuese un Singleton, pero evitando el típico Clase.Instance.DoStuff(). La cosa es que si estamos desarrollando una librería y queremos que nuestra librería se use así.

¿Os parece adecuado? ¿Cómo lo mejoraríais?

Knock, knock … Buenos días developer, venimos a hablarle de TDD

Aviso: Este es un post que te va a vender TDD.

En otras publicaciones han resumido las bonanzas de TDD, como el libro de @carlosble "Diseño ágil con TDD". Os lo recomiendo desde ya.

Pero he encontrado una presentación de Francesco Carucci, antiguo desarrollador de Crytek que actualmente trabaja en Apple, en la que muestra/vende TDD desde el punto de vista del desarrollo de video juegos.

Me ha parecido muy bien estructurada y cómo vende TDD, así que lo pongo aquí para escribirlo, compartirlo y de manera egoísta, como un ejercicio para que me ayude a no olvidar algunas cosas.

La estructura consiste en poner las diferentes razones y excusas que solemos dar para no escribir tests o por qué no hacer TDD y las respuestas que deberíamos grabarnos como mantras. Así que allá vamos:

No hago Tests por que ...

... el tiempo que gasto en escribir test es tiempo que podía estar escribiendo código.

  • Al final gastamos más tiempo en debugear y mantener código que escribiéndolo.
  • Si escribimos primero los test y el código que los pasa, el código que los pasa es código de producción. La consecuencia es que tardamos menos tiempo en tener código que funciona, esto es: código de producción.
  • La modificación del código es más confiable. Cuando modificamos código lo hacemos "más tranquilos" ya que sabemos que vamos a romper pocas cosas, y si se rompen, nos vamos a dar cuenta rápido.
  • Se evitan bugs de regresión. Al detectar un bug, escribimos un test que lo reproduzca y ese bug no volverá a aparecer.
  • Se detectan antes los bugs, como ya vimos en el post anterior

... los test no lo pueden probar todo

  • Un test es mejor que ninguno.
  • El código legacy o de terceros no hay que testearlo a menos que tengamos que modificarlo.
  • Roma no se construyó en un día, pero se construyó (y conquisto el mundo conocido)

... este código es temporal y lo cambiaré después, no necesito testearlo

  • Todo el código se modifica tarde o temprano. Hacer código que sea fácil de cambiar es la razón fundamental de TDD: elimina la sobre-ingeniería (KISS, Keep It Simple, Stupid!)
  • Los requisitos cambian: entonces hay que modificar los tests afectados y el código de producción. Pero como está testeado unitariamente, el código está más desacoplado, es más fácil de modificar y los cambios tendrán menos efectos secundarios.

En el mundo del desarrollo de juegos

El desarrollo de juegos es diferente: los test automatizados pueden no funcionar.

  • En general el desarrollo de juegos es totalmente diferente …
  • … pero escribir código es lo mismo, incluso más simple.
  • El código de un juego es más algoritmia y matemáticas, eso es incluso más fácil de testear que un proceso de negocio.
  • Un código de sobresaliente es lo mismo tanto en un juego como en una web.
  • El código de un juego cambia a menudo: más cambios es un motivo más para tener test que comprueben que no se ha roto nada.

Los juegos son para divertirse, un test no puede comprobar que un juego sea divertido.

  • Pero sí puedes capturar bugs, y menos tiempo debugando errores significa más tiempo para implementar la parte divertida.
  • Crear un test para un bug te asegura que ese bug no volverá a aparecer (El 30% de las correcciones de bugs crean nuevos bugs debido a efectos colaterales)

Esto es un juego AAA, es muy arriesgado hacer test automatizados sobre él.

  • Los juegos AAA son muy complejos, muy tecnológicos y muy divertidos. Para conseguir un juego AAA, se deben usar herramientas adecuadas, y los test automatizados son una de esas herramientas.
  • Lo arriesgado es NO hacer test en un juego AAA

¿Cuándo TDD no es apropiado?

  • Prototipos. Mientras buscamos/probamos posibles soluciones a un problema.
    • La solución final SÍ debe estar hecha con TDD.
  • En el código de wrappers de librerías existentes.
  • En la capa GUI, eso no es testing unitario, es testing de integración.
  • En código de bajo nivel, el que está muy cerca del hardware

Objetivo: Producir más funcionalidades en menos tiempo.

No perdamos de vista el objetivo, producir lo antes posible código que vaya a producción, esto es código que funciona, libre de bugs y mantenible

¿Y tu porqué no haces Test o TDD?

TDD: Mentirosos el ciclo no es Red – Green -Refactor

Nos han engañado estos del TDD, son unos malditos mentirosos, el verdadero ciclo es:

Think - Red - Green - Refactor

Y no te lo dicen, aunque para algunos iluminados sea algo implícito, el primer paso es pensar (Think) el algoritmo/lógica que quieres implementar, y es ese primer paso el que siempre me saltaba. Soy una persona visceral y suelo actuar por impulsos, y a la hora de programar ... pues me pasa un poco que me dejo llevar.

Por eso voy a desglosaros cómo veo yo el ciclo de TDD:

Think

  1. Piensa y reflexiona la lógica que tienes que implementar.
  2. Identifica las diferentes responsabilidades que hay
  3. Por cada responsabilidad habrá una clase. (¡Quieto!, aparta las manos del teclado, no es el momento de escribir las clases. Dibújalas en un PDA (Papel de Apuntar))
  4. Elige un buen nombre para cada una de ellas. Nombres descriptivos, limpios, claros, afeitaditos. Evita las terminaciones de LoQueSeaObject, LoQueSeaManajer, etc... Si no dice nada sobre la funcionalidad de la clase quítalo. Si aún así estás tentado a ponerlo, es que esa clase hace más de una cosa (Principio KISS), así que vuelve al paso 1.
  5. En el PDA dibuja las relaciones entre las diferentes clases

Foreach (responsabilidad in PDA)

  • Crea una clase de Test por cada una (ejemplo: responsabilidad1Test)
  • Y ahora sí, en cada clase de test haz todos los Red - Green - Refactor necesarios para probar la funcionalidad que la clase testeada debe tener.

Mis conclusiones

Escribe tu código como si un asesino esquizofrénico que tiene tu dirección fuese a mantenerlo

Esta es una frase muy conocida en el mundo Agile, no recuerdo si era exactamente así, pero lo que viene a resumir es que al final pasamos más tiempo leyendo, debugeando y manteniendo código que escribiéndolo. Por eso es muy importante pensar muy bien el nombre que les vamos a dar a las clases, variables, métodos, propiedades, etc. En definitiva haz lo que sea necesario para que tu código sea legible.

La formación no es importante, es IMPRESCINDIBLE

Aprender la teoría está bien, pero si viene acompañada de una práctica con alguien que te guíe te va a ayudar mucho más, sí, es algo obvio, pero que no se suele hacer.

Las herramientas de refactoring son nuestras amigas

Sólo hablo del "generate method" y "generate class" de Visual Studio, no me han hecho falta más. Cuando empiezas a escribir el test, y haciendo clic derecho y buscar esa opción en el desplegable nos permite crear rápidamente las clases y métodos que nos vayan haciendo falta, pero no te olvides del asesino esquizofrénico.

El Nirvana del TDD

El Nirvana del TDD es no tener que debugear para detectar un bug, sólo crear un test que lo reproduzca y corregirlo. Si consigues llegar a este punto ya eres un TDD Master.

¿Cómo ampliarías este post?

Ejecutar Test unitarios en el modo MTA (Multiple Threaded Apartment)

¿Trabajas con TDD? ¿Haces test unitarios con MSTests? ¿Tienes una máquina con varias cpus?.

Sip, parece un mundo ideal sobre todo por lo de hacer TDD, ;). Sin embargo como los TDDadores son como las meigas ... (existir no existen, pero haberlas haylas). Seguramente tendrán máquinas multicore y posiblemente haran test con Visual Studio 2010 y MSTests.

En este post veremos cómo podemos ejecutar nuestros test unitarios en el modo MTA (Multiple Threaded Apartment), lo que se conoce como hacer que se ejecuten en paralelo. Y es que el modo por defecto de su ejecución es el STA (Single threaded apartment). Sigue leyendo