Go con TDD: Visibilidad y naming

Continuamos con la serie de aprendiendo Go Con TDD.
Esta vez el post va a ser un poco especial. Vamos a hablar de visibilidad de los métodos y de por qué Go es especial en ese sentido.
Además comprobaremos que tener buenos tests y saber utilizar un buen IDE nos permiten hacer cambios en nuestro software de manera sencilla.

Si recordamos solo en el primer post de la serio 1. “Aprendiendo Go con TDD” hemos escrito código ejecutable que no fuesen tests. En otras palabras, no hemos hecho ninguna función main todavía.

Sigue leyendo “Go con TDD: Visibilidad y naming”

A fondo con go: structs, interfaces

Si es cierto, en el post anterior ya hablamos de structs, pero es que todavía nos queda mucho por aprender.
Ya sabemos que los structs son colecciones tipadas de campos y además son muy útiles para agrupar datos juntos.
Así que partiendo del ejemplo anterior de geometría, donde tenemos un struct Triangle con un método para calcular su área
y un struct Rectangle con un método para calcular su área vamos a darle una vuelta de tuerca para saber que son las interfaces y como sacarles partido.

9713407427_90f5f069a8_z
Estación de Chamberí – Antonio Tajuelo

Sigue leyendo “A fondo con go: structs, interfaces”

Go con TDD: structs, methods y geometría

Es hora de dar un paso más con Go y que aprendamos a utilizar struct. Los struct no son más que colecciones de campos tipadas. El ejemplo típico es que tenemos el tipo de estructura de persona tiene campos de nombre como string y edad como integer.

type person struct {
    name string
    age  int
}

Por eso vamos a presentar un pequeño problema que iremos resolviendo haciendo test antes de tirar una linea de código de producción. TDD Style.

El Acebuche - Doñana (Huelva)
El Acebuche – Doñana (Huelva) https://www.flickr.com/photos/fuzzyyol/4719924395/

Supongamos que queremos implementar una calculadora geométrica, que calcule el área de un triangulo.

Escribiendo el primer test: area de un triángulo

package geometry

import "testing"

func TestArea(t *testing.T) {
    got := Area(12.0, 6)
    expected := 36.0

    if got != expected {
        t.Errorf("got %.2f expected %.2f", got, expected)
    }
}

Como ya aprendimos en el tutorial anterior: hemos creado una clase de test llamada geometry_test.go, hemos creado una clase para el código y ambas están en el mismo package llamado geometry. Por último también hemos creado el primer test, que como detalle especial tiene %.2f para indicar que vamos a imprimir un float con 2 decimales.
Ejecutamos el test y tenemos:

$ go test
# github.com/jeslopcru/golang-examples/03-geometry
./geometry_test.go:6:9: undefined: Area

Escribiendo el código

Si ejecutamos el test nos dirá que la función “area” no está definida. Creamos el fichero y definimos algo como esto:

package geometry

func Area(base float64, height float64) interface{} {
    return (base * height) / 2
}

Así de fácil. Ya tenemos nuestro código funcionando.

$ go test
=== RUN   TestArea
--- PASS: TestArea (0.00s)
PASS

Añadiendo la funcionalidad: calcular el perímetro

Ahora vamos a crear una función para perímetro de un triangulo. El perímetro de un triangulo es la suma de sus lados.

Ya sabemos cómo funciona TDD, así que cuando terminemos tendremos algo como esto en los tests:

func TestArea(t *testing.T) {
    got := Area(12.0, 6)
    expected := 36.0

    if got != expected {
        t.Errorf("got %.2f expected %.2f", got, expected)
    }
}

func TestPerimeter(t *testing.T) {
    got := Perimeter(12.0, 6, 6.0)
    expected := 24.0

    if got != expected {
        t.Errorf("got %.2f expected %.2f", got, expected)
    }
}

Al ejecutarlo dará error y ni siquiera compilará:

$ go test
# github.com/jeslopcru/golang-examples/03-geometry
./geometry_test.go:15:9: undefined: Perimeter

Con este error solo nos queda volver a verde escribiendo el código de producción tal que así:

// GIVEN base and height integers WHEN call Area function THEN result is the area of a triangle
func Area(base float64, height float64) interface{} {
    return (base * height) / 2
}

// GIVEN three side of a triangle  WHEN call Perimeter function THEN result is the perimeter of a triangle
func Perimeter(a float64, b float64, c float64) interface{} {
    return a + b + c
}

y al ejecutar los tests…

$ go test
=== RUN   TestArea
--- PASS: TestArea (0.00s)
=== RUN   TestPerimeter
--- PASS: TestPerimeter (0.00s)
PASS

Poco a poco hemos escrito documentación de todas las funciones que tenemos. Como ya comentamos en el post anterior estamos documentado las funciones que hacemos para que así la página de la documentación sea más rica.
Si además necesitamos añadir algún ejemplo a la documentación, solo tenemos que crear un test con prefijo example como vimos en el primer post de la serie

Refactorizando: Dando un poco de semántica

Como hemos comprobado, nuestro código funciona y hace lo que dice. Aunque no se lee por ningún lado la palabra Triangulo.

Una solución podría ser hacer más semánticas las funciones, es decir, en vez de llamara a la función “Area” que sea algo así como “AreaTriangulo”. Como la idea de estos pos es que aprendamos más sobre Go, vamos a optar por una solución más “encapsulada”, crearemos nuestro propio tipo: Triangulo el cual encapsulará todo estos conceptos para nosotros.

Vamos a crear tipo simple usando struct que será nuestra “colección” en la que vamos a guardar los datos.

type Triangle struct {
    a float64
    b float64
    c float64
}

Ahora tenemos que utilizar este nuevo tipo en el código. Cómo estamos haciendo TDD, vamos a empezar modificando los tests. Es importante ir dando “Baby stepts”,
es decir haciendo cambios muy pequeños en el código para que no empiece a fallar todo. La idea es ir ganado pequeñas batallas. Por eso vamos a empezar a modificar solo el test de perímetro:

func TestPerimeter(t *testing.T) {
    triangle := Triangle{12.0,6,6.0}
    got := Perimeter(triangle)
    expected := 24.0

    if got != expected {
        t.Errorf("got %.2f expected %.2f", got, expected)
    }
}

Si ejecutamos los tests obtendremos algo como esto:

$ go test
# github.com/jeslopcru/golang-examples/03-geometry
./geometry_test.go:15:14: undefined: Triangle
./geometry_test.go:16:18: not enough arguments in call to Perimeter

Vamos a modificar el código para añadir la estructura Triangle y la función perímetro para que acepte dicha estructura.

type Triangle struct {
    a float64
    b float64
    c float64
}

// GIVEN three side of a triangle  WHEN call Perimeter function THEN result is the perimeter of a triangle
func Perimeter(aTriangle Triangle) interface{} {
    return aTriangle.a + aTriangle.b + aTriangle.c
}

Con este cambio, ya podemos ejecutar nuestros tests y todo parece funcionar:

go test
=== RUN   TestArea
--- PASS: TestArea (0.00s)
=== RUN   TestPerimeter
--- PASS: TestPerimeter (0.00s)
PASS

Ahora vamos a por la siguiente batalla, calcular el área. Aunque antes tenemos que refrescar un poco de geometría… dados los 3 lados de un triangulo, el Área se calcula a través de la formula de Herón, no vamos a entrar en muchos detalles solo usaremos este ejemplo para los tests:

Sea un triángulo de lados conocidos, siendo estos a=4, b=5 y c=3. Su Área es 6

Screen Shot 2018-09-01 at 09.28.31.png

después de la pequeña clase de matemáticas, el test quedará algo así:

func TestArea(t *testing.T) {
    triangle := Triangle{4,5,3}
    got := Area(triangle)
    expected := 6.00

    if got != expected {
        t.Errorf("got %.2f expected %.2f", got, expected)
    }
}

Y al ejecutar los tests nos dirá que tenemos un error parecido al anterior:

$ go test
# github.com/jeslopcru/golang-examples/03-geometry
./geometry_test.go:7:13: not enough arguments in call to Area
    have (Triangle)
    want (float64, float64)

Así que ahora solo tenemos que modificar la función Area usando la formula de Heron. El fichero geometry.go quedaría así

package geometry

import "math"

type Triangle struct {
    a float64
    b float64
    c float64
}

// GIVEN three side of a triangle  WHEN call Perimeter function THEN result is the perimeter of a triangle
func Perimeter(aTriangle Triangle) interface{} {
    return aTriangle.a + aTriangle.b + aTriangle.c
}

// GIVEN base and height integers WHEN call Area function THEN result is the area of a triangle
func Area(aTriangle Triangle) interface{} {
    semiperimeter := (aTriangle.a + aTriangle.b + aTriangle.c) / 2
    radicand := semiperimeter * (semiperimeter - aTriangle.a) * (semiperimeter - aTriangle.b) * (semiperimeter - aTriangle.c)
    return math.Sqrt(radicand)
}

Y al ejecutar los tests tenemos algo así:

go test
=== RUN   TestArea
--- PASS: TestArea (0.00s)
=== RUN   TestPerimeter
--- PASS: TestPerimeter (0.00s)
PASS

Todo perfecto. Con esta refactorización hemos aprendido que podemos utilizar struct para “organizar nuestros datos. Ahora sabemos como crear un struct y como utilizarlo dentro de una función (operador . para acceder a los atributos).
Del mismo modo hemos importado la librería Math para poder ejecutar la raíz cuadrada (math.Sqrt(radicand))

Ahora nuestro nuevo requisito será que hagamos el cálculo del Area para un rectángulo. Pero antes haremos un commit porque todo está en verde.

Escribiendo el test para el Area de un rectangulo

Tan solo tenemos que añadir un caso a nuestro test:

func TestArea(t *testing.T) {

    t.Run("triangle", func(t *testing.T) {
        triangle := Triangle{4, 5, 3}
        got := Area(triangle)
        expected := 6.00

        if got != expected {
            t.Errorf("got %.2f expected %.2f", got, expected)
        }
    })

    t.Run("rectangle", func(t *testing.T) {
        rectangle := Rectangle{12, 6}
        got := Area(rectangle)
        expected := 72.0

        if got != expected {
            t.Errorf("got %.2f expected %.2f", got, expected)
        }
    })
}

Y obviamente al ejecutar nos dirá que rectángulo no está definido

go test
# github.com/jeslopcru/golang-examples/03-geometry
./geometry_test.go:18:16: undefined: Rectangle

Creando el código para pasar el test

Lo primero que haremos será crear el struct Rectangle

type Rectangle struct {
    a float64
    b float64
}

Si volvemos a ejecutar los test tendremos algo como esto:

go test`
# github.com/jeslopcru/golang-examples/03-geometry
./geometry_test.go:19:14: cannot use rectangle (type Rectangle) as type Triangle in argument to Area

En lenguajes como Java podríamos declarar otra función Area a que reciba como parámetro un Rectangle pero en Go… no podemos tener dos funciones con el mismo nombre.

go test
# github.com/jeslopcru/golang-examples/03-geometry
./geometry.go:31:33: Area redeclared in this block
    previous declaration at ./geometry.go:23:31

Tenemos dos opciones, crear un package nuevo para así podamos tener una función con el mismo nombre o definir methods en nuestros “tipos”

Methods o métodos

Hasta ahora solo hemos escrito funciones dentro del package y aunque no lo parezca hemos usado un method.
En los tests cuando llamamos a t.Errorf... estamos llamando al method Errorf.

Al fin y al cabo un method no es más que una función que está vinculada a algo (un receptor). Básicamente con el método asociamos una función a un tipo concreto.
Simplificando mucho, lo que vamos a hacer es crear una función dentro del struct. dicha función solo puede ser llamada por “objetos” (notemos las comillas) de ese tipo que hemos definido en el struct.

Así que lo primero será que escribamos los tests correctamente llamando a los methods así:

func TestArea(t *testing.T) {

    t.Run("triangle", func(t *testing.T) {
        triangle := Triangle{4, 5, 3}
        got := triangle.Area()
        expected := 6.00

        if got != expected {
            t.Errorf("got %.2f expected %.2f", got, expected)
        }
    })

    t.Run("rectangle", func(t *testing.T) {
        rectangle := Rectangle{12, 6}
        got := rectangle.Area()
        expected := 72.0

        if got != expected {
            t.Errorf("got %.2f expected %.2f", got, expected)
        }
    })
}

AL ejecutar los tests nos dice que “los method Area no están definidos”

$ go test
# github.com/jeslopcru/golang-examples/03-geometry
./geometry_test.go:9:18: triangle.Area undefined (type Triangle has no field or method Area)
./geometry_test.go:19:19: rectangle.Area undefined (type Rectangle has no field or method Area)

Ahora tenemos que añadir esos method dentro de los struct

func (triangle Triangle) Area() interface{} {
    semiperimeter := (triangle.a + triangle.b + triangle.c) / 2
    radicand := semiperimeter * (semiperimeter - triangle.a) * (semiperimeter - triangle.b) * (semiperimeter - triangle.c)
    return math.Sqrt(radicand)
}

type Rectangle struct {
    a float64
    b float64
}

func (rectangle Rectangle) Area() interface{} {
    return rectangle.a * rectangle.b
}

La sintaxis para declarar métodos es casi la misma que cuando declaramos funciones, la única diferencia es que en vez de usar this
o similar para acceder a los elementos, utilizamos el nombre del receptor.

Es una buena práctica que hagamos que el nombre de la variable del receptor empiece por la misma letra del tipo que hemos definido.
Por ello hemos cambiado el nombre de aTriangle a triangle y los mismo con aRectangle a rectangle

Al ejecutar los test tenemos:

$ go test
=== RUN   TestArea
--- PASS: TestArea (0.00s)
=== RUN   TestArea/triangle
    --- PASS: TestArea/triangle (0.00s)
=== RUN   TestArea/rectangle
    --- PASS: TestArea/rectangle (0.00s)
=== RUN   TestPerimeter
--- PASS: TestPerimeter (0.00s)
PASS

Todo funciona y ya podemos eliminar nuestra antigua función Area que Golang incluso la pone en color gris para indicarnos que no se utiliza.
Solo nos queda hacer un commit y listo.

Conclusiones

Hoy hemos aprendido a importar librerías (math) para poder utilizar funciones de otros paquetes. Del mismo modo ahora sabemos definir nuestros propios tipos con struct y además somos capaces de crear _methods` para los tipos. Con lo que tenemos un código mucho más estructurado.

Nuestro código es más semántico, está mas organizado utilizando struct y no hemos dejado de practicar TDD ni un solo momento.
¿Nos atrevemos a crear solos el área para un Circulo? ¿y que pasa con el perímetro, lo hacemos solos?

 

Poco a poco con Go y TDD: package, funciones, bucles, arrays y cobertura de test

Todo funcionando, $GOPATH, HelloWorld,… ahora vamos a hincar el diente de verdad a Go con TDD.
Crearemos una pequeña calculadora con la que aprenderemos a hacer un package, funciones, tocaremos un poco los arrays y además nos servirá para mejorar nuestras skills de TDD.

Empezando por los test

Para empezar con la calculadora, vamos a crear un package llamado calculator, así que creamos un directorio con ese mismo nombre (calculator) y nuestro primer fichero será calculator_test.go (TDD a tope).

*nota: solo puede existir un package por directorio

El código de ese primer test será algo así:

package calculator

import "testing"

func TestAdder(t *testing.T) {
    sum := Add(2, 2)
    expected := 4

    if sum != expected {
        t.Errorf("expected '%d' but got '%d'", expected, sum)
    }
}

Si nos hemos fijado un poco en el mensaje de error, vemos que ahora utilizamos %d en lugar de %s porque lo que queremos es imprimir por consola un número.

Si ejecutamos go test nos aparecerá que no esta definida la función Add

$ go test
# github.com/jeslopcru/golang-examples/02-calculator
./calculator_test.go:8:9: undefined: Add

Compilation finished with exit code 2
7997258366_7e77afa99d_z
Atardecer – Paula Gonzalez Perez

Sigue leyendo “Poco a poco con Go y TDD: package, funciones, bucles, arrays y cobertura de test”

Aprendiendo Go con TDD

Hace tiempo que quiero hincar el diente a Go, el lenguaje de Google. Empecé jugando un poco con exercism.io y creo que es hora de empezar Go con test. Vamos a intentar explicar como testear un ejemplo sencillo con Go, para más adelante evolucionar ese ejemplo con usando un enfoque de TDD. La idea es conocer como funciona el lenguaje: declarar variables, crear funciones, hacer test, usar constantes…

5803193649_18e29b5b0e_z
Micah Camara – Go

Sigue leyendo “Aprendiendo Go con TDD”

Cómo saber qué preguntas hacer en una entrevista

Pasar por un proceso de selección es algo complicado, inviertes tiempo, esfuerzo en hacer las entrevistas, las pruebas técnicas… ya hemos hablado antes de Preguntas sobre… en una entrevista a un “desarrollador” y Como preparar una entrevista de trabajo. Esta vez es diferente, estoy al otro lado y créeme cuando te digo que saber que preguntas hacer es más complicado de lo que parece.

Exif_JPEG_PICTURE

Sigue leyendo “Cómo saber qué preguntas hacer en una entrevista”

¿Cuánto vas a tardar? Técnicas para estimar

 

Estimar, ¿cuanto cuesta hacer esto?¿como lo estimamos? No tengo ni idea de como cuanto voy a tardar y predecir el futuro nunca ha sido lo mío.

Las técnicas de estimación “ágiles” son colaborativas, todas las personas involucradas en el proceso deberían colaborar. Del mismo modo, estas técnicas están pensadas para ser rápidas y que puedan repetirse en cada sprint. Y una de las cosas más complicadas es que deberíamos estimas en unidades relativas.  Esto significa que no intentamos estimar euros o en horas directamente. Así aprovechamos la capacidad humana para comparar cosas entre sí y evitamos la dificultad para comparar algo con un concepto abstracto (como euros u horas).

4806295665_8ee75ebb38_z

Planning poker

Cada miembro del equipo tiene una serie de tarjetas con los números de fibonacci (incluso hay apps https://play.google.com/store/apps/details?id=artarmin.android.scrum.poker&hl=es_419). Cada numero significa un peso/esfuerzo/complejidad. Lo que hacemos es exponer una de las historias de usuario para poder “estimarla”.
Sacamos cada uno una carta y esto nos sirve para dialogar y refinar esa historia. Es decir, si un miembro saca un 1 y otro miembro saca un 8 ,hay que analizar porqué esa diferencia y detallar más la historia de usuario, o incluso partirla.

Estimación por afinidad

La idea es construir un tablero con puntos de esfuerzo/peso/valor como columnas, e ir colocando las tareas en cada columna. Esta técnica se basa en que podemos estimar historias en base a sus semejanzas/diferencias con otras.

En realidad ni siquiera es necesario poner la puntuación en las columnas. Sino solo poner las tareas más pequeñas a la izquierda y las más grandes a la derecha. En base a esta ordenación podemos analizar si es necesario “cortar” las tareas más grandes.

Estimación por talla de camisetas

Para evitar la confusión de los puntos, o peor aún estimar en horas una técnica es estimar basándonos en tallas de camisetas. En este caso cada miembro del equipo ha de indicar si cree que la tarea a estimar es: XS (Extra Small), S (Small), M (Medium), L (Large), XL (extra-large) o XXL (Double Extra-Large).

Program Evaluation and Review Technique (PERT)

La idea es que todos los miembros del equipo estimen de manera numérica, por ejemplo usando “planning poker”. Usando esos puntos proporcionados por el equipo se aplica esta formula  (O+P+4M)/6  donde O es la más optimista, P es la estimación más pesimista y M es la media.

Magic Estimation

Creamos una tabla donde las columnas son los puntos de plannig poker. El equipo seleccionará una tarea que se usará como como referencias, lo que se hace con esta tarea es estimarla por lo que es crucial que todos conozcan dicha tarea así como sus implicaciones.

La mecánica es que por turnos en silencio, cada miembro del equipo tome una tarea y la coloque en una columna, si la tarea se va moviendo por distintas columnas se anotan los cambios. Al cabo de un tiempo las tareas con más movimientos son las que habrá que refinar.

Os dejo una pequeña app https://github.com/janpetzold/magic-estimation para implementar esta técnica.

Big/Uncertain/Small

Para hacer planificaciones rápidas, la idea es hacer 3 “montones de historias”: grandes, pequeñas y las que no tengo ni idea de como son. Esto puede servir en un primer momento tener una idea rápida del product backlog.

Dot Voting

No es una técnica de estimación en sí, pero puede servir. Cada miembro del equipo tiene un limite de puntos 10 y lo reparte entre las distintas tareas a estimar.

No estimar

El desarrollo software es, por su propia naturaleza, impredecible y no repetitivo. La idea es construir pequeñas piezas de software de manera iterativa e incremental que nos lleven lo más pronto posible a entregar valor sin dedicar horas a predecir el futuro.

Algunas consideraciones

Si estimamos en puntos de historia, ¿qué significa un 5? ¿y que un 13? Una manera por ejemplo es tener una historia común, conocida por todos los miembros del equipo y en base a esa tarea estimar. Por ejemplo, ¿cuánto pesa un pato?, No tengo ni idea, pero por ejemplo sé cuanto pesa un conejo, y podría “estimar” que un pato pesa los mismo que un conejo, en cambio si me preguntan cuanto pesa un cerdo… podría estimar que es 85 veces más pesado que un conejo.

Requisitos, tareas, historias, prioridades, objetivos,… distintas técnicas para priorizar un product backlog

Requisitos, tareas, historias, prioridades objetivos,… una de las cosas más difíciles a la hora de desarrollar un producto software no es la arquitectura, ni los test, ni siquiera el lenguaje de programación, los más complicado es saber que hacer en el momento adecuado. Qué tenemos que construir, por qué vamos a hacerlo, como lo haremos y que es lo que va primero.

Sí, estoy hablando de priorizar, de objetivos. Así que aquí voy a intentar descubrir algunas técnicas para priorizar un product backlog o al menos intentarlo. No vamos a entrar en detalle de como hacerlo, hay miles de recursos que seguro lo explican mucho mejor que yo, solo quiero tener una pequeña lista de técnicas y un par de pinceladas de cómo funcionan.

6350781099_18e39fc20e_z

Sigue leyendo “Requisitos, tareas, historias, prioridades, objetivos,… distintas técnicas para priorizar un product backlog”

Makefiles como dejar de memorizar comandos en docker – Developer Vago

Si has trabajado con docker, o si lo has probado, seguro que te has dado cuenta de la cantidad de comandos que tiene y la cantidad de opciones posibles. Para simplificarme un poco la vida he estado buscando información y lo que más util me resulta es crear un pequeño Makefile con los comandos que más utilizo.

making waves
Elizabeth Donoghue – making waves

Así que hoy voy a contar algunos trucos y consejos sobre Makefiles y para que veáis la cantidad de comandos que hay aquí os dejo la lista:

Sigue leyendo “Makefiles como dejar de memorizar comandos en docker – Developer Vago”

Aprendiendo VueJS sin hacer un TODO-List

El frontend cambia muchísimo, cada día salen frameworks nuevos, herramientas,… y por ello estar al día de todo es imposible. Pero eso no deja de lado que me apetezca mejorar mis habilidades de frontend y aprender un un poco como se trabaja con javascript más hallá de JQuery y de hacer Stackoverflow Driven Development.

37036473724_28163a121c_z
Matías Garrido – Flickr

Así que me he propuesto ir aprendiendo VueJS, porque creo que tiene una curva de aprendizaje bastante asequible y voy a ver resultados pronto sin demasiada frustración. Además hace tiempo que me encontré con este magnifico libro “Desarrolla aplicaciones con VueJS“, con el curso de CodelyTV sobre hacer TDD con VueJS y Jest y tuve la suerte de cruzarme con Dani Latorre de coding stones en la conferencia “Madrid Software Crafters” y charlar sobre VueJS, frontend actual y las charla que dieron en Codemotion.

Sigue leyendo “Aprendiendo VueJS sin hacer un TODO-List”