Archive for May, 2011
Me complace anunciar la primera release de pyDoubles, nuestro framework de tests doubles para Python.
Como ninguno de los framewoks que estabamos usando me convencía realmente, empecé a programar uno yo mismo a modo de kata en un viaje de avión. Me enganchó tanto y le vi tantas posibilidades que me decidí a implementar todo lo que nos hace falta.
Sin TDD no creo que nunca hubiese conseguido un código que me guste tanto (por su claridad y su simplicidad) ni una batería de tests tan completa. A casi la mitad
del desarrollo, lo borré todo y lo empecé a hacer de nuevo. El resultado fue una mejora espectacular. Cuanto más estricto he sido con la práctica de TDD para este desarrollo, mejor resultado ha dado. Es un problema relativamente complejo el cual implica que dar un paso demasiado grande te provoca un código excesivamente complicado, rígido.
Os recomiendo que hagais alguna kata con Python y pyDoubles. Y también os recomiendo hacer vuestro propio framework de dobles a modo de kata. Bueno, al menos algunas partes
Estamos trabajando en corregir el texto en inglés de la web del proyecto que tiene muchos errores y tan pronto como esté listo lo anunciaremos en algunos foros de habla inglesa.
TDD is also the process of evolving from concrete to generalized solutions. In the firsts steps you write code to build a simple behavior based on a simple example. The simpler, the better. As you go discovering more examples, the code evolves through refactoring to implement all those behaviors. So at the beginning it had maybe one conditional statement, but then another one came into place and eventually the conditional was replaced with a loop, which turned out to be the generic code to handle all those examples.
A typical evolution can be seen in the primer factors kata (you can see the evolution in the video). There is a point where the conditional statements must be changed for a loop in order to make all the cases work.
However, too much generalization makes the code hard to change when new requirements come along and also hard to read and understand. The question is ... where do we stop generalizing?
Generalize just enough to make your current requirements work. Once the functionality has been developed, stop transforming the code towards a more generic solution. It will not add value but rather make the code dark.
I've seen an example recently during a workshop. After a bunch of tests passing and some refactoring, we had two classes, one extending the other (in the production code). Both were solving the same problem but with some particular differences. It worked fine and all the examples were green. However, we saw that they were using a dictionary and that, part of their distinct behavior could be moved to the dictionary class, applying a subtle change in the code. With that change, we could transform the class hierarchy into a single class and delegate to the dictionary. That would be a generalization step which wasn't needed but let us save some lines of code.
The problem making this generalization is that code starts loosing its meaning in terms of the domain. The implementation is too complex and it is talking about dictionaries with operations. It is no longer talking about two problems in the domain that were slightly different. It starts loosing its extensibility. With the class hierarchy, we had the chance to create a new class extending the existing (Open Close Principle) but with an apparently unbreakable algorithm, there is no obvious way to extend the behavior.
Do not refactor if you are going to loose business semantic!
Hei! Thanks to the great XP2011 staff, I've been able to present our job in the event. I told to the nice audience, the methods we are currently using in our web development to test-drive everything that can be done. I recorded the sound but as I was moving along the room, it is not good sometimes. Thanks also to all the attendees, which were really interested in the topic.
The audio file:
Keep an eye on podgramando.es, tomorrow will be published several podcasts recorded in the conference. It has been such a great event!!!
The prime factors kata, as described by Uncle Bob , contains deep lessons that can be learned by approaching it several times.
Here you can see one of my solutions:
The first time I solved the kata, it was very easy. I test-drove it very close to the video. A couple of days later I was the facilitator in a coding dojo and asked the folks to practice this kata. Dojo attendees couldn't accomplish the constraint of "don't use any loop until you have 4 green tests" that I proposed to them. At the end of the dojo I started coding the solution and I couldn't find an easy way to accomplish my own rule. I didn't finish the demo on time. So I started wondering why the process didn't work this time.
Very interesting lessons have been learned from this:
- Don't forget to triangulate depth-first
- Are you sure you can't refactor by now?
- If the problem seems to be an algorithm, choose a high level strategy before starting coding
In my demo, I wasn't very focused so I said to myself... "don't think, just embrace the TDD rules and go for them", so I started test-driving. The problem is that I didn't triangulate deph-first. I started jumping from one scenario to another but not finishing any of them. So I couldn't see a right way to refactor towards generalization. The code didn't tell me how to factor out towards the algorithm.
Even if you don't see the right triangulation, you must take the time to see what can you refactor. Bad triangulation scenario:
def factorize(number): result =  if number % 2 == 0: result =  if number == 3: return  if number == 4: return [2,2] if number == 6: return [2,3] return 
Even with this code, if you take to time to find out similarities, you can see that number 2 is a prime factor for others so that you can refactor:
def factorize(number): result =  if number % 2 == 0: if number != 2: return [2, number / 2] if number == 3: return  return 
From here, you can still success test-driving the algorithm.
I realized that it was easy for me the first time because I did choose a mental strategy before coding which was... "a number is prime if all the numbers below it can not divide it", which already was a loop strategy.
Here you can see a nice different by Angel Nuñez Salazar.
Thanks to all dojo attendees for their feedback