Experimento: conventional reviews

Desde hace ya bastante tiempo comencé a utilizar conventional commits en mis proyectos y también en mis clases. El año pasadomientras corregía una entrega de los alumnos se me ocurrió utilizar una estrategia similar para las observaciones en las revisiones de código.

A mi parecer las observaciones más comunes que veo en el código de los estudiantes se pueden agrupar en las siguientes categorías:

  • Naming (n): nombres inapropiados, poco representativos, confusos, etc
  • Programación (p): métodos muy largos, números mágicos, indentación no uniforme, etc
  • Encapsulamiento (e): elementos públicos que deberían ser privados, acceso a miembros de otros objetos, etc.
  • Modelado (m): conceptos del dominio del problema representados en el código de forma inapropiada
  • Separación de incumbencias (s): clases con varias responsabilidades, poco cohesivas, mezcla de incumbencias de dominio con incumbencias accidentales, etc

Entonces a partir de esto, es que cada comentario que hago en la revisión le agrego el prefijo correspondiente.

La idea de este experimento es poder extraer información sobre las observaciones más habituales en el código de los alumnos para luego poder accionar al respecto.

Perspectivas del inicio de clases 2024 @ fiuba

Tal vez el lector esté esperando algún comentario sobre la situación crítica que afronta la UBA (y la educación pública en general en Argentina), lamento decepcionarlo. No es que la situación me sea ajena o no despierte mi interés, pero por el momento intento mantener una de las premisas de este espacio: nada de política, fútbol o religión. No estoy seguro de cuánto mantendré esta idea, porque sinceramente la situación es preocupante y es definitivamente un tema de política y visión de país. En fin, vamos a la cuestión académica que es lo que quiero compartir.

Según indica el sistema de inscripción parece que este cuatrimestre tendremos record de alumnos tanto en la materia de grado (memo2@fiuba) como en postgrado (entrega_continua@untref).

En FIUBA tenemos 36 inscriptos, record histórico, el máximo anterior había sido 32. Esta cantidad de alumnos representa nuestro primer desafío para este 2024: mantener la calidad del cursos con más del doble de alumnos que los que veníamos teniendo (el cuatrimestre pasado tuvimos 13 alumnos).

A esto se suma un segundo desafío: alumnos del nuevo plan de estudio de Ingeniería Informática que vienen con una formación distinta por haber cursado materias distintas. Por lo que estuve relevando, son alumnos que vieron más cuestiones de diseño/programación y menos de proceso de desarrollo (usuarios, requisitos, scm/ci, ambientes, etc).

El primer impacto de esta situación está en la carga de trabajo del equipo docente, por suerte contamos con varios colaboradores (ex-alumnos de la materia) que serán un factor clave en el manejo de la carga de trabajo. Es por eso que a pesar de estos dos desafíos, estamos planificando el cuatrimestre igual que el cuatrimestre anterior, que consideramos nos dio muy buenos resultados. Eventualmente ajustaremos sobre la marcha si lo vemos necesario.

Ortografía del código

En la actualidad (y desde hace buen tiempo), varios entornos de desarrollo y editores de código tienen la capacidad de detectar «errores» ortográficos de forma similar a lo que hacen los procesadores de texto como Microsoft Word y Google Docs que subrayan las palabras que desconocen.

En general esta funcionalidad de «corrección ortográfica» viene configurada para inglés. Si codeamos en inglés (cosa que muchos programadores hacen) no hay problema. Pero si aplicamos Domain-Driven Design y nuestro usuario/cliente habla castellano, entonces seguramente codeemos en castellano y ahí el IDE/editor comenzará a que llamarnos la atención. Aquí tenemos básicamente dos opciones: desactivar la verificación de ortografía o configurarla correctamente. Para esto último, independientemente de cómo sea esa configuración seguramente vamos a necesitar descargar un diccionario.

En el video que comparto a continuación explico como configurar RubyMine, el IDE de JetBrains para Ruby, pero la configuración es práctica igual para otros IDEs de JetBrains.

Bonus: para el caso de Visual Studio Code, podemos instalar la extensión Spanish – Code Spell Checker, en otro momento lo explicaré con más detalle.

Automatización de pruebas: the wrong way

Si, lo sé, el título es un poco marketinero y bastante incorrecto como suele pasar con afirmaciones tan extremas.

La cuestión es que hoy en día muchas organizaciones/equipos con la intención de abrazar los beneficios de Agile/DevOps descubren que es necesario tener pruebas automatizadas. Hasta ahí vamos bien.

La cuestión se empieza a torcer cuando para automatizar la pruebas ponen gente exclusivamente para hacer eso mientras que los desarrolladores siguen trabajando sin alteración alguna en su dinámica. ¡ooops! No es por ahí.

Es cierto que es necesario tener pruebas automatizadas y que en general sin importar cómo se hagan, es mejor que nada. Pero la teoría y la evidencia indican que en un contexto Agile/DevOps la automatización de pruebas requiere del involucramiento activo de los desarrolladores. Los desarrolladores deben hacer su parte automatizando las pruebas unitarias y luego trabajando de forma cercana con usuarios y testers en las pruebas de aceptación. Podrá después haber algún trabajo adicional de automatización de pruebas para generar un set de regresión, pero si lo desarrolladores hacen lo que acabo de mencionar, entonces este esfuerzo adicional agrega poco valor.

Claro que esto no es trivial, nunca dije que lo fuera. Se requiere de algunas habilidades (duras y blandas) adicionales respecto del enfoque tradicional de desarrollo y testing. Para poder escribir pruebas unitarias necesitamos saber hacerlo pero más allá de eso necesitamos que la arquitectura/código de nuestra aplicación nos lo permitan. También se requieren de algunas habilidades de comunicación/colaboración para que desarrolladores y testers trabajen más cerca y de forma temprana.

Algunas de estas cuestiones las menciono en esta entrevista del año pasado y también la trato con cierta profundidad en mi Taller de Prácticas Técnicas.

Curso online de Extreme Programming

En enero comencé con un experimento, desarrollar una aplicación real (para un cliente mio) en sesiones online, abiertas y de 15 minutos. Como de costumbre, el desarrollo lo hice aplicando prácticas de Extreme Programming como ser Specification by Example, Test-Driven Development, Continuous Integration, Entrega Incremental, Story Slicing, etc., y utilizando algunas técnicas de diseño/programación como ser arquitectura hexagonal, mocks, etc.

Fueron en total 20 sesiones (unas 5 horas) en las que completé 2 mini-releases de la aplicación en cuestión. Luego, edité los videos de las sesiones, los complementé con algunos videos más y con ello le di forma un video-curso en la plataforma Udemy. La versión actual del curso tiene más de 7 horas de video y durante marzo repetiré la experiencia para agregar más funcionalidades y con ello sumar al menos otras 10 horas de video.

Los interesados en el curso lo pueden en la plataforma Udemy (aquí).

Nuevo Proyecto con AI

Hace un par de semanas comencé a trabajar en nuevo proyecto. Se trata de un equipo que trabaja en Inteligencia Artificial, más precisamente en cuestiones de procesamiento de leguaje natural (AI/NLP).

Para ser más preciso debo decir que comencé a trabajar con este equipo el año pasado pero en un rol distinto. El aquel momento colaboré con algunas cuestiones técnicas de diseño, testeabilidad, etc., de una API que el equipo utiliza para exponer sus servicios de AI. Ahora estoy en un rol distinto, estoy metido completamente en el equipo en un rol que yo denominaría como «XP Coach». La idea es ayudar al equipo a trabajar de forma ordenada con un proceso de delivery predecible y mejorable.

Entre los desafíos que veo podría mencionar que el equipo trabaja en forma remota todo el tiempo, en parte porque los miembros del equipo están distribuidos en 2 países. Esta distribución geográfica está condimentada por una diferencia de zona horaria entre los países de 2 horas. Otro desafío es mi rudimentario conocimiento de temas de AI/NLP, pero esta cuestión me parece un tema menor en el sentido que para el trabajo que a mi me toca no es necesario ser un especialista en cuestiones de este dominio. Pero creo que definitivamente el mayor desafío pasa por la naturaleza de los entregables del equipo. O sea, básicamente el principal artefacto del equipo es un modelo de AI/NPL expuesto vía una API para que otros equipos de lo organización lo consuman y lo integren en aplicaciones «consumibles por los «usuarios humanos». La cuestión es que el trabajo tiene mucho de experimentación lo cual implica ciertas particularidades a la hora de organizar el trabajo dentro de un contexto típico de agile/scrum/xp. Si bien tenemos algunas tareas que pueden representarse como simples User Stories, muchas otras no calzan naturalmente como User Stories. Por ejemplo: no siempre son estimables y no siempre es posible establecer criterios de aceptación. Un caso concreto: hay que mejorar un modelo, de entrada no sabemos cuánto podremos mejorarlo ni cuánto nos llevará hacerlo; al mismo tiempo es posible que si invertimos más tiempo podamos mejorarlo más, pero no es seguro. Respuestas a esta situación y varias otras serán parte de futuros posts.

Herramientas de gestión de backlog: estas NO

No voy decir qué herramienta no utilizar. En lugar de ello voy a contar cómo me gusta trabajar y cuales son incomodidades/limitaciones que me he encontrado con ciertas herramientas pero sin dar nombres.

Parte de la motivación de escribir este artículo tiene que ver con que en más de una vez veo equipos trabajando de una determinada forma que ni a ellos mismos les convence y ante la pregunta de porqué lo hacen me dicen cosas tales como «Es que la herramienta lo maneja así» o «Nos gustaría hacerlo de otra forma pero nuestra herramienta no lo soporta«. Estas situaciones caen dentro de lo que yo suelo denominar «Poner el caballo delante del carro». En fin, voy con mi lista.

Identificación de ítems: me gusta poder referirme a los ítems del backlog de forma rápida con un número, onda: «el ítem 14», «el ítem 182». Resulta muy práctico y directo sin ambigüedades. Hay herramientas que en lugar identificador los ítems con secuencias numéricas por proyecto, utilizan identificadores largos tipo GUID o tienen una secuencia global para todos los proyectos entonces estos IDs tienden a ser números muy largos como «1234599934» y resulta incómodo utilizarlos para identificar los ítems en una charla.

Ítems linkeables: me gusta poder compartir links directos a cada ítem, es algo que parece trivial pero he visto herramientas que no lo soportan, solo es posible compartir un link al backlog y luego uno manualmente debe posicionarse en el ítem en cuestión.

Libertad en los tipos de items: en general tiendo a no hacer distinción en los tipos de ítems, por eso me resulta indiferente si la herramienta soporta o no distintos tipos de ítems (story, tasks, etc). Pero hay herramientas que fuerzan a que todo ítem sea de algún tipo (hasta ahí, ok) y junto con ello «le imponen ciertas reglas» (por ejemplo: cierto tipo de ítem no se puede estimar) mmm, esto ya es demasiado.

Prioridad y costo: todo ítem de backlog tiene una prioridad para el negocio y un costo (estimado) asociado de construcción, entonces espero que la herramienta provea soporte explícito para estos dos datos. No todas las herramientas lo hacen. El hecho de poder tener estas propiedades individualizadas permite a posteriori hacer ciertas operaciones de reporte 7 análisis.

Iteraciones: generalmente me inclino por un esquema de entrega continua pero igualmente me gusta trabajar en iteraciones para así poder establecer una cadencia de reflexión y planificación. Hay herramientas que no soportan iteraciones.

Reporting: al cabo de un par de iteraciones me gusta poder sacar algunas métricas y proyecciones de la evolución del proyecto. Hay herramientas que vienen con un nutrido set de reportes, otras tienen algún reporte pero permiten exportar la información. Pero hay otras que nada de eso.

Para cerrar, soy consciente que aún cuando la herramienta no soporte cierta funcionalidad, es posible que podamos, como decimos en Argentina, «atarlo con alambre», buscarle la vuelta, onda: si la herramienta no tiene soporte para indicar la estimación entonces la podemos cargar en la descripción. Mmmm, demasiado rudimentario para mi gusto.

En fin, el mercado está plagado de herramientas para gestionar el backlog, cada uno que use lo que guste pero procuren no poner el carro delante del caballo.

Manejo de información sensible con git-secret

Es habitual cuando hacemos aplicaciones tener que lidiar con información sensible como ser contraseñas y tokens de acceso. A esta información sensible se le suele llamar secretos. En la actualidad la práctica habitual es almacenar estos secrets en herramientas creadas específicamente para ello y que suelen llamarse Administradores de Secretos (Secret Managers) o Bóvedas.

Algunas nubes proveen soluciones propietarias para esta cuestión como es el caso de AWS Secret Manager y Azure Key Vault pero también existen soluciones open source como Vault que pueden instalarse on-prem. Usando estas herramientas uno puede guardar en ellas su información sensible (secretos) y luego conectar al administrador de secretos con los ambientes donde quiere usar dicha información.

Pero también existen un conjunto de herramientas que posibilitan guardar secretos en repositorios Git, una práctica no muy recomendada. Estas soluciones son extensiones y/o complementos de Git y lejos están de compararse funcionalmente con los administradores de secretos, pero para proyectos personales, chicos o no críticos, son una opción completamente válida. Básicamente estas soluciones toman los archivos con la información sensible y le aplican algún tipo de encriptación de forma tal que quedan almacenados en Git pero estando encriptados. Soluciones de este tipo son git-crypt y git-secret. Es precisamente esta última herramienta la que vengo usando. A continuación voy a compartir de forma resumida como funciona.

La herramienta funciona como una extensión de Git y en conjunto con GPG, o sea: necesitamos instalar GPG (dependiendo del sistema operativo puede que ya venga instalado) y git-secret (las instrucción de instalación de git-secret son muy simples y están publicadas en su página oficial).

Una vez que tenemos la herramienta instalada podemos ir al repositorio git donde queremos agregar información sensible y lo primero que debemos hacer correr el comando git secret init para indicarle a git-secret que queremos guardar información sensible en el repositorio en cuestión. Este comando va a crear un directorio .gitsecret que será utilizado por git-secret.

A continuación vamos a indicarle a git-secret nuestro mail (asociado a nuestra clave pública gpg) para que podamos tener acceso a la información sensible que guardemos en el repositorio. Esto lo hacemos con el comando git secret tell nicopaez@mimail.com.

A esta altura ya estamos en condiciones de comenzar a agregar información sensible. Supongamos entonces que tenemos un archivo con información sensible llamado secretos.txt y entonces queremos indicarle a git-secret que queremos que maneje este archivo para lo cual ejecutamos git secret add secretos.txt. Un efecto de este comando es que el archivo secretos.txt, que tiene la información sensible sin encriptar ha sido agregado al gitignore porque precisamente no queremos que git lo versione.

El siguiente paso es «ocultar» (encriptar) la información sensible ejecutando git secret hide. Este comando generará un archivo encriptado por cada uno de los archivos que hayamos agregado previamente como secretos. En este caso, se habrá generado un archivo secretos.txt.secret que contendrá la información encriptada del archivo secretos.txt. y que podrá ser agregado sin problemas al repositorio git (es seguro hacerlo porque su contenido está encriptado). El último paso es hacer git add y commit con el archivo secretos.txt.secret.

Resumiendo como queda la historieta:

  • el archivo secretos.txt.secret contiene nuestra información sensible encritada y está versionado en nuestro repositorio git. Toda persona con acceso al repositorio podrá acceder al archivo, pero al estar este encriptado, no podrán ver si contenido.
  • el archivo secretos.txt, no está versionado por git y solo existe localmente en mi máquina para poder ser utilizado por mi aplicación.
  • Si yo me clonara otra vez el repositorio, no tendría el archivo secretos.txt (pues no está versionado en el repositorio) sino que tendría que generarlo a partir de ejecutar git secret reveal. Este comando toma los archivos encriptados (en este caso secretos.txt.secret) y los desencripta. Obviamente para poder hacer esto, el usuario en cuestión tiene que tener permisos para acceder a la información sensible (esto se hace con el comando git secret tell que ya ejecutamos previamente y que a continuación explicaré con mayor detalle.

Hasta aquí tenemos la configuración inicial, con esto de ahora en más cada nuevo archivo con información sensible (o cada modificación) deberemos ejecutar git secret add y git secret hide y a continuación el usual git add y git commit.

Una última cuestión es cómo compartir esta información sensible con otros miembros del equipo. Para esto vamos a necesitar la clave pública gpg de la persona a quien querramos dar acceso (esa persona deberá exportar su clave haciendo gpg –armor –export your.email@address.com > clave_publica_de_un_colega.gpg). Dicha clave será típicamente un archivo que en primer lugar tendremos que importar con gpg haciendo gpg import clave_publica_de_un_colega.gpg. Teniendo la clave importada podremos dar acceso a la persona en cuestión ejecutando git secret tell colega@email.com. Finalmente el último paso, que es fundamental, es reencriptar todos los secrets, para esto primero haremos un git secret reveal y a continuación un git secret hide -d.

Bien, esto es todo. Si deciden utilizar la herramienta para algún proyecto (más allá de probar lo que describí en este artículo) les recomiendo ver la documentación oficial de la herramienta.

4 confusiones habituales sobre TDD

Recientemente hablaba con un cliente sobre TDD y su poco uso en la industria a pesar de sus probados beneficios. Durante la charla me encontré, sin haberlo meditado previamente, hablando sobre confusiones habituales respecto de TDD que a mi parecer le juegan en contra.

La primer confusión, y posiblemente la más común, es confundir TDD con una técnica de testing. TDD no es una técnica de testing, como su nombre lo indica es un técnica de desarrollo. Al creer que es una técnica de testing, hay desarrolladores que directamente la dejan de lado (sin siquiera probarla) pensando que no es para uso de los desarrolladores sino para el uso de los testers :-(. Algo que aporta a esta confusión es que en algunas instituciones TDD es estudiado en materias de testing/calidad en lugar de materias de diseño/desarrollo. A favor de los confundidos admito que el nombre (Test-Driven Development) a pesar de ser preciso, puede resultar confuso.

Otra confusión que he visto reiteradamente en quienes comienzan/intentan utilizar TDD es ir directo al código sin absolutamente ningún ejercicio de diseño preliminar . La técnica es muy explícita en cuanto a comenzar por los tests y trabajar en pequeños incrementos. Pero ello no significa que no pueda (¿o deba?) hacer un poco de diseño preliminar, haciendo incluso algún diagrama y pensando en el diseño «final» (o diseño a mediano/largo plazo). En una época (allá por los ’90) había gente que hacía diseños muy detallados y luego pasaba de una a intentar implementar esos diseños en código. Luego de esa experiencia poco feliz, algunos se fueron al otro extremo sin siquiera pensar un poco antes de saltar al código. En lo personal siempre me gusta comenzar haciendo un diagrama del dominio del problema antes de saltar al código. Al mismo tiempo, cuando salto al código no es para implementar de una el dominio completo, sino que la implementación del dominio la hago incrementalmente generando incluso versiones reducidas/incompletas pero entregables al usuario. De esta forma puedo llegar a generar varias versiones de cara al usuario antes de tener materializar la visión inicial del dominio (que por cierto, es una visión que va evolucionando a medida que voy aprendiendo más del dominio).

Omitir premisas de la técnica es también una error habitual. TDD no es solamente comenzar por la prueba, hay varias cuestiones más y entre ellas una fundamental es trabajar en pequeños incrementos. Al no trabajar en pequeños incrementos, las pruebas que escribimos pueden ser más grandes/complejas y requerir mayor esfuerzo para hacerlas pasar. Al mismo tiempo podemos estar complicando el diseño (y la implementación) innecesariamente.

Finalmente, algunos creen que al hacer TDD no es necesario un esfuerzo de testing posterior y entonces no es necesario contar con la colaboración de testers en el proceso de desarrollo. Dado que TDD no es una técnica de testing, necesitamos testear nuestro software más allá de que hallamos hecho TDD. Obviamente que las características de ese testing van a ser distintas dependiendo de si el software fue desarrollado haciendo TDD o no. De entrada, si hicimos TDD el esfuerzo de testing posterior va a ser mucho menor pues varios casos ya van a estar testeados. También debemos tener presente que los tests generados en el ciclo de TDD son distintos a los tests que un tester realiza a posteriori, esto es así porque el objetivo de unos y otros tests es distinto. Más aún, TDD es una técnica surgida en un contexto Agile donde el rol de tester es radicalmente distinto a rol del tester en un contexto «tradicional» (no Agile) pero esto es material de otro artículo.

Libre recomendado: Wild West to Agile

Hace unos días terminé de leer este libro. Simplemente excelente. Su autor es Jim Highsmith, uno de los autores del Manifiesto Ágil. Jim ha escrito más de un libro y muchos artículos que nunca leí. Esa fue una de mis motivaciones para leer este libro.

El libro es en gran medida un repaso histórico, desde la perspectiva personal del autor, de la evolución de las metodologías y procesos de desarrollo. A lo largo del libro Jim va contando sus experiencias (que comienzan allá por los años 60) y que llegan hasta la actualidad. Creo que para quienes trabajamos en cuestiones de metodología y procesos es una excelente referencia para entender la evolución de la forma de trabajo y como una cosa llevó a la otra. Por otro lado creo que para aquellos «amantes de agile» es un lectura obligada para entender cómo fue gestándose Agile. El libro está plagado de anécdotas que van ejemplificando las distintas corrientes a lo largo del tiempo.

Una cosa que me gustó mucho del libro es la cuidada terminología. Jim dice explícitamente que prefiere hablar de Desarrollo de Software en lugar de Ingeniería de Software, reavivando esa eterna polémica. También habla explícitamente sobre «métodos estructurados», «metodologías monumentales», «métodos ágiles», «agile» y «agility». También hace una clara diferenciación entre método, metodología y mindset, términos que muchas veces se confunden (sobre todos los dos primeros).

Cuando habla de Agile hace explícita mención a prácticas técnicas y también a prácticas de gestión, resaltando las importancia de estas últimas.

En la parte final del libro se mete en temas de transformación digital y escalamiento. Aquí no habla de SAFe ni LeSS sino de EDGE y unFIX.

En fin, el libro me gusto mucho y lo super recomiendo.