Archivos Mensuales: septiembre 2016

Estuvimos en la Tarugoconf

logo-tarugoconf

Artículo publicado originalmente en el blog de Codesai

¿Qué es la Tarugoconf?

El viernes pasado, 16 de septiembre de 2016, asistí como orgulloso representante de Codesai, al mejor evento posible que cupiese en la imaginación de David Bonilla: la Tarugoconf. Un evento que nunca hubiese existido si no le hubiesen dicho las tres palabras mágicas “No hay huevos” y que se construye bajo las siguientes premisas: Utilidad, Practicidad, Diversión y Calité.

Citando la web:

¿Qué carallo es esto?

Sólo 100 entradas a la venta. 1 sólo día, 1 sólo track y 1 sólo objetivo: crear el evento sobre construcción y comercialización de Productos Digitales más awesómico y gallego del mundo. Lleno de ponentes con muchos tiros pegaos en las barricadas del mundillo tecnológico y que, en sus charlas, intentarán responder una simple pregunta:

¿Qué cambiaría si pudiera volver 2 años atrás?

El previo

Invitacion Tarugoconf

Cuando presentó el evento por primera vez e informó que las entradas iban a ser por invitación, sabía que no iba a sentar bien y así fue. Escuché muchos comentarios y ninguno bueno; al que no le parecía innecesariamente exclusivo (como sinónimo de excluyente), le parecía que iba a ser carne delicatessen para trolls. Como reflexión David ya comentó, que para siguientes sólo una parte sería bajo invitación y el resto abierto a todo el mundo que quisiera venir.
A mi me parece un sistema tan bueno como cualquiera. Se quedó gente fuera, que hubiese pasado igual y en esta conferencia el tamaño sí importaba.

Ah! ¡Y el evento era dos días! Organizaron para el sábado una día de ‘networking family friendly’ realmente prometedor. No lo disfruté, será para la próxima.

El evento

Benvidos a la Tarugoconf!

Y llegó el gran día. Registro y café con bollos con un ambiente algo festivo. Había gente de todo el ecosistema: desarrollo, coaching, empresa, StartUps, … caras conocidas y no tanto que invitaban a saludarse. Había conexión.

Inaugura David con una minikeynote de 15 minutos en las que nos presenta la agenda, cosas prácticas como dónde estará la pulpeira, cómo ir a la fiesta por la noche y lo más importante, la motivación de la conferencia y por qué estamos aquí hoy. Fue un momento con un montón de energía que nos ponía en situación de lo que iba a venir.

Para hacer el resumen siguiente me voy a fijar en mis notas hechas con dibujitos. También podéis ver el trabajo de Javier (@oyabun) haciendo el Live recording del evento.

Comienza Javi Santana, CTO de Carto con “Crear software para empresacas que manejan pasta de verdad”.
La idea principal que transmite es que si quieres “gallina” hay que ir a por la empresa, a instalar “on premise”. El cloud, la solución SAAS tiene un rendimiento muy bajo. Luego tienes que montar un super-equipo: Soluciones (Ninjas), Sales, Soporte (aka psicólogos). Refuerza algo que ya sabemos, que no hay que parar de investigar, si paras te mueres. Y termina con un mensaje, que el dinero mola, pero divertirse más.
Me gustó mucho, divertida, bien estructurada y conceptos claros.

Quest y regalinos

A continuación le toca a Jorge Galindo, Product Manager de 47 Degrees, una empresa que hace software para todo el mundo desde sus oficinas al lado de la Peña Camarón, en Puerto de Santa María, Cádiz, con un par. Su charla se tituló “Emprender en provincias”.
Nos contó la historia de cómo llego 47 Degrees (latitud de Seattle) a Cádiz. Como pasó la empresa por lo estados de “mundo de piruleta”, “hecatombe mundial” y a quedarse sin pasta. Desde Cádiz se tuvo que reinventar empezando en corto, consiguió llegar a empresas de Madrid tirando de networking y les fue muy bien (por aquí pasó muy rápido, me hubiese gustado saber un poco más de este éxito). Pero entraron en un bucle de mucho curro y poca pasta que les obligó a fijar un punto de no retorno en el tiempo en el que buscarían otra cosa.
Estando Raúl Raja de vacaciones en Cartagena, leyó un artículo sobre Scala, llamó inmediatamente a Jorge para decirle que tenían que cambiar a Scala ya. Y él le respondió: “¡Del tirón!… ¿Cómo dices que se escribe?”. Aparte de la broma encontraron un nicho en la programación funcional que a base de investigar, mucho open source y atraer talento, les salvó el c… ¡Hicieron hasta un framework!
¿Qué cambiaría Jorge? Detalles, porque estás donde estás gracias a todas las experiencias. La pregunta que te tienes que hacer es si te gusta lo que eres y lo que estás haciendo.

Alguna idea: Todos los viernes mandan un correo a todo el mundo con información de en qué proyectos están y a menudo organizan actividades para todo el mundo.
Les preocupa crecer por encima de 30, por si se pierde la “magia” (palabras literales), tema que me suena bastante.
Charla muy potente, con buen ritmo. Quizás en la historia hay algún hueco que creo que se podría profundizar porque daría claves de cómo emprender desde fuera de Madrid, algo muy interesante para Codesai, sin duda.

Antes del café una minicharla de IBM, en la que muestra la arquitectura de Cloud e IoT que hay detrás de mover un BB-8. Un toque geek molón rápido y a la yugular.

Ponentes de la mañana

Después del café empieza Jimena Catalina, con la charla “Sácale provecho a tu diseñador” (aunque en el programa era “La culpa SIEMPRE es del diseñador”). Jimena es Diseñadora visual freelance y tiene proyectos propios como Recetas de Rechupete. Me gustó escuchar a alguien más pegado al proceso de desarrollo que veo día a día.
Nos explica que es fundamental que el diseñador entienda el proceso de negocio. Hay que trabajar muy cerca del equipo, porque no sólo es diseñarlo, es colaborar en lo que luego hacen con él.
Destaca la importancia de un buen feedback, e intentar hablar del concreto, o qué se quiere conseguir, no de emociones.
La mejor frase: “Diseño NO es arte, no expresamos nuestras emociones. Somos artesanos al servicio, resolvemos necesidades”

El toque de inversor potente vino a cargo de Juanjo Mata. Español en los USA desde hace 25 años con un acento para pronunciar el inglés que cuando lo oyes piensas: “A este seguro que le entienden”. David dice que es gallego, pero Juanjo mencionaba mucho a Toledo, no se porqué. En su twitter dice que es COO en Teambox.
“Si quieres vender necesitas un VP de Ventas” y nos mostró una tabla de sueldos mareantes, todos con seis cifras. Comentó que en USA dan dinero por un 5% y te dejan trabajar y que en España siempre quieren influenciar en el negocio. Y expresó con impotencia que es muy difícil montar allí un equipo tecnológico estable, hay tanta oferta que se van a los dos días, lo que es un problema para conseguir ritmo.
Fue una charla muy técnica, llena de siglas que no recuerdo y me enteré de muy poco, cosa que me hizo preguntarle: “Como técnico que ayuda a Startups, ¿debería aprender más de inversión, en vez del siguiente framework?”. Su respuesta fue que solamente si quieres, aunque alguien tiene que saber de todo esto en la empresa.

Ya oliendo el pulpo vino Molpe (Alberto Molpeceres), que se ha especializado en que tu negocio pueda cobrar online, con su charla que en la agenda venía como “Lo que diga Molpe” y que él renombró “Family Business”.
Nos dejó a todos destrozados. Una reflexión muy profunda de lo que significa (¡y lo que cuesta!) conciliar de verdad.
Cinco puntos:

  1. Distingue trabajo de hogar, que no te vean todo el día al ordenador.
  2. Agenda compartida, respeta los huecos comunes, no pongas la empresa como excusa.
  3. Las distancias importan.
  4. Todos o ninguno, intenta que los eventos sean un viaje familiar.
  5. Todo el mundo juega un rol. Involucra a todo el mundo en tu trabajo, en tus éxitos, en tus preocupaciones.

El turno de preguntas convirtió la sala en una terapia de padres y madres expresando sus problemas en el día a día en un nuevo escenario para muchos.
No se si fue la mejor charla, pero sí la que más voy a recordar. Por lo inesperado del tema y lo bien tratado. Me llevo un montón de ideas para implementar en casa.

La comida tremenda. La cantidad de pulpo, empanada, tortilla que me pude comer, sólo se queda pequeña comparada con la que desearía haber comido. Muy buen lugar, en un solar al lado del Campus, y muy buen ambiente para seguir saludando a los que todavía no habíamos podido.

Zona de la comida

Después de comer Inés Luna, experta en atención al cliente con la charla “Usuarios, clientes y animales ¿Son todos iguales?”
Se centró en lo importante que es tener un buen equipo de soporte, que además esté muy en contacto con producto, tanto para saber cuándo salen las siguientes funcionalidades, cuando se resolverán ciertos errores o para dar ideas.

A continuación Diego Mariño con “Así crearía Ducksboard en 2016”. Diego fue fundador de Ducksboard, que fue adquirida por New Relic, de la que ahora es Principal Product Manager.
Diego charló con el público más que una presentación. Habló de sus experiencias en Ducksboard y en USA. Buen ambiente vespertino.

Y para terminar subió al escenario Jesús Monleón para hablar de “Cómo montar un equipo comercial para salir a vender con el cuchillo entre los dientes”. Jesús es inversor en SeedRocket y fundador de Offerum entre otras, siempre como responsable del equipo comercial.
Jesús nos llevó a sus inicios en eMagister con unas historias desternillantes sobre cómo se consigue vender algo. Entre mucho humor negro nos contó con detalle las interioridades de un equipo comercial.
Una charla muy personal y a veces dura que puso buen broche a las ponencias del día.

Ponentes de la tarde

Y después del zumo terminamos con la Mesa Redonda de Medios Digitales: “la vida más allá de la publicidad y el CPM”
Conversación claramente para iniciados en el mundo del contenido y lo que significa ganar dinero con gente que viene a verte sin tener que cobrarles. En general estaban bastante alineados.

Despedida

¡Y va terminando el evento!
Bonilla se sube a la palestra y nos cuenta los datos internos económicos de la Tarugoconf. El resultado sale positivo, pero nos aclara que es porque no ha tenido que pagar por varias cosas: como la sala (gracias a Campus Madrid), la web del evento (gracias a Space Nomads) y algo tan increíble como los vuelos de Juanjo Mata y Diego Mariño desde EEUU, ¡que se los pagaron ellos mismos! Así que si contase con todos esos gastos el evento perdería mucho dinero.

A continuación da las gracias especialmente a Candela, Yerai y Jero.

David dando las gracias al final

Nos comparte la certeza de que los eventos “de autor” son el futuro: Línea editorial, Experiencia, Networking y conseguir Leads valiosos, por encima de un CFP genérico y hacer branding personal.

Sobre si habrá Tarugoconf 2017, dice ahora mismo no le apetece, pero que sabe que alguien pronunciará las tres palabras mágicas… así que se despidió “¡Hasta el año que viene!”.

Bola extra

Javier Alonso (@oyabun) hizo un trabajo magistral, haciendo el ‘Graphic Recording’ de todo el evento. Impresionó a todo el mundo. ¡Gracias y Enhorabuena!

graphicrecording

Feedback

Me acaba de llegar un correo en el que David nos pide feedback, lo dejo por aquí también:

Para repetir:

  • Tiempo para preguntas. 30 minutos de charla y 15 de preguntas.
  • El buen ambiente entre los asistentes, cada charla fantástica.
  • La tortilla caliente y poco cuajada.

Para mejorar en la siguiente:

  • Un pequeño break entre charlas. Cinco minutos para despejar la mente.
  • La promesa de salir del evento con 10 contactos hiper-curated creo que no se cumplió. Seguro que no lo di todo conociendo gente, pero creo que si uno de los objetivos era ese habría que intentar alguna idea más para el año que viene.

En resumen

Muy potente, mucha energía, un ambiente espectacular donde podías encontrar a un montón de compañeros y a los que no conocías sabías que iban a ser igual de interesantes; un conjunto de ponentes muy cuidado y con una presentación robusta  y con mensajes e ideas claras.

Una gran oportunidad para poder aprender de gente que se ha pegado muy duro y con ideas para llevar para aplicar desde ya.

llegada

Fotos

Live Sketching de Javier (@oyabun)

Mis notas #sketchnoting

Fotos oficiales de la Tarugoconf

Mis fotos

Etiquetado , ,

Experiencias con la Kata del Juego de la Vida de Conway

screen-shot-2016-07-17-at-7-06-44-am

Conway’s Game of Life

He hecho la kata del Juego de la Vida de Conway de un par de maneras: inside-out y outside-in.

La primera forma ha sido TDD inside-out en Javascript con Karma, Mocha y Chai, y la segunda TDD outside-in con Groovy y Spock. Ahí dejo enlaces al Github donde se ve en cada commit qué decisiones he ido tomando siguiendo el ciclo:
ROJO -> VERDE -> REFACTOR.

Si te interesa, para ver una buena explicación de las diferencias de hacer TDD inside-out e outside-in, puedes leer este post: TDD: Outside-In vs Inside-Out en el fantástico blog de Adictos al Trabajo, o éste (en inglés): TDD – From the Inside Out or the Outside In?. de 8th Light.

Experiencia

Me ha sido mucho más sencillo programar el primer intento. Creo que al hacerlo inside-out y siendo que lo que hay que programar es un algoritmo, fue mucho más fácil ir separando la parte del cálculo de las reglas, de la de flujo del programa.

Empecé por las condiciones que hacían que una célula viviese o no en la siguiente iteración, y poco a poco fui yendo hacia fuera hacia la composición de la malla del universo en el que vivían las células y terminando con el bucle que recorría la malla.

La segunda iteración me resultó mucho más difícil. Elegí Groovy para probar también con un lenguaje Orientando a Objetos, y así las clases me ayudasen a delimitar mejor las responsabilidades de cada componente.

Tuve en la cabeza sobre todo el Principio de Responsabilidad Única, que cada clase gestionase sólo aquello que tenía sentido para ella.

Intenté no caer en la trampa de programar abstracciones muy genéricas, pensando el típico: “para que sea fácil cambiar esto por aquello”.

Pero sí que programaba desde el inicio respetando el Principio de Inversión de Depedencias, y al inyectar siempre los colaboradores a las clases, permite hacer TDD con Mocks de manera muy transparente y natural.

// Spock test helper to create GameOfLife class
 GameOfLife createGol() {
     def nextService = Stub(NextService)
     def nextGrid = createSeed()
     nextService.next(_) >> nextGrid
     createGol(nextService)
}

GameOfLife createGol(nextService) {
    new GameOfLife(nextService)
}

Digo ‘pero’ porque mockear todos los colaboradores antes de programarlos, para tener los tests en verde me llevó a un bug bastante difícil de cazar que explicaré más adelante.

En la revisión de código vimos que aunque los mocks ayudan a esa parte, tienes dos problemas:

  • UNO: que mockear todo puede tener el efecto que realmente no estás probando nada.
  • DOS: que al hacer un Stub, tienes que conocer la firma qué devuelven los colaboradores y eso produce un acoplamiento importante en fases muy tempranas.

También quiero destacar que tomé una decisión bastante interesante: el sistema no tenía por qué conocer en qué tipo de estructura de datos se almacenaba el grid en el que vivían las células y sólo se debían comunicar con el responsable a través de un API, que mostraba una topología de consenso.

Esto tiene mucho sentido, ¿verdad? Para ponerme a prueba, en vez de almacenar las células en un array bidimensional, decidí almacenarlas en un vector, en el que la matriz estaría almacenada por filas.

class Grid {
    int rows
    int columns
    def data = new ArrayList()
    ...
}

Para acceder a cada posición [row, column], había que hacer un cálculo de paginación, en el que las filas eran la página y las columnas el offset.

GridItem get(row, column) {
    if (row < 0 || row >= this.rows ||
        column < 0 || column >= this.columns) {
            throw new IndexOutOfBoundsException("Position requested out of grid")
     }
     return this.data[row * this.columns + column]
 }

No exponer las interioridades, hacía que el sistema más exterior que se encargaba de recorrer el grid, no pudiese hacer un bucle de manera normal.

Entonces se me ocurrió que podía imitar el comportamiento de un tipo iterable.
Esto es, para pedir la siguiente posición había que pedirla al objeto responsable. Esto me llevó a tener que mantener la posición de lectura en el propio objeto, y por tanto mantener estado.
Esto no me gustaba nada, pero como era una kata, seguí adelante para ver las implicaciones.

Y según avanzaba la programación encontré un bug bastante gordo relacionado con mockear todas las dependencias de los test unitarios. Si pedía el grid.next(), y al leer avanza el cursos una posición, y luego pedía los vecinos, estaba leyendo no los que yo pensaba, sino los de la posición siguiente.
Así que tuve que crear un método que se llamase getCurrent(), calcular los vecinos y al final usar el next(), ya en este caso solo para avanzar posición.

class NextServiceImpl implements NextService {
    ...
    Grid next(Grid seed) {
        GridItem item
 
        Grid nextGrid = new Grid(seed.rows, seed.columns)
 
        //  found a bug in calculating neighbours after next
        //   we should separate this in current() and next()
        while (item = seed.current()) {
            def numNeighbours = seed.countNeighbours()
            def nextItem = alg.calc(item, numNeighbours)
            nextGrid.push(nextItem)
            seed.next()
        }
        return nextGrid
    }
}

Mantener la decisión del iterable me costó bastante, la verdad.

A posteriori creo que no merece la pena en este problema abstraer cómo se almacena el sistema y después leyendo el libro, veo que expone al máximo nivel la estructura de datos, o por lo menos la topología.

Conclusión

La kata inside-out, fue mucho más satisfactoria, pues veía mucho mejor el problema que tenía que resolver y construía el sistema desde la base.

La kata outside-in me ha ayudado a ver el big-picture mucho mejor, y darme cuenta de dónde están las responsabilidades, sobre todo al hacer TDD. Como dato interesante, encontré más bugs y más difíciles de resolver.

En definitiva, ejercicio interesante. ¡Espero poder participar en el Global Day of Coderetreat el próximo 22 de octubre de 2016 desde Asturias!

Etiquetado , ,

Recorriendo poco a poco el libro “Understanding the 4 rules of simple design”

cover

 

Artículo publicado originalmente en el blog de Codesai

 

Kata del Juego de la Vida de Conway

En mis primeras semanas en Codesai he hecho la kata del Juego de la Vida de Conway como parte de mi formación para empaparme de la cultura y valores de la empresa.

La hice dos veces: la primera ha sido TDD inside-out en Javascript con Karma, Mocha y Chai, y la segunda TDD outside-in con Groovy y Spock. Dejo aquí mis enlaces al github donde se ve en cada commit qué decisiones he ido tomando siguiendo el ciclo: ROJO -> VERDE -> REFACTOR.

Para ver una buena explicación de las diferencias de hacer TDD inside-out e outside-in, podéis leer este post: TDD: Outside-In vs Inside-Out en el fantástico blog de Adictos al Trabajo.

Después de hacer estas dos katas, he leído el libro “Understanding the 4 rules of simple design” y he comparado mis decisiones.

Resumen y comentarios del libro “Understanding the 4 rules of simple design”

El libro empieza muy fuerte, con los prólogos de Kent Beck y J. B. Rainsberger de los que se sacan auténticas perlas:

Foreword from Kent Beck

Is wrong “Design for the future. Change is expensive. Make it cheap by anticipating it.”

This looked like a positive feedback loop to me: more speculation -> worse design -> more speculation.
The good news about disastrous positive feedback loops is that you can generally drive them backwards. I first experimented by ignoring any changes that seemed like they would happen longer than six month in the future. My designs were simpler, I started making progress sooner, and I stressed less about the unknowable future. I shortened the time horizon to three months. More better.
One month. More. A week. A day. Oh, hell, what happens if I don’t add any design elements

Es muy gráfico cómo relata una especie de evolución de su pensamiento sobre qué pasaría si no adelantamos nada de supuestos futuros.

Buceando un poco desde el enlace que da en el prólogo, llegué a un artículo de Martin Fowler sobre estas reglas de diseño donde pone la siguiente cita de Kent Beck:

At the time there was a lot of “design is subjective”, “design is a matter of taste” bullshit going around. I disagreed. There are better and worse designs. These criteria aren’t perfect, but they serve to sort out some of the obvious crap and (importantly) you can evaluate them right now.

The real criteria for quality of design, “minimizes cost (including the cost of delay) and maximizes benefit over the lifetime of the software,” can only be evaluated post hoc, and even then any evaluation will be subject to a large bag full of cognitive biases. The four rules are generally predictive.

— Kent Beck

Creo que define muy bien lo que significan las buenas prácticas: Estos criterios no son perfectos, pero sirven para detectar algo de la basura más obvia y (lo más importante) puedes evaluarlo inmediatamente.

En un entorno de trabajo donde cualquier decisión es cuestionable, tener reglas básicas para distinguir el ‘crap-code’ ayuda mucho a las conversaciones dentro del equipo

Foreword from J. B. Reinsberger

El siguiente prólogo está realmente bien. Pues ayuda a profundizar y hacerte una idea de las conversaciones que puede haber detrás de algo aparentemente tan sencillo como las cuatro reglas.

Destaco como antes, no textos del prólogo, sino de los posts relacionados de JB. Son mencionados en numerosas ocasiones por todos los autores vistos hasta ahora y se recomiendan incluso por Corey Haines en el propio libro.

The four elements of simple design

When I find fifteen lines of duplicate code, I start by extracting them to a new method, and since I probably don’t yet know what those lines of code do yet, I name the new method foo(). After around 15 minutes of working in the same area, I begin to understand what this method does, so I give it an accurate name, such as computeCost().
[…]
That leaves me with two key elements of simple design: remove duplication and fix bad names. When I remove duplication, I tend to see an appropriate structure emerge, and when I fix bad names, I tend to see responsibilities slide into appropriate parts of the design.
[…]
I claim that developing strong skills of detecting duplication, removing duplication, identifying naming problems, and fixing naming problems 
equates to learning everything ever written about object-oriented design.

Este post es oro puro, el primer párrafo me encanta, pues dar nombres a métodos o clases, es la tarea más difícil del desarrollo. Aquí da una pista muy buena.

El siguiente post relacionado de JB, es la continuación del anterior, e intenta cerrar la ‘guerra’ abierta sobre el orden de importancia de las cuatro reglas.

Putting an age old battle to rest

I don’t think it matters whether you focus first on removing duplication or on revealing intent/increasing clarity, because these two guidelines very quickly form a rapid, tight feedback cycle. By the time the guidelines guide you to any useful results, you’ll have probably used them both. Therefore, order the rules however you like, because you’ll get to the same place either way.

When we remove duplication, we create buckets; when we improve names, we create
more cohesive, more easily-abstracted buckets.

Now, I think of them as a
single guideline: remove duplication and improve names in small cycles. When I do this, I produce a higher proportion of  well-factored code compared to all the code I write.

Removing duplication and improving names helps me reduce the liability (cost) of the code that I write.
Together, they help me reduce both the total cost and the volatility of the cost of the features I deliver.

En estos tres párrafos habla de tres temas muy potentes:

  1. Cerrar la guerra sobre el orden
  2. Cohesión
  3. Coste

Introduction: This book

Me encanta esta introducción. Habla con más claridad de lo que hemos visto hasta ahora: cómo las cuatro reglas se retroalimentan, incidiendo en lo comentado por JB.

Recalca como Kent Beck que no ve que haya diseños buenos y malos, e incluso que puede haber varios buenos diseños. A partir de ahí, comparándolos se podría llegar a un consenso de las ideas fundamentales de por qué un diseño es “mejor” que otro.

If we can look at things from a comparison point of view, perhaps we can find some fundamental ideas about “better”.

Termina formulando las dos constantes en el desarrollo de software, acompañado de un tweet de Sandi Metz: “Habrá cambios pero no sabemos qué es lo que va a cambiar”

Examples

A continuación entramos en materia del libro con diferentes ejemplos divididos en capítulos (respeto los títulos en inglés), como si fuéramos construyendo desde cero el Juego de la Vida.

Test Names Should Influence Object’s API

// Test: Check world is empty
// NO
world.cell_alive_at(1,1)?
// YES
world.empty?

Hay que usar nombres de test de hablen de negocio, y construir un API apropiada. Si usamos nombres de test orientados a datos, corremos el riesgo de construir un código que expone información que no es responsabilidad de la clase.

Duplication of Knowledge about Topology

class LivingCell
    attr_reader :location
end class

Aquí, Corey Hanes propone poner la localización dentro de la celdas, para no duplicar el conocimiento acerca de la topología del sistema, como en el código visto antes.

Pensé en hacer esto, pero tal como estaba resolviendo el problema, no podía mover o quitar el conocimiento de la ubicación de las células fuera de la clase Grid, que está un nivel hacia afuera: lo necesitaba para recorrer la malla y calcular la siguiente iteración y para calcular el número de vecinos.

Como experimento para esta kata, la estructura de datos en la que almacené las células de la malla, una estructura de dos dimensiones, fue en un tipo List, unidimensional. Y para consumirlo, desarrollé una especie de Iterable y el acceso a un elemento concreto con paginación.

Así, el primero de los problemas que comento lo tenía resuelto, no se iba a recorrer la malla.

El segundo problema, el de calcular el número de vecinos es el que no supe cómo resolverlo. ¿Cómo podía acceder a los vecinos de un elemento, si la posición que ocupan la tiene solo los elementos? ¿Cómo accedo a un elemento concreto de la malla?

Después de terminar la kata, se me ocurrió una solución a esto. Podría haber usado métodos como .filter() sobre el List, para buscar elementos. No es muy eficiente, pero consigue lo que se quiere, abstraes la localización del Grid y se lo pasas a las células, lo probaré para la próxima.

Behavior Attractors

Whenever we have a new method — a new behavior — an important question is “where do we put it?” What type does this belong to?

Siempre que tenemos un nuevo comportamiento la pregunta es dónde lo ponemos.
En el libro recomienda ponerlo en cualquier sitio, no pararse a analizar el problema. Si nos encaja, perfecto; pero si no, tenemos que moverlo. Además moverlo cuanto antes para que luego con el uso no sea más difícil.

// Where do we put neighbors?
// Location seems perfect.
class Location
     attr_reader :x, :y
     def neighbors
         # calculate a list of locations
         # that are considered neighbors
      end
 end

Destaca que a través de eliminar la duplicación de conocimiento de manera agresiva es como conseguimos clases que atraen comportamientos. Y como corolario, si intentamos eliminar y no encontramos dónde colocarlo es que nos faltan algunas abstracciones.

En el ejemplo de código, me llamó mucho la atención poner los neighbors en Location. Porque eso significa que es un dato que se guarda, no un dato calculado al momento del tick. Interesante para explorar.

Testing State vs Testing Behavior

En este apartado habla que hay que testear el comportamiento y no el estado, y pone como ejemplo que lo primero que comprueba en la kata es:

world.empty?

Yo lo que pensé que era el primer comportamiento era algo como:

world.stable?

Es decir: “¿Es el sistema estable? ¿Hay que hacer una siguiente iteración? ¿Cuál es la condición de parada?”. Comentándolo con los compañeros, parece que afronté el problema desde demasiado afuera. Outside-in no quiere decir literalmente: “Desde la capa más exterior, hacia dentro”.

Don’t Have Tests Depend on Previous Tests

def test_an_empty_world_stays_empty_after_a_tick
     world = World.new
     next_world = world.tick
     assert_true next_world.empty?
 end

Rather new world is empty, let’s explicitly ask for an empty world.

def test_an_empty_world_stays_empty_after_a_tick
     world = World.empty
     next_world = world.tick
     assert_true next_world.empty?
 end

Si cambiamos el constructor base y devuelve otra cosa que un mundo vacío, el primer test continuará pasando. Para evitar esto, quien invoque al objeto no debería usar el constructor base con la confianza que vendrá con un estado específico, y menos en la preparación del test, debería usar un ‘constructor’, un ‘builder’, para crear un objeto con un estado concreto y válido.

Esto me parece simplemente genial. Dejar de confiar en los constructores y crear builders que te den el objeto en el estado deseado. Es un problema que me encuentro de manera recurrente, no confío en los datos que tengo al preparar un test.

Breaking Abstraction Level

def test_world_is_not_empty_after_adding_a_cell
     world = World.empty
     world.set_living_at(Location.new(1,1))
     assert_false world.empty?
end

Este tests está acoplado a una capa de abstracción que no es la suya, por lo que si se cambia el sistema de coordenadas a tres dimensiones, por ejemplo, fallarán tests que no tienen nada que ver.

El libro recomienda en este caso hacer un doble de test que abstraiga de ese detalle. Otra opción puede ser usar un helper que de cree ese objeto de coordenadas y así solo está definido en un sitio.

def test_world_is_not_empty_after_adding_a_cell
    world = World.empty
    world.set_living_at(Object.new)
    assert_false world.empty?
end

Este tipo de problemas nos hacen ver todos los puntos de contacto que tienen nuestros objetos con los demás.

Naive Duplication

Muy interesante esta sección en la que veremos las diferencias entre duplicidad de código y duplicidad de lógica de negocio.

Vamos a observar las condiciones para que una célula viva en la siguiente generación:

class Cell
    # ...
    def alive_in_next_generation?
        if alive
            number_of_neighbors == 2 ||
            number_of_neighbors == 3
        else
            number_of_neighbors == 3
        end
    end
end

Podríamos refactorizar este código:

// An optimization of is_alive condition
class Cell
    # ...
    def alive_in_next_generation?
        (alive && number_of_neighbors == 2) ||
            number_of_neighbors == 3
    end
end

Con este refactor de código recordamos una de las cuatro reglas: “El conocimiento se debe representar una y solamente una vez”.

Every piece of knowledge has one and only one representation.

Mirando otra vez al código original podemos ver que esos 3s no significan lo mismo.
Recomienda que una buena técnica para no caer en este error, sería nombrar de forma explícita los conceptos antes de refactorizar.

class Cell
    # ...
    def alive_in_next_generation?
        if alive
            stable_neighborhood?
        else
            genetically_fertile_neighborhood?
        end
    end
end

Así se ve mucho mejor y en caso de cambiar las condiciones de supervivencia, accedemos a reglas de negocio directamente.

En mi código no hice refactor porque me di cuenta que no era el mismo conocimiento, pero no extraje a un método cada comportamiento, interesante apunte para la próxima.

Procedural Polymorphism

El if en el código del apartado anterior diferencia los casos comprobando el valor del estado:

if state == ALIVE
...

En esta sección destaca que el uso de variables de estado es un indicio de que no se ha entendido el negocio. Interesante.

¿Cómo resolvemos esto? Nos presenta el Polimorfismo, como una técnica que nos da la posibilidad de llamar a un único método y tener más de un posible comportamiento. Si usamos ifs para hacer estas diferencias le llama Procedural Polymorphism.

Cuando vi esto me vino a la cabeza que una buena razón para no tener cuerpos ifs muy grandes o complejos es que se podría romper el Principio Open/Close porque este método tiene más de una razón para cambiar. Deberían ser super-sencillos.

Avanzando con el polimorfismo, la OO nos da su método preferido, el Polimorfismo basado en tipos.

Así en nuestro ejemplo podemos coger el estado y trasladarlo a un par de tipos:

class LivingCell
    def alive_in_next_generation?
        # neighbor_count == 2 || neighbor_count == 3
        stable_neighborhood?
    end
end

class DeadCell
    def alive_in_next_generation?
        # neighbor_count == 3
        genetically_fertile_neighborhood?
    end
end

¡Polimorfismo! ¡Me encanta! Me parece muy mágico y elegante.

Pero Haines no lo deja ahí, no nos deja tranquilos en nuestra satisfacción. A continuación rompe el polimorfismo de este ejemplo cambiando de nombre a los métodos. ¿Por qué?

La explicación que da, es que el polimorfimo hace abstracciones muy atractivas que podrían ocultar detalles del comportamiento real de cada subtipo, siendo incorrecto ese genérico que queremos atribuirle.

Para darnos un ejemplo, se plantea la propia existencia de la clase DeadCell, pues no tendría mucho sentido si el tamaño del Grid fuera infinito.

Es muy fácil, sobre todo al principio, sacar abstracciones rápidamente y hacer una jerarquía de tipos. Pero si nos damos cuenta que es incorrecta deshacerla suele ser complicado.

Making Assumptions About Usage

La idea fundamental bajo la pregunta: “¿Necesitamos esta abstracción?” es: “El uso influencia la estructura”. Propone que hay que construir nuestra lógica de negocio y las abstracciones que usemos motivadas por el uso que hagamos.

Unwrapping an Object

Partiendo de este trozo de código que muestra una solución para contar los vecinos de una célula:

class Location
    attr_reader :x, :y
end

location1 = Location.new(1, 1)
location2 = Location.new(1, 2)

if location1.equals?(location2)
    # Do something interesting
end

Para hacer ese “algo interesante” tenemos que saber si las dos posiciones son iguales. Y generalmente haríamos algo como esto:

class Location
    attr_reader :x, :y
    def equals?(other_location)
        self.x == other_location.x &&
        self.y == other_location.y
    end
end

location1.equals?(location2)

¿Qué sucedería si aplicamos en la kata la restricción (muy potente) de “Nuestras funciones no pueden retornar valores”?
Tendríamos que transformar este código para que cumpla el ‘Tell, don’t ask’ y confiar en los objetos para que hagan un trabajo que generalmente haríamos nosotros.

Para ello propone una solución muy interesante, el uso de lambdas: le decimos al .equals? lo que queremos que ejecute si se cumple la condición.

count_of_locations = 0
location1.equals?(location2, -> { count_of_locations++ })

class Location
    attr_reader :x, :y
    def equals?(other_location, if_equal)
        other_location.equals_coordinate?(self.x, self.y, if_equal)
        nil
    end

    def equals_coordinate?(other_x, other_y, if_equal)
        if self.x == other_x && self.y == other_y
            if_equal.()
        end
            nil
    end
end

Es de destacar que como no podemos retornar nada, hay que invocar a other_location con la lambda, para que lo ejecute.

Me ha encantado encontrarme el uso de funciones anónimas en este ejemplo; creo que combinándolo con el apartado anterior de “Romper el nivel de abstracción” puede quedar un código con menos efectos laterales.

Inverted Composition as a Replacement for Inheritance

Volvemos al ejemplo anterior del polimorfismo:

// Let’s create mother class
class Cell
    attr_reader :location
end

class LivingCell < Cell
end

class DeadCell < Cell
end

Esta extracción al crear el padre no introduce un nuevo concepto de dominio. La herencia es a menudo utilizada como una forma de “reusar” más que para eliminar duplicidades.
Es un error común crear clases ‘base’ de este estilo, que pueden llegar a ser un contenedor de comportamientos muy poco relacionados.

Si la herencia no es un solución, ¿qué otras opciones tenemos?

En el ejemplo usa módulos de Ruby, y en otros lenguajes tendríamos Traits (Groovy) y en otros algo como los decoradores.

class LivingCell
    include HasLocation
end

class DeadCell
    include HasLocation
end

Llegados a este punto, con la duplicidad medio resuelta, vemos que tenemos dos clases apuntando al mismo tipo, (Living|Dead)Cell a Location.
Una técnica útil es Invertir la dependencia, que la localización apunte a las células.

class Location
    attr_reader :x, :y
    attr_reader :cell
end 

class LivingCell
    def stays_alive?(number_of_neighbors)
        number_of_neighbors == 2 ||
        number_of_neighbors == 3
    end 
end 

class DeadCell
    def comes_to_life?(number_of_neighbors)
        number_of_neighbors == 3
    end
end

De esta manera, las clases que representan células están únicamente centradas en la información que les atañe, como las reglas sobre cómo evolucionan.
También hemos extraído la topología de las reglas del juego, viendo que el tipo Location tiene un rol de estructura, que une la malla con la célula.

Comparándo con mi código, la composición invertida es muy similar a la solución que había propuesto yo inicialmente en la kata: Grid -> Position -> Info

Como ‘Rule of Thumb’ la dependencia de clases debe ir desde la que más cambia a la que menos cambia, desde la menos estable a la más estable, es decir, la dependencia la tiene que tener aquella que tiene más posibilidades de cambiar sus atributos.

Conclusión

Programar el Juego de la Vida de dos maneras diferentes y luego leerme este libro ha resultado ser un ejercicio muy intenso y productivo. ¡Y escribir este post, claro!
Me llevo un buen montón de herramientas.

A continuación voy a leerme el libro “Practical Object-Oriented Design in Ruby”, de Sandi Metz. Os iré contando!

Etiquetado ,

cover

In my first weeks in Codesai, I have to code the Conway’s Game of Life in a pair of ways.

First one was TDD inside-out in Javascript, and the second one was TDD outside-in with Groovy. I left there links to my Github.

If you want to know a little bit more about TDD styles, you can read this beautiful post: TDD – From the Inside Out or the Outside In?

After that I read the small book “Understanding the 4 Rules of Simple Design” and I leave a little review in GoodReads :

Very interesting thoughts about Four Rules of Simple Design based in Game of Life Kata.
I agree with most of the conclusions and the review of Simple Design Rules.
Little ‘but’ ahead… In my opinion, I see in the final examples, a little bit of ‘magic’ and some jumps in the flow we were following with the author.

It’s a good booklet, you can read it very quickly and you take very clear and useful information.

I’m writing right now a more extended post with detailed comments. Stay tuned!

 

Book review – Understanding the 4 Rules of Simple Design

Etiquetado