Llegó a mis manos hace bastante tiempo el libro “Feynman’s Lost lectures” y me he propuesto terminar de leerlo. Es un libro fascinante en el que se aprenden conceptos de geometría muy interesantes de los que se infieren respuestas curiosas sobre, por ejemplo, el comportamiento de la luz dentro de un elipsoide. Feynman utiliza estos (y otros) principios geométricos para explicar conceptos más complejos como, por ejemplo, el movimiento orbital.

Este libro está imbuido de una forma de describir los fenómenos que me recuerda a una cita suya. Por lo menos la recibí cuando estaba suscrito a su cuenta de citas de Twitter (sí, ahora es X).

“Understand. Don`t memorize. Learn principles, not formulae.”

Me dispongo en este post a intentar indagar sobre los principios que hay detrás de la arquitectura hexagonal y si puedo sacar alguna ventaja de ella o si, por el contrario, es otra patraña sin sustancia como tantas otras que vinieron en el pasado.

En qué consiste

No pretendo hacer una descripción profunda y precisa de todos los elementos de una arquitectura hexagonal. Estoy seguro de que podéis encontrar muchos blogs y artículos que desgranan de forma minuciosa cada elemento y sus responsabilidades. Sin embargo, es necesario poner un poco de contexto sobre el objeto de esta indagación.

La citada arquitectura tiene una representación más o menos como esta:

Arquitectura de la entidad y casos de uso

Por hacer un resumen, podemos distinguir varias partes:

¿Aporta algo la arquitectura hexagonal?

Para poder responder a esta pregunta, voy a indagar sobre algunos principios que subyacen a esta estructura.

Primero, quiero destacar la preponderancia del dominio del problema. El hecho de reducir el ‘hexágono’ a un dominio específico y los casos de uso que lo gestionan aportan una ventaja, acota el impacto de los cambios al dominio concreto. Cuando tenemos que gestionar varios dominios en nuestro sistema completo, que los cambios estén acotados y no afecten a todo el sistema siempre es una ventaja. Esto es similar un principio como el siguiente:

"There should never be more than one reason for a class to change." In other words, every class should have only one responsibility.

El dominio y sus casos de uso son algo más extenso que una clase, pero el principio puede aplicarse de la misma forma porque el objetivo es el mismo, acotar el impacto de los cambios. Y sí, este es el ‘Single Responsibility Principle’.

Por otro lado, la aplicación y su dominio pueden estar compuestas por un conjunto amplio de clases, métodos e incluso interfaces internos. Sin embargo, a la hora de acceder a esta funcionalidad, no vamos a exponer una fachada que dé acceso a toda la funcionalidad posible. Por el contrario, vamos a exponer uno o varios interfaces diseñados en función de los escenarios de uso por parte de otros módulos. Estos son los puertos de entrada. Esta óptica en el diseño también se refleja en otro principio:

Clients should not be forced to depend upon interfaces that they do not use.

Pretendemos con esto evitar que los equipos de desarrollo de otros módulos que se integran con el nuestro puedan utilizar nuestro dominio de forma inadecuada, creando a su vez dependencias no deseadas. Y, una vez más, eso acota el impacto de los cambios a aquellos módulos que realmente utilizan la funcionalidad que se modifica. Ya os habréis dado cuenta de que este es el ‘Interface Segregation Principle’.

Finalmente, si nos fijamos en los puertos de salida, de alguna forma estamos haciendo un esfuerzo de abstracción sobre cuáles son las necesidades de la aplicación, independientemente de cómo se resuelvan dichas necesidades. Cuando un caso de uso necesita persistir información para recuperarla en otro momento del tiempo, en realidad, es irrelevante si la persistencia se hace en memoria, en un sistema de ficheros o en una base de datos. Lo que necesitamos es persistir un objeto del dominio. Esto se parece a otro principio:

"Depend upon abstractions, not concretes."

En realidad, estamos aislando la lógica de negocio de la aplicación de los detalles. Este aislamiento permite, una vez más, acotar el impacto de los cambios en cuestiones de detalle y que la lógica de la aplicación y su dominio no se vean afectados por los mismos. Empecé a conocer este principio a partir de la inversión de control, aunque podréis encontrarlo más específicamente como ‘Dependency Injection Principle’.

Llegados a este punto cabe volver a hacerse la pregunta: ¿aporta algo la arquitectura hexagonal? En mi opinión, la respuesta es simple; desde el punto de vista del desarrollo de software, la arquitectura hexagonal no aporta nada que no debiéramos estar haciendo ya.

¿En qué contextos es útil?

Puede parecer un contrasentido que, después de mi conclusión anterior, la utilice o pueda promover su uso. Sin embargo, hay determinados contextos en los que me facilita la vida.

  1. Organización

Cuando comenzamos a abordar el desarrollo de un nuevo sistema, necesitamos empezar debatiendo cómo lo organizamos. Qué paquetería tendrá, cómo nombramos las clases, qué módulos vamos a crear, etc. Todo el mundo tiene una forma particular de estructurar el desarrollo. Estos debates y acuerdos consumen tiempo. Tiempo que muchas veces no tenemos. La arquitectura hexagonal es algo ampliamente conocido y es un convenio tan válido como cualquier otro, con la ventaja de que cualquier persona nueva en el equipo o la conoce o tiene recursos para conocerla sin frenar al resto.

Por lo tanto, dejemos de discutir sobre si la tortilla española debe o no llevar cebolla y pongámonos a batir los huevos.

  1. Los detalles a la mazmorra

Cuando entramos en un proyecto que ya está en marcha, lo normal es que abramos el código y comencemos a expandir la paquetería. En mi caso, hay veces en que el alma se me cae a los pies. Lo que encontramos en el primer nivel son Controllers, Services, Mappers, DAOs, Spring, Kafka, PostgreSQL, Mongo…. No hay forma de enterarse de cuál es el propósito de la aplicación. ¿Cuáles son los conceptos que maneja? ¿Qué escenarios de uso tienen? ¿Cómo se gestionan?

La arquitectura debe indicar el propósito de la aplicación. Disponer de un convenio que da preponderancia al dominio y los casos de uso facilita promover una estructura de proyecto y de paquetería en la que lo primero que veamos sean los dominios que gestiona. Dentro de ellos tendremos sus entidades y procesos de negocio y, en las mazmorras, meteremos los detalles técnicos.

  1. Inculcación de principios

El software es algo de lo que mucha gente habla pero poca practica. Desarrollar software no es una tarea sencilla. No se resuelve poniendo cuatro anotaciones y tirando palante. Existen disciplinas, estructuras matemáticas, patrones y principios que muchas veces no dominamos en profundidad repitiendo errores resueltos desde hace muchos años. Aunque, eso sí, podemos empapelar paredes con posters súper bonitos sobre todos esos principios.

Disponer de una arquitectura donde los principios se hacen evidentes permite que las personas del equipo, especialmente las menos experimentadas, los practiquen y los mantengan interiorizados.

Conclusión

Este post analiza los principios de diseño sobre los que se sustenta la arquitectura hexagonal con el objetivo de determinar su utilidad. Desde este punto de vista, podemos detectar en esta arquitectura su apoyo en principios como “Single Responsibility”, “Interface Segregation” y “Dependency Injection”.

Asumiendo que ya estamos utilizando estos principios en el diseño de las aplicaciones, la adopción de arquitectura hexagonal no supone una mejora sustancial a lo existente.

No obstante, existen otros aspectos de los proyectos de desarrollo de software en los que la adopción de esta arquitectura puede suponer un avance importante. Entre estos avances se pueden destacar:

Cuéntanos qué te parece.

Los comentarios serán moderados. Serán visibles si aportan un argumento constructivo. Si no estás de acuerdo con algún punto, por favor, muestra tus opiniones de manera educada.

Suscríbete