lunes, 26 de diciembre de 2011

Maven

No sé bien cómo definir Maven. En la red hay numerosas descripciones, pero no me termina de de convencer ninguna.

Maven es un gestor de plugins. Lo que ocurre es que estos plugins están muy orientados a esas tareas tediosas y repetitivas que necesitamos para construir nuestro software: compilar, empaquetar, resolver dependencias, probar, generar documentación, gestión de versiones, publicar nuevas releases, ...

Maven está pensado en Java y para Java. Pero hay plugins para usarlo de otras maneras. Y si no te convence... Puedes hacerte tu propio plugin.

lunes, 19 de diciembre de 2011

Retrospectiva 2011, Sprint 2012

Hace un año, me fijé unos objetivos para todo el 2011. He cumplido poquitos, pero estoy contento. Voy a valorarlos y a fijarme nuevos objetivos para este año que comienza.

Tuenti

Sé que tengo muchos amigos esperando a que escriba esta entrada, así que... ¡no me hago de rogar más!

¿Cómo me cogieron en Tuenti? Temo que seré algo vago en algunos aspectos, ya que me parece feo dar cierta información, pero también creo que será una entrada interesante.

jueves, 15 de diciembre de 2011

10.000 visitas

Hola!!

Pues tan sólo quería agradeceros a todos por leerme, ya que hemos sobrepasado las 10.000 visitas a la web.

Sinceramente, me parece increíble, ya que lleva activada desde Julio.

¡¡Gracias a todos!!

miércoles, 14 de diciembre de 2011

Cómo transformar un proyecto Netbeans en uno Maven

Últimamente estoy pasando muchos proyectos de Netbeans a Maven, con las ventajas (e inconvenientes) que esto supone. Así que he decidido compartir con vosotros los pasos que suelo seguir y, ya de paso, me hago una chuleta :D

lunes, 12 de diciembre de 2011

Un día en Codice Software

Creo que fue en septiembre cuando vi la mejor oferta de trabajo que he visto en mi vida, en Codice Software, y no pude evitar echarles el currículum. Eso es lo que tienen las acciones sin pensar: que asumes muchas cosas que no tienen por qué ser así.

viernes, 9 de diciembre de 2011

Virtualbox: qué hacer cuando no tienes tu vboxdrv

Bueno, ésta es una minirreseña para apuntarme lo que tengo que hacer cuando pierdo mi vboxdrv y virtualbox deja de funcionarme.

Tengo que apuntármelo porque ya me ha pasado varias veces y he perdido algunas horas, con lo fácil que es hacer:

# dpkg-reconfigure virtualbox-dkms 

En fin.. lo mismo alguien también lo encuentra útil.

lunes, 5 de diciembre de 2011

Code Coverage o cómo engañarte a ti mismo

Viene siendo muy habitual pensar que las pruebas son sinónimo de corrección y que es importante tener una gran cobertura de código. Voy a tratar de demostrar que esto no es así.

Ojo... con ello no digo que estén mal, sino que es necesario saber de qué estamos hablando. Yo soy partidario de un número de pruebas adecuado y de un porcentaje de cobertura... suficiente.

Si está probado, funciona

Sabemos que está probado, pero... ¿cubrimos todos los casos de uso? ¿Hemos cometido un error en las pruebas? ¿Se ha modificado el código después de realizar las pruebas?

Pasar las pruebas no es sinónimo de correctitud. No pasar las pruebas sí es sinónimo de error. El error puede estar en las pruebas o en el código, pero es una llamada de atención sobre aquéllo que debemos revisar.

Si encontramos un problema no contemplado en las pruebas, deberíamos añadirlo a la batería para que no vuelva a ocurrir.

Cobertura del 100%

Una cobertura de código amplia no puede ser mala. Lo malo puede ser no saber cómo interpretarlo.

Nuevamente, no podemos tomar por buena la definición en positivo, sino que hay que tomarla en negativo: No significa que cada línea de código por la que pasamos esté probada. Signfica que cada línea de código por la que no pasamos, no está probada en absoluto.

Por poner un ejemplo muy sencillo: Tenemos una simple división de tipo : "a / b". En esta operación, "a" vale 3 y "b" vale 1. El porcentaje de cobertura es del 100%, pero es evidente que fallará cuando "b" valga 0.

Conclusión

Así que las pruebas están bien, y la cobertura está bien, pero sólo si sabemos realmente lo que significan.

¿Cuál es el porcentaje de cobertura adecuado? Todos sabemos que el porcentaje bueno de cobertura es el 80%, ¡¡y no menos!! (traducido por mí, si queréis)

domingo, 4 de diciembre de 2011

Code Retreat Global Day: Retrospective

Yesterday was the day.

I had been waiting for it for a long time. Lots of people join together all around the world to improve their skills as Developers.

I had the chance of attending the Madrid meeting. It was carried on by Enrique Comba. There I found a lot of people that I met first time in another Code Retreat, a year ago. I met new people too.

My first thought was that I must not to be there. I already have been practising the 'kata' and I already knew the result. But some time later, realize that the solution doesn't matter. It is the people who matters. It is more important to speak with them, to think with them. It doesn't matters if you get the answer. The real important thing is that you met another people, and each of them allows you to see the same problem from another perspective.

I learnt a lot. I realize I was trying to solve the problem by my own, without my mate. In another team, we didn't write a lot of code, but we could think about the mistery of life. In another one, the same happened, but about the abstraction of the problem.

It was a very short day, and it was a very important opportunity to meet some people who does mind about our job, about computer programming.

And I feel lucky for having been there.

Thank you all, organization teams, mates, friends. Thank you for your comments or your thoughts, for your your words.

See you soon.

viernes, 2 de diciembre de 2011

Python: Cómo hacer pruebas 5: freshen

Después del éxito cosechado con el artículo "Python: Cómo hacer pruebas (4)", no puedo evitar aprovechar el tirón y subir el nivel: BDD, o, lo que es lo mismo, Business Driven Development.

Éste va a ser un tema muy arriesgado, ya que en mi vida he conseguido hacer BDD para... el ejemplo que os voy a mostrar. No lo he usado nunca más, aunque me parece bastante interesante el tema.

Aún me guardo un temita en el tintero para otro artículo. Lo dejaré como una sorpresa :D

Qué vamos a utilizar

Hay un montón de formas de hacer BDD. En Python también. Sin embargo, parece que Cucumber se ha transformado en un estándar, aunque es Ruby y no Python.

He estado buscando mucho, evaluando posibilidades como PyHistorian, PyCukes, Lettuce, ... Pero ninguno es paquete Debian. Eso no es un problema, claro, porque puede usarse PyPi o empaquetarse a mano, pero sabía yo que podía encontrar algo mejor.

Finalmente, lo he encontrado y... es paquete Debian. Se trata de python-freshen. ¿Y cuál es la mejor característica de esta pequeña maravilla? ¡Pues que se utiliza como un plug-in para nuestro amito nose, al cuál dediqué un artículo!

Así que es requisito indispensable tener instalado python-freshen, el cual ya tiene como dependencia a python-nose, por lo que nos vale.

El problema

Como sabéis, explico mediante ejemplos. En esta ocasión no va a ser menos. El ejemplo que voy a ejecutar es el conocidísimo problema de fizzbuzz. Resumiendo: imprimir los valores hasta uno dado, sustituyendo los múltiplos de 3 por "fizz", los de 5 por "buzz" y los de 3 y 5 por "fizzbuzz".

Estructura de ficheros

Lo primero y más importante es ver cómo deben quedar los ficheros que vamos a escribir más adelante. Tendremos 3 ficheros, repartidos en dos directorios. Podéis situar el directorio raíz donde queráis:

.
├── features
│   ├── fizzbuzz.feature
│   └── steps.py
└── fizzbuzz.py

Para ejecutar las pruebas, nos situaremos en el directorio raíz (donde se encuentra "fizzbuzz.py") y ejecutaremos nose, con la opción --with-freshen:

$ nosetests --with-freshen .

----------------------------------------------------------------------
Ran 0 tests in 0.000s

OK

Podríamos usar también la opción -v para que nos cuente qué test está ejecutando. No he conseguido que sea todo lo bueno que me gustaría, pero... me vale.

Y ahora es cuando creamos los archivos.

Archivo features/fizzbuzz.feature

Este archivo va a especificar nuestro problema, desde un punto de vista funcional y en lenguaje casi natural. Si os lo curráis un poco podéis especificarlo en vuestro idioma, pero... lo siento; en castellano me suena raro y complicaría la explicación, así que lo pongo en inglés:

Feature:
  In order to check my fizzbuzz implementation
  I want to recover the list of fizzbuzz numbers up to 15

  Scenario Outline: Get the list of first values
    Given a <number>
    When you calculate the result
    Then it returns a vector with the <result>

  Examples:
    | number | result                                                                                   |
    | 1      | [1]                                                                                      |
    | 2      | [1, 2]                                                                                   |
    | 3      | [1, 2, 'fizz']                                                                           |
    | 4      | [1, 2, 'fizz', 4]                                                                        |
    | 5      | [1, 2, 'fizz', 4, 'buzz']                                                                |
    | 6      | [1, 2, 'fizz', 4, 'buzz', 'fizz']                                                        |
    | 7      | [1, 2, 'fizz', 4, 'buzz', 'fizz', 7]                                                     |
    | 8      | [1, 2, 'fizz', 4, 'buzz', 'fizz', 7, 8]                                                  |
    | 9      | [1, 2, 'fizz', 4, 'buzz', 'fizz', 7, 8, 'fizz']                                          |
    | 10     | [1, 2, 'fizz', 4, 'buzz', 'fizz', 7, 8, 'fizz', 'buzz']                                  |
    | 11     | [1, 2, 'fizz', 4, 'buzz', 'fizz', 7, 8, 'fizz', 'buzz', 11]                              |
    | 12     | [1, 2, 'fizz', 4, 'buzz', 'fizz', 7, 8, 'fizz', 'buzz', 11, 'fizz']                      |
    | 13     | [1, 2, 'fizz', 4, 'buzz', 'fizz', 7, 8, 'fizz', 'buzz', 11, 'fizz', 13]                  |
    | 14     | [1, 2, 'fizz', 4, 'buzz', 'fizz', 7, 8, 'fizz', 'buzz', 11, 'fizz', 13, 14]              |
    | 15     | [1, 2, 'fizz', 4, 'buzz', 'fizz', 7, 8, 'fizz', 'buzz', 11, 'fizz', 13, 14, 'fizzbuzz']  |

Realmente este archivo se creará poco a poco, añadiendo un "Ejemplo" cada vez.

Lo más importante de aquí son los comienzos de las líneas: las palabras "Feature", "In order to", "I want", "Scenario Outline", "Examples" y, sobre todo, "Given", "When", "Then".

Hay libros escritos sobre este pseudo lenguaje, así que os dejo que echéis un poco de imaginación o que busquéis en la documentación. Siento no poder explicarlo aquí.

Como se puede observar, a parte de tener un poco cuidado con las palabras con las que empezamos cada línea, es casi lenguaje natural. Según el caso, se puede conseguir un lenguaje natural completo.

En teoría, este archivo podemos enseñárselo al cliente e, incluso, pedirle que nos ayude a construirlo. Con el tiempo, podría llegar a crearlo el propio cliente.

features/steps.py

En este archivo vamos a utilizar expresiones regulares para emparejar las definiciones del archivo features con nuestro programa principal.

Veamos qué aspecto queda:

from freshen import *
from freshen.checks import *

from fizzbuzz import *

@Given('a (\d+)')
def create_data(number):
    scc.number = int(number)

@When('you calculate the result')
def calculate():
    scc.result = fizzbuzz(scc.number)

@Then('it returns a vector with the (.+)')
def check_result(pattern):
    assert_equal(pattern, str(scc.result))

Como puede observarse, realizamos operaciones para Given, When y Then, pasando a los decoradores un parámetro que es la expresión regular que debe cumplirse para ejecutar el propio test.

En nuestro caso, he utilizado una variable de freshen para almacenar mis datos. Existen 3 variables posibles:

  • glc o Global Context, que se mantendrá durante toda la ejecución actual.
  • ftc o Feature Context, que se mantendrá durante esta característica.
  • scc o Scenario Context, que se mantendrá durante este escenario.

En las funciones lo que hago es almacenar el valor inicial, calcular el resultado y comprobar que el resultado es lo esperado, respectivamente.

Se puede observar cómo los matchings de las expresiones regulares se transforman en parámetros de nuestras funciones.

fizzbuzz.py

Finalmente, el archivo solución del problema que, en este caso, es lo que menos nos interesa, pero lo incluyo para que podáis probarlo todo junto:

def fizzbuzz(number):
    return [offuscate(x+1) for x in xrange(number)]

def offuscate(n):
    if n % 3 == 0 and n % 5 == 0:
        return 'fizzbuzz'
    if n % 3 == 0:
        return 'fizz'
    if n % 5 == 0:
        return 'buzz'
    return n

Ejecutando ahora...

Y cuando ahora ejecutamos, el resultado es más que satisfactorio:

$ nosetests --with-freshen .
...............
----------------------------------------------------------------------
Ran 15 tests in 0.031s

OK

Insisto en que con la opción -v se nos mostrará el nombre del escenario actual

Más información

Pues de python-freshen hay poco... algún ejemplo y poco más. Podéis mirarlo en su propia web.

Pero claro, podéis ver más cosas en la web de cucumber o buscar, directamente, RSpec

También podéis echar un ojo a alguno de mis antiguos posts relacionados con las pruebas: