Como seguramente ya sabrán, el pasado mes, Apiumhub fue sponsor de la JBCNConf, y parte del equipo de desarrolladores tuvimos el placer de asistir al evento y poder inspirarnos y compartir conocimientos con parte de la comunidad Java en Barcelona. 

 

JBCNConf 2019: notas y reflexiones

Durante nuestra estancia en la JBCNConf 2019, el equipo de Apiumhub pudo asistir a diversas conferencias de temas muy distintos. La sensación generalizada fue que la conferencia giró entorno al sponsor principal, Red Hat, puesto que contaron con diversas conferencias y un workshop. Esto me inspiró para realizar algunas pruebas de concepto con la herramienta que presentaron, Quarkus, como ellos lo definen: “a Kubernetes Native Java framework”. Pero hoy no vengo a hablar de Quarkus, hoy me gustaría hablar de una de las conferencias que más captaron mi atención. Hablo de la conferencia impartida por Victor Rentea – Senior Java Engineer, Technical Team Lead y Java Coach en IBM, titulada “Evolving a Pragmatic, Clean Architecture – A Craftsman’s Guide”. 

 

Evolving a Pragmatic, Clean Architecture – A Craftsman’s Guide

En primera instancia podríais pensar que es una charla más sobre “Clean Code” o “Clean Architecture”, y lo cierto es que en parte tendríais razón, se habla sobre los valores principales de los que hemos oido hablar hasta la saciedad. Pero lo que más llamó mi atención, fue el enfoque que le da Victor a su ponencia, apoyándose principalmente en las bases del Clean Code y el Extreme Programming. Además, pone en el punto de mira al desarrollador, al bienestar del equipo técnico y a su confortabilidad para poder realizar trabajo de calidad en las mejores condiciones posibles. Rentea expone que un proyecto o repositorio de código no es una construcción de código, sino que defiende la idea de que tiene más símil con un jardín, es decir, algo orgánico en constante crecimiento, que requiere cuidados continuos, en clara referencia al refactoring, lo cual amplía más adelante.

Las técnicas en las que basa su exposición son técnicas ya más que conocidas tales como:

  • Single Responsability Principle ( SRP),
  • Don’t Repeat Yourself (DRY),
  • Keep it Short and Simple (KISS),
  • You Aren’t Gonna Need It (YAGNI), entre otros.

Cuidando al equipo técnico

Uno de los puntos claves que defiende se basa en que un buen arquitecto debe proteger al equipo técnico con herramientas de automatización, que garanticen minimizar los riesgos del proyecto, así lo afirma: “Fear kills creativity“. Minimizando los riesgos en el proyecto, el equipo técnico se siente más seguro y esto provoca de manera proporcional una mejora del código productivo. Para minimizar estos riesgos, propone técnicas de testing que aseguren el código y su funcionalidad.

Otro factor que me pareció muy interesante, fue la propuesta de hace pensar siempre al equipo de forma continuada, para mantener la motivación. Para ello propone diferentes soluciones:

  • Regular brainstorming: El equipo técnico debe pensar de manera conjunta como mejorar el código. En mi opinión, esta técnica no solo puede mejorar la calidad del código, sino que además provoca un alineamiento entre los distintos miembros del equipo.
  • Continuous Refactoring: Provocado por el punto anterior, aplicar las decisiones tomadas durante la sesión de brainstorming.
  • There are no boring tasks: Automatizar las tareas aburridas y repetitivas como método para mantener la motivación del equipo técnico. Eliminar este factor de la ecuación es algo fundamental para la motivación.

Como declarado seguidor de Clean Code y Clean Architecture, Rentea propone la aplicación de una arquitectura hexagonal, también conocida como arquitectura por capas o Ports and adapters. Victor repasó los fundamentos principales de esta arquitectura, pero no quiero extenderme en esta parte de la cual hay mucho escrito y podéis encontrar varios artículos en nuestro blog sobre ello, por ejemplo Aplicando Arquitectura Hexagonal a un proyecto Symfony, en el cual se repasan las bases fundamentales de dicha arquitectura.

Uno de los puntos más interesantes es cuando aparece la necesidad de refactorizar una clase o servicio que ha crecido demasiado. Una vez tomada la decisión de dividirlo, aparece una nueva responsabilidad para la nueva clase o servicio emergente ( SRP ),  esta parte es, en mi opinión, de las más complejas de aplicar en la refactorización de código. Saber definir la nueva responsabilidad y además decidir la jerarquía que existe entre la clase original y la nueva emergente:

  • Vertical ( DRY ): Definiendo así una nueva capa de extracción, y esto implica que una clase depende de la otra.
  • Horizontal ( SRP ): Las responsabilidades de ambas clases son totalmente separadas y no tienen dependencias entre sí.

Además clasifica los tipos de duplicación que pueden aparecer en un proyecto, sensibles de refactorización en muchos casos:

  • Rush/Lazy: Duplicar código o reglas de negocio mediante Copy & Paste.
  • Imposed: Son duplicaciones que difícilmente se pueden suprimir. Por ejemplo, validaciones que se realizan en frontend y backend en un proyecto.
  • Inadvertent: Una mala organización del repositorio, puede hacer que a veces olvidemos funcionalidades ya implementadas hace tiempo y puede provocar que repitamos funcionalidades ya existentes en nuestro repositorio.
  • Inter-developer: Un desarrollador no conoce una funcionalidad ya desarrollada por otro miembro del equipo y la vuelve a implementar. Para intentar minimizar la duplicación, mejorar la calidad del código y la interacción del equipo técnico con éste, Rentea enumera algunas técnicas que favorecen la calidad del código. 
  • Sesiones de Pair Programming es la mejor técnica para compartir conocimiento dentro del equipo, mejorar el código producido, minimizar la producción de bugs o errores y además incrementa la velocidad de desarrollo a medio-largo plazo.

Todo esto, además respaldado por sesiones de Coding Katas, Refactoring Hackatons, Coding dojos u Offensive Refactoring.

Uno de los puntos clave para tener un entorno cómodo en el que el equipo técnico pueda desarrollar en condiciones óptimas y pueda desarrollar código orgánico de calidad, es un código testeado. Afirma que un código altamente testeado y bien testeado es un buen código, puesto que implica un código simple, desacoplado y documentado de forma dinámica: los tests nos están indicando la funcionalidad de nuestro código productivo y sus reglas de negocio.

Rentea enumera diversos tipos de tests, ordenados de menor a mayor dificultad, basándose en su mantenibilidad:

  • Pure functions: Corresponde al código más interno e independiente dentro de nuestro dominio. Las funciones puras carecen de estado, es decir, el mismo *input* siempre retornará el mismo *output*. Estás funciones realizan una acción muy concreta, lo cual facilita su testeabilidad. Este código carece de dependencias ni side effects.
  • Mock-based: Es más complejo de realizar y mantener, puesto que pese a tener esas dependencias substituidas por mock objects, si esas dependencias cambian, posiblemente el test necesite ser refactorizado o reescrito.
  • In-memory Emulation: Lo justifica como *fragile data fixtures*. Depender en una estructura de datos concreta, implica que si en un punto determinado de la evolución constante de nuestro código orgánico, dicha estructura de datos cambia, implica tener que cambiar todas las estructuras de datos que estamos utilizando como fixtures en nuestros tests.
  • On Real System: Pruebas de integración, End-to-End, en las que se realizan tests sobre sistemas reales, implican unas dependencias sobre terceros (como por ejemplo, una base de datos o un sistema de caché en Redis). Dichas dependencias pueden producir falsos negativos por problemas ajenos a nuestro código o obligarnos a refactorizarlos por cambios de versión o actualizaciones en estas.

 

JBCNConf notas: conclusiones

En conclusión, Victor nos anima a mantener toda la lógica de nuestro negocio dentro de nuestro Core Domain, lo más desacoplada posible, para favorecer así el testeado unitario de nuestro código, favoreciendo la mantenibilidad de éste e incrementando así la velocidad de desarrollo.

Como conclusiones, Victor enumera los siguientes puntos clave:

  1. La importancia de evitar el overengineering, defendiendo así el principio KISS
  2. Proteger al equipo técnico en un entorno confortable que les genere la confianza necesaria para afrontar cualquier reto y no temer a refactorizar legacy code por miedo a romper funcionalidades existentes.
  3. Abstraer de nuestro dominio todas las dependencias externas.
  4. Refactorizar y extraer solo cuando sea estrictamente necesario. (Mediante DRY o SRP)
  5. Aplicar la arquitectura por capas para abstraer las responsabilidades en cada capa y extraer dependencias de nuestro dominio. Enfatiza en mantener nuestro dominio agnóstico de las dependencias externas.
  6. Tests: La importancia de poner a prueba los límites de tu código y de tu diseño.

 

Para finalizar, me gustaría extraer mis propias conclusiones sobre la ponencia de Victor Rentea. Personalmente, estoy de acuerdo en los todos los puntos que se tratan. Hay que ser pragmáticos en el día a día, mantener la simplicidad en nuestro código, optar por un diseño bien estructurado, que favorezca el crecimiento y refactorización de nuestro código. 

Como el propio Victor comenta al inicio de su ponencia, las técnicas y consejos que se exponen se fundamentan bajo unos principios básicos y se favorecen aplicando las siguientes técnicas reflejados en el libro Extreme Programming ( XP ):

  • Continuous Integration
  • Pair Programming
  • Continuous Refactoring
  • Test Driven Design

Estas técnicas, en conjunto con las ya nombradas durante el artículo, favorecerán que nuestro código crezca de forma orgánica y mejorando su calidad, y aumentando la felicidad y motivación de nuestro equipo técnico. Además, concluye animándonos a mejorar con la siguiente cita: “The fastest way to learn is to teach the others. The fastest way to grow into a senior is to help the others grow“. Es una de las citas que más me han dado que pensar y que no puedo estar más de acuerdo de todo lo que aprendí en la JBCNConf. Compartir el conocimiento con nuestra comunidad es fundamental para el crecimiento global. Si nuestro equipo técnico mejora, el conocimiento empezará a fluir en ambas direcciones, lo cual implica un crecimiento personal.