Etiqueta: buenas prácticas

Hacen falta más programadores contando sus miserias

Desde que Andrés planteara hace ya dos años el reto de escribir sobre la selección tecnológica en pymes llevo queriendo escribir algo sobre ello.

Todavía no va a ir de esta, pero valga este mini-post para referenciar dos enlaces que han entrado en mi radar esta misma semana. En el primero Matt Mullenweg quota a Jony Ive de Apple para afirmar que tan importante como el producto (o el servicio) que proporcionas a tus clientes es el proceso, o el aprendizaje, con el que has llevado hasta él. Algo en lo que creo firmemente y que también leí en Kent Beck (aunque ahora no encuentro el enlace). En el segundo nos hablan de como no todas las arquitecturas valen para todos los casos.

Basicamente mi opinión va en la línea de que los creadores de opinión en torno al software, son lógicamente, increiblemente expertos en sus campos. Los frameworks con más éxito, son hechos por empresas como Google o Facebook. Las conferencias están llenas de gente que hace cosas muy chulas con las últimas tecnologías. Pero cuando tengas que decidir, si estás leyendo este post, seguramente no trabajes en Google, ni serás un mega-experto. Puede que tus clientes para hacer el deploy te hagan conectarte a un teamviewer ejecutándose en un Windows en una red interna donde te permiten abrir un putty al servidor y «monitorizan» todo lo que tecleas que debe hacerse a mano para validarlo. Trata de hablar con ellos de docker (o incluso de scripts para automatizar).

Hace falta más conferencia, más libros y más posts de gente contando sus miserias, y de como su trabajo es tan necesario como el de quien tiene la suerte de poder desplegar en AWS, porqué también están resolviendo problemas reales.

Modelado de datos booleanos en la base de datos

Cuando definimos la información que un usuario puede visualizar o modificar a través de un formulario nos encontraremos datos aparentemente booleanos. Por ejemplo: ¿Hay un pozo en esta aldea?.

La primera aproximación para implementar esta información es poner un checkbox en el formulario y definir el campo como booleano en la base de datos.

CREATE TABLE aldea (id serial, pozo boolean);

Haciéndolo de este modo existen varios posibles problemas:

  • A nivel usabilidad. Que pasa si el usuario no sabe si hay un pozo. Lógicamente dejará el checkbox sin marcar, pero cuando se revise esa información no se podrá saber si a conciencia se dejo en blanco indicando que no había pozo, o si se desconocía el dato.
  • A nivel implementación. Por defecto, a no ser que la lógica implementada en cliente lo gestione de otra forma, en la base de datos almacenaremos un valor NULL y no un valor FALSE. Al tener valores nulos las queries que hagamos se pueden complicar, por ejemplo un SELECT * FROM aldea WHERE pozo IS FALSE; no nos devolverá los valores nulos. Si empleamos la tabla para hacer un informe o exportarla a una hoja de cálculo tendremos que lidiar con los nulos, …

Por tanto cuando modelemos una información que parezca binaria, preguntémonos (y preguntemos al cliente) si es necesario distinguir entre falso, y desconocer el dato. Si estamos en la segunda situación debemos huír de usar checkboxes y emplear otro tipo de widget, como un combobox donde el usuario pueda escoger «Existe», «No existe» o dejar en blanco si no conoce el dato. A nivel implementación la información del combobox la guardaremos en general como un texto o un tipo enumerado. Y si eres un producto owner que usa algún tipo de documento para definir el modelo de datos a los desarrolladores asegurate siempre de especificar esta información.

Habrá situaciones en las que aún presentando al usuario la información mediante un combo, nos interese modelar el campo como un booleano. En este caso la lógica por encima de la base de datos sería la responsable de traducir el campo en blanco por un nulo, el ‘Existe’ por un true y el ‘No existe’ por un false.

Cuando modelemos un campo en la base de datos que sea verdaderamente binario para evitar confusiones deberíamos implementarlo de esta forma.


CREATE TABLE aldea (
id serial,
pozo boolean NOT NULL DEFAULT false
)

Addendum

Cuando trabajamos con campos booleanos que admiten el valor nulo nos podemos encontrar un problema adicional al hacer migraciones de la base de datos. Imaginemos que tenemos un campo contador de tipo boolean, y que en la base de datos tenemos valores a true, false y null. Si a posteriori decidimos cambiar contador por un sistema de medida, con opciones como Contador, Manual, Volumétrico, … hacer la migración hacia adelante será sencillo.


UPDATE myschema.mytable SET sistema_medicion = 'Contador' WHERE contador IS true;

Pero el revert no sería tan sencillo, porque habremos perdido la información de nulos y false.

Comentarios al artículo de Complejidad y Reversibilidad de Kent Beck

Andrés me pincha para que lea y comente el último post de Kent Beck en su muro de facebook. Como todo lo que escribe Beck hay que leerlo con atención y se pueden sacar lecciones interesantes. Pero este artículo en particular se me hace complicado de leer porque creo que mezcla demasiadas cosas a la vez. Comienza con una teoría general sobre sistemas complejos y luego salta a prácticas concretas de facebook para atajarla en distintos estadios del desarrollo sin pararse a explicar que técnicas tienen sentido en según que contextos. Analicémoslo por tanto atendiendo al artículo como dos partes separadas.

Complejidad y Software

Software complexity es un término con definición propia en el mundo académico. En la práctica todo desarrollador tiene una noción intuitiva de que es complejidad y debería tener como principio el atajarla. Beck explica alguno de los elementos de la complejidad y cuales de ellos se puede intentar mantener bajo control en un producto como facebook. La cuestión es, si en otro tipo de productos software se puede o tiene más sentido atacar otro frente distintos al de la irreversibilidad. Personalmente se escapa de mis conocimientos esta reflexión pero apunto algunos elementos para el debate:

  • Estados. Atendiendo al producto como un todo (hardware, acciones del usuario, red,..) seguramente será difícil de atajar. Si nos quedamos con las acciones (interacción) del usuario me recuerda a la diferenciación entre mapa y camino de la que se reapropió Andrés atendidendo a Verplank.
  • Interdependencias. SOLID, KIS, Patrones, Modularidad o cualquier práctica de buen diseño entiendo que ayuda a disminuirla a no ser que se me escape algo.
  • Incertidumbre. Supongo que es el más complicado. Usuarios usando la aplicación en formas no previstas. Requisitos cambiantes,…
  • Irreversibilidad. Nada que decir, es en el que se centra Beck.

Atajar la Irreversibilidad

La segunda parte del artículo habla de algunas de las técnicas que usan en Facebook para combatirla. Algunas pueden ser consideradas de modernas como el Frequent Pushes (¿Continuous Delivery?) y otras como el Code Review llevan con nosotros mucho tiempo. Beck las enumera todas juntas pero creo que intentar ponerlas bajo una clasificación más o menos habitual en factorías de software tradicionales puede ayudar a decidir cuales pueden ser aplicables en cada caso. Dejo fuera (IRC y Data-informed decisions)

  • Desarrollo
    • Development servers
    • Code review
    • Correlation
  • Pre-Producción / Testing
    • Internal usage
    • Staged rollout
    • Advance countries
    • Shadow production
  • Producción
    • Frequent pushes
    • Soft launches
    • Dynamic configuration
    • Right hand side units
    • Double write/bulk migrate/double read

Sin duda algunas de las técnicas como Staged Rollout es discutible en que fase van y son clasificables bajo esta óptica. La idea de intentar clasificarlas es sólo para poder compararlas con una forma de trabajo que nos resulte más cercana para a partir de ahí ver cuales podemos empezar a aplicar y en que punto de nuestro proceso.

Qué puedo aplicar y cómo si no soy Facebook

Más que técnicas concretas en realidad lo que Beck plantea es una cultura (o dos). El Desarrollo Ágil y el DevOp. Intentar aplicar alguna de sus estrategias de forma separada sin abrazar la filosofía subyacente creo que sólo produce desgaste. Con esto no quiero decir que tengas que hacer pair programming y tener un devop en tu equipo, pero sí al menos comprender que hay valor en los principio que proponen.

Para mi los pasos en ese camino son tres: Tests, Automatización y Monitorización.

Monitorización. Si no estás midiendo lo que sucede rendimiento, comportamiento de usuarios, … saber lo que está pasando o cuando un cambio no tiene el efecto previsto.

Automatización. Si hacer un despliegue es costoso e implica varios pasos, se harán pocos , se tardará más tiempo en tener feedback, se introducen más posibilidades de error y no hablemos de lo que supone revertir un mal cambio. Si no se automatizan los procesos se vuelve más complicado que todos los desarrolladores tengan el mismo entorno y este sea parecido a producción.

Tests. Probablemente la piedra angular. Estoy leyendo Working Effectively with Legacy Code, y en los primeros capítulos expone algunas cuestiones sobre tests que tienen relevancia para la «reversibilidad». En el libro comparan trabajar sin tests a hacer acrobacias sin red, y expone dos formas de introducir cambios en un sistema.

Changes in a system can be made in two primary ways. I like to call them Edit and Pray and Cover and Modify. Unfortunately, Edit and Pray is pretty much the industry standard. When you use Edit and Pray, you carefully plan the changes you are going to make, you make sure that you understand the code you are going to modify, and then you start to make the changes. When you’re done, you run the system to see if the change was enabled, and then you poke around further to make sure that you didn’t break anything. The poking around is essential. When you make your changes, you are hoping and praying that you’ll get them right, and you take extra time when you are done to make sure that you did.
Superficially, Edit and Pray seems like “working with care,” a very professional thing to do. The “care” that you take is right there at the forefront, and you expend extra care when the changes are very invasive because much more can go wrong. But safety isn’t solely a function of care. I don’t think any of us would choose a surgeon who operated with a butter knife just because he worked with care. Effective software change, like effective surgery, really involves deeper skills. Working with care doesn’t do much for you if you don’t use the right tools and techniques.
Cover and Modify is a different way of making changes. The idea behind it is that it is possible to work with a safety net when we change software. The safety net we use isn’t something that we put underneath our tables to catch us if we fall out of our chairs. Instead, it’s kind of like a cloak that we put over code we are working on to make sure that bad changes don’t leak out and infect the rest of our software. Covering software means covering it with tests. When we have a good set of tests around a piece of code, we can make changes and find out very quickly whether the effects were good or bad. We still apply the same care, but with the feedback we get, we are able to make changes more carefully.

En esencia, durante el desarrollo tener tests te permite probar y si no funciona revertir a coste casi cero. En producción el coste de revertir no es cero (al menos sin aplicar otras de las técnicas mencionadas) pero al menos te permite detectar errores de forma temprana.