lunes, 10 de mayo de 2010

Patterns de tests de unidad 1: ¿Como deberían ser nuestros tests de unidad?

¿Cuales son las características deseables en los tests de unidad de un proyecto? Esta es una pregunta difícil de responder porque el conjunto de tests de unidad de un proyecto es muchas cosas a la vez.

Por un lado, funcionan como una herramienta de desarrollo: la ejecutamos y nos informa de errores en nuestro código. En cierta forma son una extensión del compilador y así como este nos informa errores de sintaxis los tests nos informan errores de lógica.
Cuando vemos los tests como una herramienta de desarrollo es fácil ver que ciertas características son deseables: los tests deben ejecutarse rápido, deben cubrir la mayor parte posible del sistema y deben ser confiables (es decir, no deben producir falsos positivos).

Pero, por otro lado, a diferencia del compilador los tests no son una herramienta desarrollada por terceros. Nosotros mismos somos los encargados de desarrollarla y sobre todo de mantenerla. Si, la segunda caracteristica deseable es la mantenibilidad! Por lo tanto todas las buenas prácticas que utilizamos en el desarrollo de software de producción aplican en el desarrollo de tests de unidad. Hay que evitar la duplicación, asegurarnos de que nuestro código sea fácil de leer, de testear y tratar de minimizar la cantidad de lugares en que hacemos llamadas al código que estamos testeando.
Si no nos preocupamos por la calidad del código de nuestros tests es muy fácil que terminemos en la situación de que la mayor parte del costo de hacer un cambio en nuestro sistema sean las modificaciones a los test de unidad.

Finalmente, los tests de unidad tienen una tercera característica deseable que es la de servir como documentación. Muchas veces la forma más fácil y segura (porque está garantizado que los tests están sincronizados con el código) de ver que hace una clase es leer los tests de unidad correspondientes. Sin embargo, para que esto sea posible los tests de unidad tienen que estar escritos de una manera que haga que sea sencillo entender lo que dichos tests esperan de la clase que están verificando.

En proximos posts vamos a contar las buenas prácticas y patterns que permiten lograr estas características deseables de los tests de unidad.

miércoles, 5 de mayo de 2010

Desconfíen de los parámetros booleanos

Este post es el primero de una serie que vamos a hacer con consejos sobre calidad del código y en particular sobre mantenibilidad (algo que consideramos muy importante).

Uno de las primeros consejos de legibilidad de código que uno recibe cuando empieza a programar profesionalmente es que no se deben usar "números mágicos" y que todos los valores literales con significado especial para nuestro programa deben ser reemplazados por constantes. Esto se hace para protegernos de posibles cambios pero sobre todo para mejorar la legibilidad de nuestro código (después de todo se suele usar la constante PI, cuyo valor es dificil que cambie).

Sin embargo, este criterio no se sigue en el caso de parámetros booleanos y entonces es común ver métodos con definiciones como esta:

public FileWriter(File file, boolean append) {
 
}
 

Este es un constructor que es parte de la biblioteca standard de Java. Si se mira el código del lado del método la cosa no parece tan fea. Si uno elige un buen nombre para el parámetro el código queda claro:

public FileWriter(File file, boolean append) {
    if( ! append) {
            //trunca el archivo
    }
}
Sin embargo, si uno mira el código en la llamada al método el resultado es bastante críptico:
FileWriter writer = new FileWriter(file,true);
¿Qué significa ese true? ¿Significa "truncá el archivo" o significa "hace append al archivo"?. Esto depende del nombre que le hayamos puesto a la variable y la única manera de saberlo es ir a la definición del método y leer el código. Es exactamente lo mismo que nos pasa cuando nos encontramos un "número mágico".
Es interesante ver como este efecto no se da en todos los lenguajes. En aquellos que tienen la posibilidad de parámetros con nombre como Smalltalk (o permiten simularlos como Ruby) el código de la llamada es completamente legible:
writer = FileWriter.new(file,:append => true);
¿Como podemos hacer para solucionar este problema? Lo primero que se nos ocurre es hacer lo mismo que normalmente hacemos con los literales de otros tipos, es decir reemplazarlos por constantes con nombres significativos:
public enum {
  Append,
  Truncate
} CreationMode;
 
public FileWriter(File file, CreationMode creationMode) {
    if(creationMode == CreationMode.Truncate) {
            //trunca el archivo
    }
}
 
FileWriter writer = new FileWriter(file,CreationMode.Append);

Sin embargo, antes de tomar este camino es bueno revisar si la existencia de este parámetro booleano no nos está alertando sobre un problema más de fondo. Básicamente este tipo parámetros permite al código llamador controlar el flujo de ejecución del método llamado, algo sospechoso no ya desde el punto de vista de la programación orientada a objetos si no desde la óptica de la programación estructurada. Por lo tanto es probable que si revisamos el código del método nos encontremos con que en realidad la mejor solución es tener dos métodos cada uno con uno de los comportamientos que originalmente ocurrían al pasar el flag en true o false.

Como normalmente ocurre con estos consejos, esto no significa que no haya que usar jamás parámetros booleanos, si no que es bueno antes de usarlos considerar otras opciones. Además tenemos que tener en cuenta que cuando escribimos un método no solo importa la calidad del código del método que escribimos si no que su interfaz no lleve a los usuarios de dicho método a escribir mal código (sobre todo sabiendo que muchas veces los usuarios vamos a ser nosotros mismos o quizás un psicopata violento que sabe donde vivimos)

lunes, 3 de mayo de 2010

Mantenibilidad vs Reusabilidad

Ya hace bastante tiempo que vengo haciendo entrevistas para contratar Programadores. Aparte del hecho de que es una actividad que depara no pocas sorpresas (ver sino: the-nonprogramming-programmer), y a la que debemos evidentemente darle alguna vuelta de tuerca, como hacer pair programming con el candidato, llenar de brea a los mentirosos o algo asi, no es el objetivo de este post charlar sobre técnicas de entrevistas sino sobre una pregunta que suelo hacer durante las mismas.

Recientemente un compañero, con el que estaba haciendo una búsqueda en particular entrevistando junto a mi, se reia cuando al promediar cada una de las entrevistas disparo la misma pregunta "Qué es lo más importante a tener en cuenta al programar un sistema? La Reusabilidad o la Mantenibilidad? Si te tuvieras que quedar con una de las dos, cual elegirias?". Luego de un par de segundos de desconcierto, la respuesta llega, siempre, invariablemente, la misma: " La Reusabilidad, claro".

Porqué? porqué?, cuando?, quien?, En que momento metimos en las cabezas de los programadores que el objetivo fundamental a perseguir cuando uno programa es la reusabilidad, es hacer componentes que puedan ser reusados una y otra vez?

Con una mano en la biblia del programador ("The art of computer programming", de Knuth?) cuantas veces recuerdan haber reutilizado un componente escrito para un sistema anterior? o Para el sistema presente? Vamos, recuerden que esta bajo juramento!

Ahora, cuantas veces recuerdan haber buscado en el código (o internet) un codigo parecido al que tenes que trabajar, copiarlo , pegarlo y modificarlo (POC/P: Programacion Orientada a Copy/Paste) ? Muchas?

Lo cierto es que a lo largo de la carrera profesional de un desarrollador siempre, invariablemente hemos visto como el marketing de un determinado framework proclama a viva voz : "Es para permitir armar componentes reutilizables", "Este framework generico te permite escribir ABM genericos, de manera de poder reutilizar las pantallas (los formularios, la ui)", "Este lenguaje permite extenderlo para facilitar la reusabilidad", incluso la POO fue vendida inicialmente como la panacea para lograr componentes reusables y extensibles.

A ver, que no se malinterprete, el código que uno desarrolla DEBE ser lo más reusable posible pero siempre, subrayo siempre, se debe dar prioridad en el diseño y el desarrollo a la MANTENIBILIDAD.

Porque?

Simple y sencillamente porque el hecho de que algo vaya a ser reusable depende de decisiones y acciones futuras con una determinada probabilidad mientras que la Mantenibilidad se necesita en el 100% de los casos y desde el primer dia de vida del sistema a lo largo de tooodo su ciclo de mantenimiento (notaron? Mantenimiento y Mantenibilidad? que casualidad), siempre claro, que el sistema entre en produccion.

Como uno no puede preveer el futuro, y no sabe si realmente va a reutilizar el componente que esta diseñando hoy, hacerlo más genérico de lo necesario implica hacerlo mas complejo de lo necesario para el caso en cuestion y esto a su vez lo hace mucho, mucho más dificil de mantenerrrrrrr!!!

Increible como parezca el mantenimiento de un sistema representa del 60% al 80% del costo total de un sistema, siendo el otro 20%-40% el costo del proyecto inicial de desarrollo (y estoy siendo conservador, conozco algunos que .... pero mejor no entro en detalles...por ahora). Reducir este costo es crucial y solo se puede lograr con un sistema lo mas simple posible, refactorizado y con amplia cobertura de tests de unidad. Esto último es esencial porque además si un sistema es mantenible los tests de unidad facilitan luego su extensibilidad porque es fácil modificarlo sin pisar alguna mina antipersonal y que todo el sistema explote!

Y La reusabilidad, que?

La reusabilidad de un componente, si viene, no viene dada por la clarividencia de un arquitecto iluminado sino por la repetida necesidad de una solucion similar a un mismo problema, que se refactoriza y extrae, utilizando justamente técnicas de refactoring y patrones de diseño (Ver GOF "Design Patterns", "Refactoring" de Martin Fowler o más recientemente Refactoring to Patterns, de Joshua Kierevisky). Es Posterior a la primera implementación, solo cuando uno se encuentra con el segundo ejemplo del problema o, mejor aún, el tercero, comienza a pensar en que está faltando un método o un componente (Clase) reutilizable (o cualquier otro síntoma de problemas con el codigo, ver Code Smells en el libro de Refactoring).

Entonces?

Entonces, chimpances entrenados, en todos los sistemas que hemos realizado lo más productivo ha sido tener, siempre y en todo momento, a la mantenibilidad como valor más alto.

El truco es que justamente al enfocarse en que nuestro código sea mantenible aumenta la reusabilidad!!! El código mantenible es más simple, tiene métodos y clases cortas, con menos acoplamiento, mayor cohesión, su intención y proposito es más claro, todo lo cual hace más fácil extraer comportamientos comunes y al refactorizar descubrir componentes faltantes que puedan ser reutilizados. Haciendolo al revés, se los digo por experiencia, no da el mismo resultado (el orden de los factores SI altera el producto, y no saben en que medida).

Ahora, hablar de "cómo?" hacerlo más mantenible es tema de otro Post, diría de una serie...., pronto en sus salas de blog más cercano!

martes, 27 de abril de 2010

Conclusiones del Code Retreat

Un poco más descansados después del fin de semana "corto" vamos a contar algunas conclusiones del Code Retreat del sábado.

El grupo En primer lugar queremos decir que fue un placer programar y discutir con todos los participantes del evento. Se dice que vale más un voluntario que cinco mercenarios y claramente las personas que participan de un evento que arranca a las 8:30 de un sábado entran en la categorías de voluntario.

Además todo el grupo tenía un nivel técnico muy interesante y mucha energía para participar. Los Code Retreat son eventos cuya calidad depende casi exclusivamente de los participantes (como el desarrollo!...) y creo que tuvimos mucha suerte en ese sentido.

Lo - Estuvimos pidiendo feedback a los participantes y por el lado de lo negativo todos estuvieron de acuerdo con que el horario fue medio cruel. La verdad es que no sabíamos como se iba a desarrollar el evento y teníamos miedo de que se estirara hasta muy tarde si no empezábamos temprano pero cuando lo repitamos vamos a empezar más tarde (a las 9 menos cuarto ;) ).

Lo + Por el lado positivo a muchos les gustó la rotación de los pares. Creemos que eso es una parte fundamental del ejercicio ya que así es como se van diseminando las buenas ideas entre todo el grupo. No es casualidad que este mismo efecto se menciona como una de las ventajas de usar Pair Programming en un proyecto de desarrollo.

Alguién mencionó que le había gustado el consenso al que se llegaba en la solución usando Pair Programming. Esta es otra característica interesante de PP, no hay decisiones tomadas por una sola persona.

También recibió varias menciones positivas el hecho de borrar el código entre las iteraciones. Esto es muy interesante porque fue una de las cosas que más resistencia generaba al principio del evento. Ser capaces de eliminar y escribir de nuevo código con el que no estamos conformes es una habilidad importante, permite encontrar soluciones mejores y no quedar atados a la primera que se nos ocurre. Fue muy bueno haberla podido ensayar en el Retreat.

La práctica de TDD fue bien recibida. Llamó la atención como la elección de los tests lleva a distintas soluciones y también como los tests sirven como indicadores de la calidad del código (si nos cuesta escribir tests probablemente tenemos un problema de diseño en el código que queremos testear).

Sugerencias Hubo varias sugerencias para próximas versiones, con las que estamos totalmente de acuerdo:

  • Hacer más corto el evento (creemos que probablemente la demo final estuvo de más),
  • No borrar el código si no que en cada iteración una pareja toma el código dejado por otra y sigue desde ahí (es otro tipo de ejercicio pero parece muy interesante)
  • Hacer una retrospectiva final (la verdad es que esto estaba previsto pero nos olvidamos!!!. De todas maneras se había hecho un poco largo y ya estábamos todos muy cansados).

Agradecimientos Para terminar queremos decir que estamos muy contentos por haber podido llevar a cabo esta iniciativa. Queremos agradecer a Pragma por el sponsoreo y muy especialmente a todos los participantes que fueron los que realmente llevaron adelante el evento.

lunes, 26 de abril de 2010

Primer Code Retreat Argentina

Este sábado 24/04 organizamos el primer Code Retreat de Argentina, en Buenos Aires. Fue una experiencia muy interesante que nos dejó muy conformes!










El objetivo de este Code Retreat fue familiarizarse con prácticas de Extreme Programming como Pair Programming y Test Driven Development (TDD).

Lo que hicimos fue trabajar en sesiones de 40 minutos, cada una de los cuales consistió en que los participantes intentaran resolver un problema de programación, trabajando de a pares y utilizando TDD. Una vez terminada cada sesión hicimos una retrospectiva de 15 minutos para reflexionar sobre los problemas encontrados y los distintos formas en que cada par había encarado su solución del problema. Después de la retrospectiva se cambiaban los pares, se borraba el código y se iniciaba una nueva sesión atacando el mismo problema.

De esta manera se realizaron 5 iteraciones y por ultimo, una 6ta iteración, en la que realizamos una demostración de un intento de solución del mismo ejercicio del Retreat.

Un punto aparte a destacar es la buena onda y el esfuerzo de todos los concurrentes en participar de un evento un dia no laboral. La integración y la comunicación crecieron en conjunto, iteración tras iteracion.

Los Participantes del primer Code Retreat fueron:
Claudio Meschini
Mario Del Lago
Hernan Vitto
Alejandro Miralles
Fernando Claverino
Gabriel Naiman
Damian Aberbuj
Emanual Teodoro
Amit Stein
Javier Andres Cengia
Matias Nicolas Blanch
Juan andres Knebel
Nicolas Bases
Augusto Bellucci
Claudio Vidau

Tambien agradecemos a Pragma, el Sponsor del evento.

Les dejamos algunas fotos del encuentro y vamos a realizar un post más completo cuando tengamos más feedback de los participantes y escribamos nuestras conclusiones.

sábado, 17 de abril de 2010

Code Kata

Es un hecho conocido que hay grandes diferencias de productividad entre un programador y otro.  Según algunos estudios los mejores programadores son entre 10 y 20 veces más productivos que los peores. Otros estudios hablan incluso de una diferencia mayor, sobre todo teniendo en cuenta que hay programadores que tienen productividad negativa
(ver http://www.pyxisinc.com/NNPP_Article.pdf).

Si esta diferencia se debiera solo a motivos de talento personal no podríamos hacer nada al respecto. Sin embargo, todos los buenosprogramadores atribuyen buena parte de su éxito a ciertas habilidades y hábitos que fueron adquiridos por ellos en algún momento y que les permitieron potenciar su talento natural.  Kent Beck (el autor de jUnit) afirma "Yo no soy un programador sobresaliente, soy un buen programador con hábitos sobresalientes".

Se tiende a pensar que estos hábitos se adquieren a través de la experiencia en el trabajo diario. Sin embargo las presiones y conflictos de un proyecto de software hacen que sea un pésimo lugar para aprender cosas nuevas. Para que un entorno facilite el aprendizaje es necesario que sea aceptable cometer errores, y esto no es así cuando estamos desarrollando software para alguien que nos paga por eso. Cuando tenemos presiones, tendemos a ser cautelosos y hacer las cosas como las hemos hecho antes, lo que causa que no aprendamos nada.

Además sería injusto para nuestros clientes utilizarlos de conejitos de India para probar nuevas técnicas o metodologías.  Dave Thomas dice al respecto: "En desarrollo de software aprendemos en el trabajo y por lo tanto nos equivocamos en el trabajo. Hay que buscar una manera de separar el aprendizaje del trabajo profesional. Necesitamos ensayos".
Por lo tanto, si queremos mejorar nuestras habilidades, hay que encontrar un espacio distinto al trabajo diario para hacerlo.

Esta idea es el origen de los Code Kata. Este concepto fue copiado de las artes marciales en las cuales una kata es un conjunto de movimientos que los estudiantes repiten hasta internalizarlos y lograr realizarlos de manera automática.  Las katas se hacen sin oponentes y su único objetivo es mejorar la técnica.  Es algo asi como, si recuerdan la pelicula Karate Kid,  cuando el señor Miyagi mandaba a Daniel-san a pulir los autos para mejorar su técnica de defensa...

Como es un Code Kata? Es un ejercicio corto (entre 30 minutos y una hora), que se intenta resolver tantas veces como sea necesario. Lo importante no es encontrar una solución sino la forma en que la buscamos. Esto es exactamente lo contrario de lo que pasa en el trabajo diario, donde lo fundamental es lograr una solución.

Después de cada intento buscamos feedback y analizamos posibles mejoras en nuestra forma de resolverlo. No buscamos solo mejores soluciones al problema sino mejoras en nuestro método de resolución. La manera óptima de conseguir feedback sería que otra persona nos observara y nos indicara las cosas que le parece que podríamos mejorar (este es el rol del sensei en las katas de artes marciales). Como esto es dificil de conseguir, otra posibilidad es utilizar algún software que capture la pantalla mientras resolvemos el problema de manera de poder después nosotros mismos buscar oportunidades de mejora.

Hace un tiempo hice un experimento con esta técnica, tomando como ejercicio escribir de cero un ABM simple en Rails . Repetí 18 veces la kata y cada vez capturé la pantalla mientras lo hacía y busqué oportunidades de mejora. Fue un ejercicio fantástico y fui mejorando muchos aspectos, desde cuestiones de entorno y herramientas hasta aprendizaje de nuevas librerías, pasando por profundizar el conocimiento del framework. En definitiva pude hacer una instrospección de como estaba haciendo mi trabajo y mejorar las cosas que no me gustaban.

Para tener una idea de cuanto fui mejorando, la primera vez que hice el ejercicio me llevó 45 minutos, mientras que la última pude hacerlo en menos de 15, comenzando desde cero cada vez,  logrando al mismo tiempo mejores resultados.

En definitiva, creo que es una técnica muy importante. Para aquellos que quieran probarla les recomiendo esta página de Dave Thomas donde
hay una lista de 21 ejercicios propuestos:

viernes, 26 de marzo de 2010

El porque de los chimpancés entrenados

Hace un poco más de 15 años, los que escribimos este blog estábamos en la facultad, haciendo nuestras primeras materias de ingenieria de software, después de varios años de materias más técnicas. Fue allí donde por primera vez nos vimos expuestos a la minimizacion de la importancia de la programación, expresada en la siguiente frase:"Si el diseño y el relevamiento de requerimientos es lo suficientemente bueno la programación podría ser hecha por chimpancés entrenados", que figuraba textual en uno de los libros de la materia (Gracias Ed!).

Como no podiamos estar mas en desacuerdo la elegimos como título para nuestro blog.

Esta creencia era y es bastante extendida en el sector y se expresa en metáforas como la de que el desarrollo de software es como hacer "Arquitectura" de un edificio donde una persona especializada se ocupa de realizar un diseño y un grupo de albañiles-programadores se ocupan de la tarea subalterna de transformar es diseño en código.

Además, como la tarea de programación se ve como algo de poco nivel y sencillo, se la ha intentado automatizar varias veces. En la época en que nosotros empezábamos nuestra vida profesional, la herramienta, la bala de plata, que iba a hacer obsoletos a los programadores y a permitir que los funcionales escribieran (perdón, debimos decir: diseñaran) directamente los programas eran los llamados "lenguajes de cuarta generación" o 4GL como Clipper, Clarion o Fox. De todas maneras no fue esta la primera vez que se intentó esto: en los comienzos de Cobol la idea de marketing fue muy parecida. Y hace muy poco tiempo se intentó lo mismo con la idea de UML ejecutable (entre muchos otros ejemplos).

Todo esto chocaba contra la realidad que percibíamos dia a dia, sobre todo porque en nuestra actividad profesional veíamos que la habilidad de los programadores era crucial para el éxito de los proyectos. Hemos visto mas de un proyecto de desarrollo con pésima gestión ser salvado por un equipo de "Heroes-Programadores", que inmolando sus vidas lograban llevar el proyecto al mejor resultado posible. Por el contrario cuando un equipo de desarrollo no era bueno, no importaba ni la mejor gestión ni la metodología usada, sencillamente el proyecto se hundía por el peso de su Deuda Técnica (ya hablaremos de este tema en otros posts).

Por eso, cuando por los años 2002/2003 descubrimos las metodologías ágiles y en especial Extreme Programming sentimos que era algo que se correspondía bastante más a lo que pensábamos y a la realidad en que estábamos inmersos. Nos encontramos con una metodología donde muchas de las prácticas tenían que ver directamente con el código y que además incluía el nombre "Programming" en el titulo.

Pensamos y sostenemos que la programación es fundamental para el desarrollo de software y que si en un proyecto no tenes buenos desarrolladores , que usen buenas prácticas y produzcan codigo de calidad, vas a fracasar independientemente de tu metodología, tus herramientas o la calidad de tu management.

Y esa es la idea de este blog, un blog para los "chimpancés entrenados".