Análisis forense de un YAGNI

«You Aren’t Gonna Need It» o «No vas a necesitarlo». Una de las reglas que todo aquel que se dedica al desarrollo de software debería tener presente en todo momento. Y no me refiero sólo a programadores o arquitectos, sino también a Product Owners que destrozan su producto llenándolo de funcionalidades banales.

No voy a extenderme mucho en el concepto. Hay mucha literatura por ahí. Sólo quería explicar un caso concreto que me comentaba un buen amigo hace poco. De como uno de esos YAGNIs le explotó en la cara recientemente. Como todos los accidentes, nunca hay una sóla causa, por lo podríamos argumentar que no toda la culpa fue del YAGNI. Pero lo cierto es que si alguien se hubiese planteado la necesidad de esa nueva funcionalidad antes de implementarla, probablemente no estaríamos hablando de esto ahora.

Os pongo en situación. Un sistema promocional requiere aplicar una promoción cuando se produce una determidada condición. Esa promoción siempre tiene un importe fijo. El mismo para todos los clientes y mercados. Nadie de negocio ha planteado nunca cambiar esa condición, no está en ningún backlog, nadie lo pidió y no parece que vaya a cambiar en un futuro próximo.

La cafetera.

Pero resulta que una conjunción lunar hace que un colaborador del equipo muy espabilado, voluntarioso e implicado con el proyecto, aunque algo joven e inexperto en el producto y en las técnicas de programación, tenga una conversación informal con el product owner. Y en lugar de hablar de futbol, se plantean que estaría bien parametrizar ese importe por tipo de cliente y mercado. Y se ponen manos a ello.

La zorra y el avestruz.

El resto del equipo, que está ocupado en otras tareas, no aprecia los riesgos de la modificación. Tampoco se ha hecho un grooming ni se ha planificado en ningún sprint, por lo que el desarrollo pasa bastante desapercibido.

Los spaghetti

Parece que el código del producto no es especialmente sencillo. Esta parte es bastante monolítica y tiene implicaciones con el sistema de pagos y los flujos principales de operación del producto. La modificación inicial era bastante sencilla, básicamente un «cuando pase esto, le ingresas esta cantidad al usuario». Pero al parametrizar esa cantidad por tipo de usuario y mercado, se añade más entropia a la ecuación. Y el código monolítico lleno de casos de uso que violan el principio de responsabilidad única tampoco ayuda.

Las caches las carga el diablo

Mi amigo no puede entrar en muchos detalles, pero resulta que, por circunstancias del producto, averiguar a que mercado pertenece el usuario para entregarle la cantidad que corresponde es tarea complicada computacionalmente. Por lo que alguien en el equipo propone cachear esos datos.

Nuestro voluntarioso programador, después de escuchar las críticas y consejos de un equipo de desarrollo que tampoco tiene muchas ganas de dedicar tiempo al problema, decide hacer su enésimo cambio e implementa esa cache. Y considera que el punto adecuado para guardar esa información es en el flujo de autenticación, ya que, a fin de cuentas, todos los usuarios se autentican en algún momento.

Y aquí tenemos el gran amplificador del problema. Lo que debería ser un caso de uso que ocurre esporádicamente, acaba afectando a uno de los flujos más importantes y usados de cualquier aplicación: el login.

¿Que me decías, cariño?

Cuando un coche sale malo suele decirse que aquello de «seguro que lo fabricaron el lunes a primera hora». En software, estos errores suelen aparecer los viernes, cuando los programadores quieren cerrar sprint y el product owner quiere explicarle al jefe lo listo que es y las cosas chulas que ha implementado el equipo.

Y aquí tenemos a nuestro voluntarioso colaborador pidiendo un code review a sus compañeros un viernes a primera hora de la mañana, todos ellos con el café en mano y pensando en el fin de semana.

Y resulta que la pull request, que ya llevaba varios días desarrollo y cayó en el sprint un poco torcida es aprobada sin demasiadas comprobaciones. Los test pasan, el proceso de integración continuo hace lo suyo y los cambios suben a producción sin que nadie sospeche el infierno que se va a liar en los próximos minutos.

Me gusta el olor de Napalm por la mañana

Lo que podía haber sido un viernes tránquilo se convierte pronto en un pequeño infierno. El error afecta el login de los usuarios, pero no falla siempre, sólo con algunos. La cache alimenta la entropía. No todos los usuarios fallan, y no fallan siempre. A veces falla el login, a veces la aceptación de GDPR, otros usuarios pierden su configuración de idioma. Las consecuencias son algunos clientes enfadados, medio equipo buscando e intentando corregir el problema. Gente dejando de hacer otras tareas importantes pero menos prioritarias, jefes cabreados que huelen la sangre y aprovechan para sacar los trapos rotos.. En resumen, mucha gente enfada por culpa de algo que no debió implementarse nunca.

Conclusiones

Los errores nunca vienen sólos. Por lo general, se acumulan varios pequeños errores que originan un gran problema. En este caso, hay algunas causas evidentes.

  • Tareas sin análisis previo o no «groomeadas».
  • Inexperiencia del desarrollador, tanto en el producto como en las técnicas de ingeniería.
  • Poco apoyo por parte del resto del equipo. Por falta de voluntad, o incluso por desconocimiento de la existencia del riesgo.
  • No construir usando pequeños incrementos de valor. Según parece la rama de desarrollo vivía sóla desde hacía varios dias e incluía múltiples funcionalidades. Eso dificulta las code reviews, molesta las subidas a producción y en general, cabrea al equipo.
  • Malas revisiones de código por parte del equipo. Por la razón que sea, los miembros más expertos del equipo no supieron aportar su conocimiento en la revisión de código.
  • Pero sobretodo, el error principal es la existencia del YAGNI en si mismo.

Es posible que toda la cadena de fallos lleve a otro error similar algún día, pero al menos será porque se estaba intentando aportar nueva funcionalidad.

El número de líneas es un gran determinante sobre la complejidad del software. Y la complejidad de un software tiene costes directos, medidos en euros. Un software complejo genera errores y hace más caro el desarrollo. Es mala idea engordar el código con funcionalidades innecesarias.

En este caso, TODA la funcionalidad que necesitaba negocio en el momento acual era añadir una constante con el valor 10 en alguna lugar del código. Como mucho, parametrizarlo en una configuración. 30 minutos de desarrollo, no más.

Volviendo a los orígenes

Recientemente leía un artículo en meneame en el que se trataba la poca calidad del código que escribían alumnos de últimos cursos y en cierta manera abogaban por volver a trabajar en entornos donde la memoria y el tiempo de proceso eran mucho más caros que hoy.

Reconozco que el artículo me tiró un poco para atrás al principio, pero luego recordé dos o tres experiencias en mi vida que me hicieron estar bastante de acuerdo.

El jodido VAX de la Salle

Cuanto cursaba el primer curso de Telecos en la Salle Bonanova hacíamos las prácticas de programación en C, en un supermaquinón host que llamaban el VAX (ahora se que aquello no era más que un juguete grande, aunque muy caro https://es.wikipedia.org/wiki/VAX).  El tema es que teníamos que usar el editor vi por narices, no había otro. Además, estaba mal configurado el terminal y no había manera de usar las flechas de teclado. Y lo más divertido, teníamos 60 compilaciones por práctica. A partir de ese número, el sistema te penalizaba con 60 segundos, más 10 segundos extra por cada compilación que pasase de 60.

Había prácticas donde fumabas un cigarro en cada compilación. Sobra decir que te mirabas muy bien el código antes de mandar a compilar.

Al año siguiente, cuando dejé Telecos y pasé a estudiar Informática Superior en la UAB, las prácticas de programación me parecían un juego de niños.

Un ejemplo de overkilling, o como matar moscas a cañonazos

La segunda experiencia relacionada es un proceso batch que metía datos en un mysql. Un compañero (y supuesto technical lead del equipo) se empeñó en programarlo con un comando de symfony usando doctrine. Doctrine no es especialmente bueno en ese tipo de tareas, ya que, salvo que lo ajustes adecuadamente, intenta guardar en memoria todas las entidades que ha creado.

Aquel proceso duraba casi una hora y solía romperse a la mitad por falta de memoria.

Siempre pensé, en realidad estoy convencido de que era así, que aquel tech lead no usó doctrine por que creyese que era lo más óptimo, sino porque no sabía trabajar bien a nivel de SQL. Le daba tanto terror (opinión mía) que prefería implementar un mostruo en lugar de bajar de nivel y hacer las cosas fáciles, sencillas y óptimas.

El cerebro acorchado

De eso no hablaba el artículo, es una reflexión personal. Muchas veces he tenido la sensación de que llega un día en que el cerebro empieza a acorcharse. Se acomoda y no admite nuevos conocimientos. empezamos a creer que solo existe una manera de hacer las cosas y somo impermeables a nuevas ideas.

Es por eso que siempre intento estar un poco fuera de mi zona de confort. Con 25 años de carrera por delante, es muy importante aprovecharse de la experiencia adquirida, pero mucho más aún seguir con el motor en marcha y mejorar.

Para probarme y ver si ya estoy en fase de acartonamiento, me he puesto a programar lo que sería una práctica de la universidad, una implementación de árboles binarios en Golang.  Y ¿Cómo no? La he programado en Go, que es mi juguete actual y por el que estoy apostando fuerte en mi carrera profesional.

Y he de decir que he sufrido. Creo recordar que en mi época de estudiante era más rápido implementando este tipo de cosas. O quizás era menos exigente y sólo aspiraba al aprobado justito.

En próximos articulos me meteré más en explicaros este proyecto y algunos patrones que he aplicado que me parecen muy interesantes por la manera en que se usan en Golang.

 

 

Patentes de Software. Tuve la misma idea que Google.

Andaba yo como casi cada tarde sábado elucubrando alguna idea para hacerme rico y dejar de trabajar. De repente me encuentro con que mi nueva idea está patentada, y nada menos que por Google.

La idea es sencilla, nada de ciencia para cohetes. Simplemente, montar un agregador de información que recorra la web con un spider y detecte cualquier publicación geolocalizada. El interfaz de usuario (la web) mostraría un mapa donde el usuario podría consultar información relativa a una zona.

Buscando algo de información al respecto, me encuentro con esta patente de Google, que  explica el proyecto prácticamente con las mismas palabras que yo habría usado.

Y la verdad. Me cabrea. Y mucho. Yo entiendo que si un señor inventa un motor para enviar cohetes a la luna, o una medicina para tratar una enfermedad, o un proceso químico para generar un nuevo compuesto, o lo que sea, tenga derecho a proteger su idea y su inversión.

Pero, ¿Una idea? ¿Pueden patentarse las ideas? Es que les ha costado más tiempo escribir todo el texto de la patente que pensarlo. Una idea que cualquiera ha podido pensar mientras evacuaba plácidamente.

¿Que pensáis? ¿Es moral patentar ideas? ¿Tiene derecho google a parar un proyecto sólo porque tienen tiempo y dinero para pagar abogados que escriban bonitas patentes?

¿Se aplican las patentes de ideas fuera de USA? Tengo entendido que no se admiten esas patentes en Europa, y yo soy europeo. Pero claro, ¿Quien se arriesga a perder el tráfico orgánico de Google?

Fin de la pataleta.