miércoles, 23 de septiembre de 2015

Book review: "Workout: Games, Tools & Practices to Engage People, Improve Work, and Delight Clients"

Book cover


Introduction

The book "Workout: Games, Tools & Practices to Engage People, Improve Work, and Delight Clients" is Jurgen Appelo's third book. It's like the second part of Management 3.0 which gives a different approach to management.
It focuses on management practices whereas Management 3.0 is more theoretical.

Although these kind of books aren't my favorite, I decided to read it because his blog posts are very good and I frequently read them.

Good practices

In the author's opinion, a good practice should:
  • engage people and their interactions.
  • enable people to improve the system.
  • help to delight all clients.
This is a good pattern to know when a manager is following a good practice or not. When you have doubts about whether a practice is good or bad these three points should help you.

The top 3, for me, were kudo box (www.management30.com/kudo-box), merit money (www.management30.com/merit-money) and delegation boards (www.management30.com/delegation-boards).

I'm going to write just about kudo box and other different subject (the law of requisite variety) because I don't want to write a long blog post but If you want to know more about these practices, in the links next to them you will find a lot of information.

Law of Requisite Variety

This law says "if a system is to be stable, the number of states of its control mechanism must be greater than or equal to the number of states in the system being controlled".
This means that anything that controls a system must be at least as complex as the system being controlled.
Organizations are complex adaptative systems. Then, for example, a manager of a team in an organization should be as complex as the team who is managed. As you can image that's a ridiculous statement. In simple terms, a manager can't manage a group of people.

Kudo box

This practice consists of writing a letter to a colleague when she did something good for the team. All the letters are put in the kudo box and, for example, once a month the box is opened and all the letters are read aloud.
Each letter should focus on individual effort instead of outcome because a great outcome requires many individuals' effort.

Recap

Despite the amount of pages, this book is easy to read. What I'm more impressed about is that it gave me a different point of view on management.

I'm not a big fan of managers or management but now I know that is because of all the bad practices that I've suffered in my career.
It also shows me that it's possible to create an environment where people really want to work when we focus on the real important things (see good practices).

In short, if you have money buy this book as soon as possible or if you don't have any money the book is free when you sign up here:

https://management30.com/product/workouts/


domingo, 16 de agosto de 2015

Ejemplo mejorado de doble de test

El artículo anterior trataba de un ejemplo de doble de test de tipo stub.
El stub se llama StubUserDAO e implementa el método findUserBy, devolviendo siempre el mismo objeto.

Si quisiéramos que findUserBy devolviera otro User tendríamos que crear otra clase como StubUserDAO que devolviera ese User, ya que StubUserDAO siempre devuelve el mismo User.

Como puedes imaginarte, no es una solución flexible, ya que casi con cada nueva prueba tenemos que crear una clase parecida a StubUserDAO.

Para solucionar este problema, en este artículo te quiero presentar la versión de un doble de tipo de tipo stub:



La principal diferente, de este doble de test en relación con el anterior es que podemos cambiar el User que va a devolver el método findUserBy.
Podemos cambiar el usuario que devuelve el método utilizando el método.
En el código, el test should_throw_exception_when_passwords_are_different_version1 hace que que StubUserDAOv2 devuelva un usuario con contraseña "other_password", y el test should_throw_exception_when_passwords_are_different_version2 hace que devuelva un usuario con contraseña "another_contraseña".

Como he comentado al principio, la principal ventaja de este tipo de stub es flexible ya que permite devolver diferentes tipos de valores sin tener que crear una nueva clase.
Otra ventaja de este tipo de stub es que la configuración del stub para que devuelve el usuario es el propio stub. Al tener la configuración en el stub queda claro lo que estamos probando, porque podemos ver la contraseña del usuario y la contraseña que utilizamos en el signin al mismo tiempo ya que están al lado.
Esto simplifica mucho el comprobar que es lo que fue mal cuando el test falla.

Un par de comentarios sobre el ejemplo:

  • Recuerda inicializar siempre stub. Así nos evitamos desagradables efectos secundarios como que si ejecutas todos los test no todos pasan, pero si ejecutas uno en concreto pasa (también puede ser el efecto contrario). Esto es debido a que un test comparte usuario con otro test a través del stub.
  • Hay que utilizar como atributo en la clase de test el objeto StubUserDAOv2, y no UserDAO. Parece una tontería pero la primera vez que creé el stub, me quede un buen rato atascado porque Eclipse me decía que no podía utilizar el método setUserFoundByEmail y era porque utilicé UserDAO:





martes, 14 de julio de 2015

Refactorizar y test unitarios


Imagen de http://blog.arnaud-lefebvre.fr/

El proceso que sigo cuando estoy desarrollando una nueva funcionalidad es:
  1. desarrollo la nueva funcionalidad de la forma más rápida posible para que simplemente funcione.
  2. refactorizo el código para que sea más fácil de entender y para que sea más fácil de mantener.
Refactorizar es cambiar el código sin cambiar su comportamiento. El código debe de funcionar de la misma manera antes y después de cambiarlo.
Refactorizar consiste en muchos cambios pequeños en el código que hacen que nuestro código y diseño mejoren.

Cada vez que cambiamos nuestro código hay que comprobar que funciona. Los test unitarios son la forma más rápida que conozco de comprobar que el código funciona.
Si no tengo test unitarios tengo que ejecutar la aplicación y comprobar manualmente que el código que he cambiado funciona. El refactorizar se hace muchas veces por lo que hacer esta comprobación consumirá mucho de nuestro tiempo.

Resumen

Refactorizar es muy importante en mi proceso de desarrollo porque hace que mi código sea fácil de entender y de mantener.
Escribo test unitarios ya que es la forma más rápida que conozco de comprobar que mi código sigue funcionando después de refactorizar.
Si refactorizar es también importante para ti, test unitarios también deberían de ser importante debido a que la otra opción, que es comprobar de forma manual, te va a tomar mucho mas tiempo.

miércoles, 10 de junio de 2015

My first project with Scrum

Image from http://www.3news.co.nz

Introduction

I've been working on a new project for the last few months. I worked with two external developers on this project. One of them has experience as Scrum master so the team decided to use Scrum as the methodology in the project.
I'd read a lot about Scrum and I'd applied some practices in the past but I'd never used Scrum by the book.

In this blog I've written a summary about my experience using Scrum in a project that was built from scratch.

I´m not going to talk about the practices of Scrum, so if you want to know more, a good place is:

http://www.scrumguides.org/

you can find there the official guide of Scrum in many languages.

Pros


  • Retrospectives really work. Every retro helped us to discover the problems in the sprint and to solve them. For example, part of the team didn't work at the office and that caused communication problems. The communication improved thanks to the retros and the actions that we took in each one.
  • Team building. We spoke a lot, and because of all the meetings we knew each other and came together as a team. I was new in the company and I didn't know my colleagues nor the external developers. I believe we made a good team in few months due to the scrum practices.
  • The product's design is understood for each member of the team. In this case, sprint meetings allowed us to understand the whole design of the application. That could also improved the design because many decisions were taken together.


Cons


  • Scrum can be used as a tool for micromanaging the team. That could happen when dailies and retros are done in the wrong way. Dailies would just be about the status of each story and retros would just be about checking estimations in detail. It didn't happen but I realized how a person could transform scrum into something ineffective.
  • Feedback in the last part of the project. We did an acceptance test after the development had finished where most of the company participated and we received a lot of feedback. I see this like a negative thing because we couldn't transform the feedback into new features. Our sprints were two weeks long and the last day of each sprint we did a demo where all the people involved in the product attended, including the people who gave us feedback in the acceptance test.


I'd like to add that we could apply the use of Scrum better because, for example, we had to write documents and other tasks after the development had finished and they should have been included in the project.
Furthermore, our main problem was that we didn't have a product owner and a colleague had to play that role. I believe the highest benefit of Scrum and other Agile methodologies is that the value is maximize and due to the fact that we didn't have a proper product owner that benefits were decreased.

The next blog explains the meaning of value very well:

http://ronjeffries.com/xprog/articles/value-is-what-you-like/

The same writer has just released a book with the title "the nature of software development" and is amazing. It has a little more than 100 pages that explains in the most clear way possible what software development is about. I've read it recently and it´s a really nice book.

Recap

I'm happy with the end result of the project although we could do it better . I love how Scrum practices allow us to improve the team performance and the development process.

Scrum doesn't have development practices and I miss them because developing an incremental and iterative product without them is very hard. For example, TDD and continuous integration.
So, in regards to development practices XP is better than Scrum because it includes many practices for us, programmers.

* 22-06-2015 Solved grammar error

domingo, 3 de mayo de 2015

Mi primer proyecto con Scrum

Imagen de http://www.3news.co.nz


En los últimos meses he estado trabajando en un nuevo proyecto. En este proyecto hemos tenido a dos personas externas. Uno de ellos tiene experiencia como Scrum master por lo que el equipo decidió el utilizar Scrum como metodología en el proyecto.
He leído bastante sobre Scrum y he utilizado partes en el pasado pero nunca había utilizado Scrum by the book.

A continuación, voy a comentar de forma resumida mi experiencia utilizando Scrum en este proyecto, que desarrollamos desde cero.
No voy a hablar sobre cuales son las prácticas de Scrum, por lo que si no lo conoces, un buen recurso es:

http://www.scrumguides.org/

donde hay guías oficiales en muchos idiomas, incluido en español.

Cosas buenas

  • Las retrospectivas realmente funcionan. En cada retro hemos ido viendo las dificultades que teníamos y hemos ido mejorando en esos aspectos. En nuestro caso, parte del equipo no trabajaba siempre en la oficina y eso causó problemas de comunicación. Este problema de comunicación disminuyó mucho gracias a las retros, y a los acciones que tomamos después de cada retro.
  • Formamos equipo. Todo el tiempo que pasábamos juntos hablando hizo que nos fuéramos conociendo y que poco a poco formáramos equipo. Soy nuevo en la compañía y no conocía a mis compañeros ni a la gente externa contratada pero gracias a las prácticas de Scrum a los pocos meses formamos un buen equipo.
  • El diseño de la aplicación es entendido por todo el equipo. Las reuniones de sprint permitieron que todos los miembros del equipo entendieran el diseño de la aplicación. El diseño mejoró debido a que las decisiones importantes las tomábamos en conjunto.

Cosas no tan buenas

  • Es muy fácil convertir Scrum en una herramienta de control. Podemos controlar hasta el mínimo detalle lo que hace cada miembro del equipo, si en las reuniones diarias solo se comenta el estado de cada uno, y en las retros se miran en detalle las estimaciones, . Es lo que se llama micromanagement. No es algo que halla pasado en el proyecto pero es algo que me di cuenta que podía haber pasado ya que pusimos al principio demasiado énfasis en que las estimaciones fueran las correctas.
  • Mucho feedback al final del proyecto. Al final del proyecto realizamos un test de aceptación en el que participó buena parte de la compañía y recibimos muchos comentarios interesantes. Lo veo como algo negativo porque no tuvimos tiempo para poder añadir los comentarios en la aplicación. Cada dos semanas hicimos demos para la compañía, en donde esas mismas personas que hicieron comentarios, asistieron pero no dijeron nada al respecto.

Además de las puntos comentados anteriormente, podíamos haber aplicado Scrum mejor, ya que, por ejemplo, al terminar el proyecto tuvimos que realizar documentación y otras tareas y deberían haber sido parte del proyecto.
Además, el principal problema que tuvimos con Scrum fue el product owner, debido a que no encontramos a nadie que encajara con el puesto, por lo que una persona sin la suficiente experiencia y poder (de tomar decisiones sobre el producto) tuvo que ejercer esta posición. Debido a ello, el mayor beneficio de Scrum y también de las demás metodologías Agile, que es el maximizar valor, se vio resentido.

Este artículo de Ron Jeffries explica muy bien qué es valor:

http://ronjeffries.com/xprog/articles/value-is-what-you-like/

Este mismo autor, ha sacado un libro con el título The Nature of Software Development que es una maravilla. Son ciento y pico hojas que explican de forma sencilla y sin palabras técnicas en que consiste el desarrollo de software. Perdón por el off topic pero acabo de terminarme el libro y me ha encantado.

Conclusión

Aunque podíamos haber utilizado Scrum mejor estoy contento con el resultado final del producto. Me encanta como ciertas prácticas de Scrum permiten el ir mejorando el funcionamiento interno del equipo y el proceso de desarrollo.

Scrum es una metodología genérica, que se puede utilizar en otros proyectos que no sean de software. Creo que por ello, echo en falta algunas prácticas específicas para programadores, que deberían estar incluidas. Por ejemplo, TDD e integración continua, porque estás prácticas son fundamentales cuando se realiza un desarrollo de un producto de forma iterativa e incremental, como en Scrum.
En este sentido, XP es mucho más completo porque incluye estas y otras prácticas específicas para nosotros, los programadores.

miércoles, 1 de abril de 2015

La comunicación es la clave


Cuando llegué a Holanda, mi nivel de inglés a nivel de conversación era pésimo, pero gracias a que tenía bastante experiencia como programador no me resultó difícil el encontrar trabajo.

Encontré trabajo en una startup, que consiste en una aplicación para dar y recibir feedback y orientada al mundo corporativo. La aplicación consistía en una aplicación web y web móvil, y una aplicación para el iPhone.
Habían contratado una empresa externa para que les hiciera una primera versión de la aplicación, y ahora me tocaba el mejorar esa primera versión.
Fui el primero al que habían contratado, por lo que trabajaba solo con la persona con la que había hecho la entrevista, y que resultó ser el dueño de la startup.
Esta persona no estaba contenta con el resultado final de esa primera versión del producto porque la empresa contratada no le mantuvo al día de como iba la aplicación y se había dado cuenta que estar involucrado en el desarrollo le ayudaría a tener el producto que deseaba.
Los primeros meses los pasé principalmente hablando con el dueño sobre cuál era su idea de como debía de ser la aplicación. Como he comentado, mi nivel de ingles era pésimo, por lo que el tenía que esforzarse en entender y en hacer que le entendieran. Además que cada dos por tres tanto yo como el teníamos que confirmar que lo que habíamos entendido era lo correcto. Esto incluso hubiera sido más difícil si no hubiéramos tenido una pizarra (whiteboard) para reflejar nuestras ideas.
En estas conversación, que duraban horas, me hablaba de como era el producto y de como quería que fuese, pero también de muchas otras cosas. Entre ellas, me hablaba de a quien iba dirigido, como pensaba que podía venderlo y las características principales que lo diferenciaban de la competencia.
Después de unas primeras semanas, que las dedicábamos la mayor parte del tiempo a hablar, el tenía que marcharse frecuentemente a ver clientes y posibles clientes. En ese tiempo, pasó algo que no me había pasado antes y que pareció algo casi mágico.
Mientras estaba desarrollando la nueva versión, si me encontraba con algún tipo de decisión que tenía que tomar y que afectaba al modelo de negocio, no tenía ni las más mínima duda de cual era el camino que debía tomar. No tenía dudas, no porque habíamos hablado hasta el más mínimo detalle del producto, sino que gracias a las conversaciones que habíamos tenido podía estar seguro de cuál sería el camino que el tomaría.
Además, se me empezaron a ocurrir ideas de posibles nuevas funcionalidades que costaban poco tiempo en programarse y que creían que estaban alineadas con el producto deseado.
El tiempo pasó y esas largas conversación ya no sucedían tan frecuentemente como al principio. Además que mi nivel de inglés mejoró, por lo que no era necesario el dedicarle tanto tiempo a transmitir la información. Así, también esos momentos "mágicos" dejaron de suceder.

Conclusión

No voy a añadir ninguna conclusión, ya que creo que en este caso cada uno tiene que sacar sus propias conclusiones. Solo comentar que el manifiesto agile me pareció mas cercano a partir de ese tiempo.




martes, 24 de marzo de 2015

Comentando el libro "the art of agile development"

Imagen de http://www.extremeprogramming.org/

Introducción

El libro the art of agile development trata de TODAS las etapas de un desarrollo utilizando XP. He escrito todas en mayúsculas porque el libro es muy completo y habla de cada etapa con mucho detalle.
Los autores del libro son James Shore y Shane Warden. James Shore lo conocía de antes porque tiene una página sobre TDD en Javascript que tiene muy buena pinta:

http://www.letscodejavascript.com/


Dentro de cada capítulo hay un apartado con posibles preguntas que nos podemos hacer, problemas que podemos tener y posibles alternativas a ciertas prácticas.
Al ser un libro muy completo y con muchos detalles, es muy fácil el encontrar una pequeña joya en forma de consejo en muchas de sus hojas.


Hay, a continuación, un apartado sobre XP y luego una serie de conceptos que aparecen en el libro y que me han gustado especialmente. Estos conceptos son root cause analysis, informative workspace, pair programming y theory of constrains.

XP

Extreme programming (XP) es una metodología que a diferencia de otras metodologías Agile se centra mucho en prácticas para los programadores.
Así, dentro de las prácticas de XP tenemos pair programming, TDD, simple design y refactoring.
Todas estas prácticas permiten que el equipo se centre en llegar a la excelencia técnica, que es uno de los principios detrás del manifiesto Agile.
Creo que tener estas prácticas es algo que la diferencia de otras metodologías y que puede hacerla que tenga mayor número de éxitos, pero que a su vez resulta complicado de implantar al tener más prácticas que, por ejemplo, Scrum.
Si quieres saber más sobre XP, en la siguiente página hay mucha información sobre esta:
http://www.extremeprogramming.org

Root cause analysis

Root cause analysis es un método que nos permite llegar a la raíz de un problema. En nuestro caso, lo podemos utilizar cuando nos encontremos con un error en nuestro código de producción.
Cuando nos encontremos con un problema en nuestro código debemos de preguntarnos 5 veces el porqué se ha producido.
Una cosa importante sobre este tema y que comentan en el libro es que resulta fácil el culpar a una persona del problema, pero que detrás de la persona tenemos nuestro proceso de desarrollo, por lo que si tenemos que culpar a alguien hay que culpar a nuestro proceso y, luego, intentar mejorarlo.

Informative Workspace

La idea es muy simple, añadir información relevante relativa al proyecto en la zona de trabajo.
Tener una zona de trabajo con información del proyecto permite a todo el equipo y a la gente fuera del equipo el ver el progreso de este, simplemente caminando alrededor.
El objetivo principal de esta práctica es la información. Difundir información entre todas las personas involucradas en el proyecto.
Los gráficos deben de estar en este espacio porque permiten de una forma simple, eficaz y sin malentendidos el informar. Hay principalmente dos gráficos en XP y son: iteration plan y release plan.
También comentan que es mejor utilizar un bolígrafo y un papel en vez de pantallas, debido a que nos da más flexibilidad y en que de un solo vistazo se puede ver todo.
Creo que otra de las cosas en las que ayuda estas prácticas es en aumentar la confianza de los stakeholders en el equipo ya que pueden ver en todo momento el estado del proyecto.

Pair programming

Lo primero que llama la atención sobre pair programming en el libro, es que esta en la sección de pensar (thinking). Lo que nos da una idea para que lo utilizan los autores.

Esta práctica mejora, según los autores, el poder mental (brainpower) mientras estamos programando. Así, mientras el que esta programando (driver) solo esta pendiente de desarrollar, la otra persona (navigator) tiene como tarea la de pensar.
Cuando practicamos pair programming no es que dos personas este realizando el trabajo de dos, sino que se divide el trabajo, uno programa y el otro piensa. No es que el que programa no esté pensando sino que la pareja tiene mas tiempo para hacerlo.

He practicando pair programming en los coderetreat y todas las veces acabé muy cansando porque al estar con una pareja estas todo el tiempo concentrado al 100%. Otra gran cosa es que se aprende muchísimo y creo que en general todo el mundo tiene la misma sensación.

Theory of constraints

La teoría de las limitación dice que en todo sistema hay una y solo una limitación y que esta es la que provoca que se ralentice el sistema.

XP considera que la limitación en software development es el desarrollador. Eso es algo que se dice muchas pero que muchas veces en el libro.
Después de leerlo tantas veces estaba algo mosqueado porque aunque es cierto que los programadores podemos mejorar para que el sistema vaya mejor creo que hay otras posibles opciones. Como puede ser los managers que en muchos cosas ralentizán el trabajo de los programadores con sus decisiones, o la poca integración de la gente de negocio en el proceso de desarrollo.
Escribí un tweet y tuve la suerte de que jb me respondió.

Resumen

Aunque tiene unos años es un libro muy recomendable. Me ha ayudado a entender XP y todos las prácticas relacionados con XP.
Tiene muchos consejos sobre cómo implantar XP en una organización y creo que son muy útiles.

Personalmente, me encantaría practicar XP porque aunque sé que las primeras semanas o meses voy a estar muy cansado, debido principalmente a pair programming, voy a poder aprender muchísimo y creo que el resultado final va a ser un gran producto.

*Modificado 25-03-2015: añadido enlaces al libro e información de los autores

miércoles, 11 de marzo de 2015

Ejemplo de código Java hecho con TDD (con historia incluida)

Imagen de http://www.programming-challenges.com/

Hace algunos meses estaba buscando un nuevo trabajo como programador, y una de las cosas que suelen pedir en Holanda, para medir las habilidades de los candidatos, es un ejemplo de código.

Por lo que he vivido durante esos meses, hay un número grande de empresas que no solo quieren un ejemplo de código sino que te piden resolver un problema concreto en un tiempo determinado.

En una de las empresas, el problema que me pidieron resolver me pareció interesante. El problema era el construir una aplicación que calculara la fecha en la que un cliente tendría su pedido listo, teniendo en cuenta la fecha actual del sistema y el tiempo que se tarda en realizar la tarea.

El ejercicio lo hice completamente utilizando TDD y me costó (creo recordar) dos semanas, utilizando horas de mi tiempo libre, ya que tenía trabajo.  Lo tuve que hacer dos veces, debido a que la primera vez, la solución que había elegido en un punto me estaba complicando el añadir más test sin romper los test anteriores.

Después de enviar mi solución al problema, me quedé a la espera de recibir información de si les había gustado, y si era así, si me invitaban a una entrevista. Estaba bastante ansioso de recibir la respuesta porque terminé bastante contento de como me quedó.  No es que sea perfecto el código, sino que era la primera vez que enseñaba mi código a alguien después de haber aprendido TDD.

Nunca recibí ningún tipo de feedback sobre el código y ni siquiera se dignaron en decirme nada de porqué se estaban retrasando tanto.

Ya que no he recibido ningún tipo de feedback y que me quedé con ganas, lo he publicado en GitHub y estaré más que encantado de recibir cualquier tipo de comentario.

No he añadido muchos detalles sobre cual es el problema porque no quiero dar pistas sobre cual era la compañía, pero creo que los comentarios que añadí en el código y los test hacen que resulte fácil de entender.

El enlace al código es:

https://github.com/kikers25/programming_challenge

El ejercicio está hecho con maven y java 7. Las librerías que utilicé son: JUnit 4, hamcrest, Joda-Time y pitest.
Pitest es una librería que mide la cobertura del código utilizando "mutation testing". Hay un artículo en español muy bueno que explica muy bien qué es "mutation testing":

http://testeandosoftware.com/mutation-testing/

martes, 3 de marzo de 2015

Dobles de test con jMock en un ejemplo

Introducción

En los dos últimos artículos (este y este) hemos visto cómo crear nuestros propios dobles de test. En este artículo vamos a ver un ejemplo de una librería de dobles de test: jMock.

jMock

Hay muchas librerías de dobles de test, como easyMock, Mockito y JMockit. La mayoría de esta librerías están bien y te van a ayudar a crear dobles de test que te faciliten el trabajo de testear una clase.

Yo utilizo jMock porque me ayuda a mejorar el diseño de mi código. Por defecto, nos obliga a tener que declarar de forma explícita cuales son las llamadas que todos los dobles de test que utilicemos en nuestro código a probar.
Si, por ejemplo, en un método tenemos un doble de test que llamamos a tres de sus métodos, tenemos que especificar que permitimos la ejecución de los tres métodos.

Al tener que añadir todas las llamadas al principio del test, podemos ver si hay algo que huele mal (smell) en nuestro código, y así poder mejorar nuestro diseño.

Un inconveniente de jMock comparado con otras librerías como easyMock es que es más complicado de leer el código, pero personalmente es más que suficientemente legible el código.

Ejemplo

En el artículo sobre dobles de test de tipo spies, hay un ejemplo con dos tipos de dobles: spies y stub. Vamos a utilizar ese mismo ejemplo, junto con el mismo código de producción pero añadiendo un test utilizando jMock. Al tener un test con dobles de test hecho por nosotros y otro test con dobles de test de jMock nos va a permitir el ver la diferencia de utilizar la librería y nuestro código.

Vamos a utilizar el mismo código de producción y añadiremos al código de test un nuevo test utilizando jMock.



Creo que el código de producción que aparece arriba es fácil de entender, pero si necesitas alguna explicación extra, en el artículo sobre spies puedes encontrarla.
A continuación, el código de test.



Ambos test hacen lo mismo, comprueban que UserService.findOrCreateWith llama al método sendEmailTo de EmailService, o lo que es lo mismo, comprueban que se envía un email.
La mayor diferencia entre ambos test es que el primero falla cuando nuestro doble de test devuelve false y que el segundo falla lanzando una excepción.

El test con nuestro código de dobles de test comprueba de forma explícita que es llamado el método. Y el test con los dobles de test con jMock comprueba de forma implícita que es llamado el método.

El test should_send_an_email_when_a_user_was_created_with_jmock, dentro de Expectations comprueba que es llamado un vez el método EmailService.sendEmailTo en:



Nuestro doble de test también podría lanzar una excepción cuando no es llamado el método, pero para ello tendríamos que crear un método que realizara la comprobación y lanzara la excepción. Este método debería de utilizarse al final del test.
jMock no necesita que llamemos a ningún método para comprobar las llamadas a los colaboradores porque siempre comprueba internamente (gracias a la anotación Rule) al final de cada test si las expectativas de cada doble de test fueron satisfechas.

Dobles de test propios o librería

Cuando descubrí los dobles de test, los creaba todos a mano, pero ahorré mucho tiempo cuando empecé a utilizar librerías.
Actualmente la mayoría de mis dobles de test los creo con jMock.

Aunque utilizo mas jMock que mis propios dobles de test, siempre hay casos en los que resulta mucho más fácil el crear mis propios dobles de test.
Por ejemplo, cuando resulta complicado el añadir un doble de test con jMock siempre utilizo mis propios dobles de test.
Otra ejemplo sería, cuando no voy a utilizar para nada en los test un colaborador creo un doble de test de tipo dummy o stub para que sea más fácil de entender el test.

martes, 24 de febrero de 2015

Un ejemplo de doble de test con spies

Imagen de https://www.organicconsumers.org

Introducción


En el artículo anterior hablé sobre los dobles de test y los dobles de test de tipo stubs. Los stubs son los tipos de dobles de test que más utilizo en mi día a día.
En este artículo voy a hablar sobre otro tipo de dobles de test: spies.

Tipos de test unitarios

Una forma de clasificar los test unitarios es a partir de la forma que comprueban que nuestro código de producción funciona. Así, tenemos test que comprueban el estado y test que comprueban el comportamiento.
  • Estado: Estos test primero realizan operaciones y comprueban que el resultado es el esperado. La comprobación de que el resultado es el esperado se hace a través de los métodos de tipo assert, como por ejemplo assertEquals, assertTrue y assertNull. Como puedes imaginarte, este tipo de test unitario es el más común y un porcentaje muy alto de los test son de este tipo.
  • Comportamiento: Estos test lo que hacen es comprobar que se llaman a ciertos métodos de los objetos colabores de la clase que estamos testeando. Lo que comprueban es la interacción de nuestro método con los colaboradores. Los dobles de test de tipo spies nos ayudan a realizar esta comprobación, es decir, nos ayudan a testear el comportamiento de nuestro código de producción.

Spies: un ejemplo

Los tipos de test spies son objetos que graban información de como han sido llamados.
Vamos a verlo con un ejemplo. Primero, vas a ver el código de producción y luego el código de test.

Tenemos un método findOrCreateWith de la clase UserService, que devuelve un usuario a partir de su email.
Si el usuario con ese email existe en la base de datos, lo devuelve. Pero si no existe, lo añade a la base de datos y posteriormente envía un email a esa dirección.
Entonces, si existe un usuario con ese email lo devuelve, pero si no existe lo crea y envía un email.



Algunos comentarios sobre el código de arriba:
  • UserService tiene dos objetos colaboradores: UserDAOEmailService.
  • UserDAO se encarga de manejar el usuario en la base de datos.
  • EmailService se encarga de enviar emails.
  • UserDAO y EmailService son interfaces.
  • El método UserDAO.findUserBy siempre devuelve un objeto de tipo User. El método isEmpty de User devuelve true cuando es un objeto vacío, ya que no está en la base de datos, y false cuando es el objeto real. No me gusta devolver null en ningún método por lo que utilizo este patrón. Si quieres saber más escribí un artículo sobre esto aquí.
Después de ver el código de producción, lo que queremos es comprobar que cuando el usuario no existe en la base de datos enviamos un email al usuario, o lo que es lo mismo llamamos al método sendEmailTo del colaborador EmailService.



En el test should_send_an_email_when_a_user_was_created los pasos que he seguido y que separado con un línea en blanco son:

  1. Inyectar un stub de tipo UserDAO y un spy de tipo EmailService a UserService
  2. Llamar al método que estamos testeando: findOrCreateWith
  3. Finalmente, comprobar que se ha enviado el email. Esto se hace comprobando que el método wasSentEmail vale true. Y la única manera de que wasSentEmail sea true es que sendEmailTo halla sido llamado.


Mejoras

No estoy del todo contento con el código de producción que he escrito, así que si alguien me puede ayudar a mejorarlo estaré más que contento en leerlo. Los siguientes puntos describen algunas de las partes que son mejorable bajo mi punto de vista:

  • findOrCreateWith es un nombre horrible para llamar un método. Quizás hubiera sido mejor el llamarlo find o create.
  • EmailService tampoco me gusta como nombre. Quizás SenderEmail hubiera sido mejor.
  • Es importante que en un mismo método halla el mismo nivel de abstracción o lo que es lo mismo, que se utilice el mismo lenguaje. Creo que en este caso findOrCreateWith no está en el mismo nivel. Una pista que me hace pensar eso es que la clase que estamos testeando se llama UserService e inyectamos un objeto que se llama de forma parecida: EmailService.
El código de test no es tampoco perfecto, pero una de las razones es porque lo que he intentado simplificar al máximo.

Fuentes

  • http://googletesting.blogspot.nl/2013/03/testing-on-toilet-testing-state-vs.html
  • http://www.martinfowler.com/bliki/TestDouble.html



lunes, 16 de febrero de 2015

Un ejemplo de doble de test con stubs


Imagen de http://www.parts-recycling.com

Introducción

Un doble de test simula un objeto de producción y nos permite el probar otros objetos.

Según Martin Fowler en este artículo, hay cinco tipos de dobles de test: dummy, fake, stubs, spies y mocks.

En este artículo voy a enfocarme en stubs y en fakes dummies porque son los dobles de test que más suelo utilizar.
Para saber más sobre los dobles de test podéis leer el artículo de Fowler o este de XUnitPatterns, que son muy buenos.

Aunque podemos crear un objeto de tipo stub con cualquier framework de pruebas como JMock o EasyMock, es mejor hacerlo nosotros mismos para así entender mejor como funcionan.

Ventajas de los dobles de test

Los dobles de test unitarios tienen dos ventajas frente a utilizar los objetos reales de producción:
  • Determinismo: siempre se va a comportar como queremos. Con los objetos reales dependiendo de muchos factores van a comportarse de una forma u otra. Así, si el objeto accede a base de datos se comportará de forma distinta dependiendo de los registros que hay en la base de datos.
  • Rapidez: no acceden a la base de datos o al sistema de ficheros y tampoco acceden a Internet por lo que hacen que el test sea mucho más rápido, que es lo que queremos. Porque unos de los principales cualidades de un buen test unitario es que es rápido porque así podemos ejecutarlo a menudo.

Stubs

Stubs, cuya traducción al español no me atrevo a hacer, son objetos que han sido programados de forma muy simple por nosotros para que responden de una forma determinada.

Imagina que tenemos un objecto UserService que tiene un método que se llama signIn que permite validar que un usuario pueda hacer "log in" y devuelve el usuario.



En el código anterior, el método signIn solo hace tres cosas: buscar al usuario a partir de su email, validar que las contraseñas son las mismas y devolver el usuario.


Lo que queremos probar es que si el usuario tiene diferente contraseña que la pasada por parámetro se va a lanzar una excepción de tipo AuthenticationException.
Para ello, queremos que UserDAO devuelva un usuario con diferente contraseña que la que pasamos por parámetro.
Vamos a crear una clase de implemente UserDAO y cuyo método findUserBy devuelva siempre el mismo usuario.



El nombre del objeto de tipo stub es StubUserDAO y como puedes comprobar no tiene ningún misterio. Es una clase que implementa UserDAO cuyo único método devuelve un usuario con la contraseña "other_password".

El método initialization crea los objetos UserService y StubUserDAO e inyecta el objeto StubUserDAO a UserService.

En el ejemplo, hay dos test unitarios que hacen lo mismo pero de dos formas distintas. Ambos comprueban que se lanza la excepción AuthenticationException.

El test should_throw_exception_when_passwords_are_different_version1 comprueba que se lanza la exception con un fail cuando no se ha lanzado.
El test should_throw_exception_when_passwords_are_different_version2 lo comprueba a través del estándar JUnit.

Dummy

Dummy es otro tipo de doble de test que no hace nada. Se suele utilizar para no tener que pasar como parámetro un null como valor.

En el ejemplo anterior el objeto EMAIL es un doble de test de tipo dummy. El código de producción que implementa la interfaz UserDAO lo utiliza, pero como estamos utilizando nuestro stub pues no se utiliza.
En el ejemplo, si EMAIL valiera null no pasaría nada pero eso es porque no es código real de producción.
Suelo comprobar que los parámetros (email y password en este ejemplo) del método no valgan null en mi código de producción.


lunes, 9 de febrero de 2015

5 consejos para escribir mejores test unitarios

Cuando empecé a escribir test unitarios cometí muchos errores y seguro que todavía cometo y cometeré muchos otros. En este artículo quiero ayudar a la gente que empieza a que no cometan los mismos o al menos a que puedan identificarlos.

1. Una razón para fallar

Cuando un test falla tiene que estar muy claro cual es la razón por la que ha fallado y si nuestro test unitario esta comprobando mas de una cosa, tendremos que mirar todas esas partes del código y eso nos va a costar mas tiempo de lo necesario.
Por el contrario, si solo comprueba una parte específica de nuestro código de producción, va a resultar trivial el solucionarlo cuando el test falle.
Como regla general, tener solo un assert, es la mejor forma de cumplir esta buena práctica.

2. Nombre del test

El nombre del test es muy importante, ya que al ejecutarlo lo primero que vas a ver cuando falle es el nombre. Así que, el nombre del test (junto con el mensaje de error) debe de decirte el porqué ha fallado sin tener que ver el código de producción.
El nombre tiene que contener el qué se está testeando y cual es el resultado que se espera. Como puedes imaginarte, al contener esta información el nombre del test no va a ser corto. Por lo que se podría decir que, al contrario que con el código de producción, el nombre va a ser largo.
En mi caso, utilizo el siguiente formato:
should_elResultadoEsperado_when_elCasoQueEstoyProbando

Un ejemplo del formato que utilizo seria el siguiente:
should_throw_exception_when_there_is_no_internet_connection

Hay mucha gente que en vez de utilizar un guión bajo para separar las palabras pone en mayúsculas la primera letra de la palabra:
shouldThrowExceptionWhenThereIsNoInternetConnection

No hay ninguna opción que sea la mejor. Utilizo guiones bajos porque personalmente entiendo mejor el texto.


3. Rápido

Que tus test unitarios se ejecuten en pocos milisegundos es una de las cualidades más importantes que deben tener.
Y te preguntarás el porqué es tan importante que tus test unitarios sean rápidos. Principalmente, porque podrás ejecutarlos cada pocos minutos y eso te permitirá el conocer si hay algo que no funciona como esperas, casi al momento de escribirlo.
El principal problema de velocidad en los test es debido a que el código habla con la base de datos, con el sistema de archivos o que acceden a internet.
Para solucionar este problema puedes utilizar dobles de test, en vez de la clase que realiza este tipo de operaciones que tardan tanto en ejecutarse.
Escribir dobles de test es fácil pero en general se suelen utilizar librerías que hacen el trabajo por ti y te dan más opciones. En Java tienes muchas. En mi caso, utilizo JMock.

4. Fixture

Ten mucho cuidado al compartir variables y métodos entre test. Más de una vez no entendía porque un test fallaba o porque un test no fallaba y la razón era porque tenía compartía variables entre varios test unitarios.
La mejor forma de evitar esto es no compartir variables entre test. También se pueden compartir variables, pero para evitar estos problemas, inicializa las variables compartidas en el método setUp de la clase.

5. Test que no comprueba nada

Cuando veas el código de tu test tiene que estar más que claro cual es la manera de que falle el test. Por eso, si tienes un test sin ningún assert y sin manejar las excepción, ¿como vas a saber cuál es la razón de que ha fallado?
Creo que todo test tiene que tener de forma explícita cual es su razón de fallar.
Así, un test que no comprueba el resultado, que no verifica que un objeto colaborador se ha llamado o que no maneja las excepciones no tiene mucho significado.


lunes, 26 de enero de 2015

Cómo aprendí Test Driven Development





TL; TR

Busca a alguien con experiencia en TDD, empieza aprendiendo a escribir buenos test unitario, haz katas para aprender lo básico de TDD y después lánzate a hacer TDD en partes fáciles de implementar de tu aplicación.

Objetivo: como comenzar

El otro día (bueno, no fue el otro día, fue en octubre...) me preguntaron como he aprendido test driven development (TDD) y quería extenderme en la explicación y compartirlo por si a alguien le resulta de utilidad.

Como contexto, decir, que llevo un año practicando TDD y creo que tengo suficientemente fresco los primeros pasos que dí como para escribir este artículo.

Después de leer muchos blogs de como comenzar y de darle a la cabeza, me planteé aprender TDD en dos fases. Primero, aprender como escribir test unitarios (ver mi artículo anterior) y posteriormente TDD.

Lo hice de esta manera porque pensé (y todavía pienso) que TDD está muy vinculado con escribir test de forma correcta y sin una buena base debe de resultar más difícil el aprenderlo.

Primera fase: escribir test unitarios

Así que empecé a escribir test unitarios en casa después de haber aprendido lo básico sobre JUnit, la librería que se suele utilizar como estándar para escribir test unitarios.

Es muy importante que los test que escribas estén bien implementados, ya que solo hay algo peor que un código sin test unitarios, código con test con falso verde. Es decir, que no fallan pero porque no pueden fallar o porque hacen otra cosa diferente que lo que aparece en su nombre.

Después de unos meses escribiendo test me leí el libro Effective Unit Testing de Lasse Koskela y me ayudó radicalmente a mejorar mis test debido a que mientras me lo estaba leyendo recordaba los test que había escrito y como podía haberlo solucionado mejor gracias a los consejos del libro. Me ayudó principalmente en mejorar la legibilidad y la mantenibilidad de mis test.

Luego, empecé en el trabajo a escribir test y me resultó muy pero que muy complicado en muchos casos el escribir test.
Y en un punto me dí cuenta que el problema era que el código que había escrito no era testeable, ya que en un porcentaje muy alto, el código que no tiene test no era testeable. Como comenta Michael Feathers:

Código que no ha sido diseñado para ser testeable no es testeable. La testeabilidad no es cualidad que aparece accidentalmente.

Fue un palo grande pero, después de asumirlo, empecé con la tarea de escribir nuevo código diseñado para ser testeable y poco a poco empecé a hacerlo mejor.


Segunda fase: Test driven development

Al terminar de leer el libro Test driven de Lasse koskela (este tío es un gran escritor), decidí que ya era el momento de empezar con TDD y empecé a hacer katas / code katas.

Según la wikipedia, una kata es un ejercicio que ayuda a los desarrolladores a mejorar sus habilidades como programador.

Puedes encontrar muchos tipos de katas y de muchos niveles en Internet. En cuanto a las herramientas puedes utilizar tu IDE favorito junto con la versión que conozcas de Java y de Junit o puedes utilizar cyber-dojo

Cyber-Dojo es una aplicación web que permite escribir código en tu navegador, compilarlo y ejecutarlo. Además no es solo para Java, sino que permite muchísimos lenguajes como C, C++, C#, Clojure, Grovy y un largo etcétera.

Hice bastantes katas pero no muchas porque me resultaba aburrido el hacerlo solo.

El paso a practicar TDD en el trabajo fue lento. Básicamente, en las nuevas funcionalidades que desarrollaba le dedicaba partes de mi tiempo a practicar TDD. Poco a poco el tiempo a TDD fue creciendo hasta dedicarle todo el tiempo.

Recomendaciones 


  • Encuentra tu motivación. TDD es difícil de aprender así que tener una motivación te ayudará a seguir. Mi motivación consistía en reducir el número de errores en mi código. Siempre he dedicado un tiempo importante en mi trabajo a solucionar errores y estaba cansado que aunque ponía mucho empeño en solucionarlo de la forma correcta los errores que encontraba y en desarrollar nuevo código sin errores, siempre salían muchos.
  • Busca un mentor o alguien con experiencia en TDD. Te va a ahorrar más de un quebradero de cabeza y mucho tiempo. He aprendido TDD por mi cuenta porque nadie en mi entorno tenía experiencia y con diferencia lo que más eché de menos fue el no haber tenido a nadie a quien poder preguntar. Ahora pensando, a lo mejor hubiera podido haber utilizado Internet para buscar a alguien.
  • Haz cursos que te ayuden en avanzar. En mi caso, hice el curso de Carlos Blé sobre Test dobles y me ayudó a dar el salto a usar dobles de test de forma más activa en mi código.


Nota. Después de leer el artículo varias veces creo que he resumido mucho los pasos que he seguido. Si echas en falta alguna parte, solo tienes que preguntar :-)

miércoles, 14 de enero de 2015

Objetivos 2015

Pues ha pasado un año, ¡un año! Que se dice pronto.
La primera impresión que tengo al echar la vista atrás es que ha sido un año duro, duro e intenso pero en el que he aprendido mucho.

Primero quiero ver cuantos de mis objetivos del año pasado he cumplido y posteriormente el escribir una nueva lista con los nuevos objetivos.

En la siguiente lista aparece en color negro mis objetivos del año pasado y en rojo las conclusiones de si lo he conseguido cumplir o no:
  • Escribir un blog de forma regular: Para empezar con buen pie aquí tengo mi primer artículo que espero que sea el primero de muchos. Con un artículo cada dos semanas es más que suficiente. Empezamos mal. Este primer objetivo no he estado ni cerca. Escribir un artículo cada 2 semanas significa 24 artículos anuales y este año he escrito 8.
  • Aprender más lenguajes de programación: En la página code 2013 están realizando una gráfica con todos los lenguajes con los que está programando la gente. Al participar me he dado cuenta que no he aprendido nuevos lenguajes este año y que hay que remediarlo lo más pronto posible. Este tampoco. No he aprendido ningún lenguaje de programación nuevo y ni siquiera he hecho un amago de aprenderlo.
  • Utilizar de forma regular TDD: He estado aprendiendo mucho sobre TDD pero solo lo pongo en práctica de forma puntual y creo que ha llegado el momento de utilizarlo en mi día a día. Puedo decir que esta la he cumplido porque utilizo de forma regular TDD (test driven development), aunque no diariamente. Estoy muy contento de haber conseguido este objetivo porque ha sido duro. Si vas a aprender TDD es mejor tener a alguien que tenga experiencia.
  • Sentirme cómodo al hablar en inglés: Aunque hablo, escribo y leo en inglés de forma regular cada vez que hablo en inglés no me siento nada cómodo y hay veces que me pongo nervioso. Creo que es un problema de mi actitud y no del nivel que tengo. El cambio de empresa y el tener que comunicarme de forma diaria con un grupo mas o menos grande de gente me ha ayudado mucho a conseguir este objetivo. Así que lo voy a dar por conseguido.
  • Aprender Holandés: Al menos lo básico. Llevo viviendo aquí casi dos años y no entiendo casi nada cuando la gente habla. Me apunté a clases, que consistían en 2 días a las semana y 3 horas y cuarto cada día. Pero... no fui ni a la primera clase. Creo que no era el momento para aprender un nuevo idioma. Que no estaba preparado para aprender dos lenguas a la vez.
  • Hacer ejercicio: Cuando no hago ningún tipo de ejercicio lo noto y no solo físicamente. La bicicleta ayuda pero sin realizar algún otro deporte no es suficiente. Quiero correr un día a la semana e ir al gimnasio dos veces a la semana. No voy dos veces a la semana al gimnasio pero si que voy una vez. Me encuentro mejor no solo por el ejercicio, sino también por cuidar mejor lo que como. Podía ser mejor pero está bien. 

La nueva lista de objetivos, que aparece abajo, no va a variar mucho de la del año pasado:
  • Escribir en el blog de forma regular: dos artículos a la semana. Ahora sé que me voy a tener que esforzarme mucho para conseguir este objetivo pero seguro que merece la pena el lograrlo.
  • Aprender más lenguajes de programación: voy a intentar Groovy y/o Scala. Todo el l tiempo que le he dedicado a TDD lo puedo dedicar a aprender nuevos lenguajes.
  • Aprender Holandés: he aprendido la lección. Voy a intentar coger un curso que no me ocupe mas de un par de horas a la semana.
  • Hacer ejercicio dos veces a la semana: mi vida ha mejorado haciendo ejercicio así que hacer mas ejercicio seguro que lo mejora más.
  • Mejorar mi pronunciación al hablar en inglés: tengo los típicos problemas de pronunciación de los españoles y alguno propio. Creo que mejorándolos me ayudaran a comunicarme mejor.
  • Aplicar agile prácticas en mi día a dia. He leído bastantes libros sobre metodologías ágiles y creo que ya ha llegado el momento de aplicar lo aprendido.
En resumen, de los objetivos he conseguido cumplir dos. No son muchos pero estoy contento, podía haber sido peor :-)

Este próximo año espero poder aprender al menos la mitad de lo que he aprendido en 2014.