Introducción a la Arquitectura Hexagonal

Puertos, adaptadores y DDD

La Arquitectura de Software es un conjunto de patrones y abstracciones que se debe seguir en el desarrollo de software así como en la interacción de sus diversas piezas, que permiten a todos el equipo seguir una misma línea de trabajo  y cubrir todos los objetivos y restricciones de la aplicación.

Ejemplos de arquitectura son MVC, la programación por capas, peer-to-peer, orientada a servicios (SOA), cliente-servidor...


Odoo text and image block

Todos estos patrones permitirán el desacoplamiento de nuestro dominio con elementos externos, por lo cual produciremos sistemas con las siguientes características:

 

 

Odoo - Sample 1 for three columns

Independientes del framework

 

Odoo - Sample 1 for three columns

Independientes de la UI

 

Odoo - Sample 1 for three columns

Independientes de la base de datos

 

Odoo - Sample 1 for three columns

Independiente de agentes externos

 

Odoo - Sample 1 for three columns

Mantenibles

 

Odoo - Sample 1 for three columns

Altamente Testables

(Principio de Inversión de Dependencias (DIP) de SOLID)

Odoo - Sample 1 for three columns

Reutilizables

(Principio de Responsabilidad Única (SRP) de SOLID)

Tolerantes al cambio

(Principio de Abierto/Cerrado (OCP) de SOLID)

                                                                Historia y motivaciones

                                                                Por qué se crearon las Arquitecturas Hexagonales

                                                                Durante mucho tiempo, una de las grandes pesadillas en las aplicaciones de software ha sido la infiltración de la lógicadel negocio en el código de la interfaz de usuario. Ello trae un problema triple:

                                                                    1. Primero, el sistema no puede ser fácilmente probado con suites de pruebas automatizadas porque parte de la lógica que se necesita probar depende de detalles visuales que cambian a menudo, como el tamaño de un campo de entrada o la posición de un botón. 

                                                                    
                                                                2. Por la misma razón, se vuelve imposible cambiar su uso de uno dirigido por personas a un sistema de funcionamiento por lotes.

                                                                    3. Por ello, se vuelve difícil o imposible permitir al programa ser guiado (o usado) por otro programa cuando se desee.

                                                                La solución tentativa, repetida en muchas organizaciones, es crear una nueva capa en la arquitectura, con la promesa que esta vez, realmente y verdaderamente, ninguna lógica del negocio será puesta en esta nueva capa. Sin embargo, al no tener un mecanismo para detectar cuando una violación a esa promesa ocurre, unos años más tarde, la organización ve que la nueva capa esta mezclada con la lógica de negocio y el problema otra vez reaparece.


                                                                Un interesante problema similar existe con lo que es normalmente considerado “el otro lado” de la aplicación, donde la lógica de la aplicación está atada a una base de datos externa u otro servicio. Cuando el servidor de base de datos se cae o se somete a un importante re-trabajo o reemplazo, los programadores no pueden trabajar porque su trabajo está atado a la presencia de la base de datos. Esto trae costos de demora y a menudo malos sentimientos entre las personas.

                                                                Habitualmente la confusión y el acoplamiento de las aplicaciones viene dado por no saber qué es lógica de negocio y qué son interacciones con entidades externas. La regla que se debe cumplir es que el código perteneciente a la parte interior no debería invadir el exterior.

                                                                La arquitectura hexagonal, o puertos y adaptadores, dada a conocer por Alistair Cockburn, resuelve estos problemas al observar la simetría del caso: hay una aplicación interna que se comunica con cosas externas a través de un número de puertos. Los elementos externos de la aplicación pueden ser tratados con simetría.

                                                                ¿Por qué hexágonos?

                                                                El hexágono tiene el propósito de resaltar visualmente:

                                                                • La asimetría interna-externa y la naturaleza similar de los puertos, con el fin de alejarse de la imagen unidimensional de las capas y todo lo que ella evoca.

                                                                • La presencia de un número definido de diferentes puertos.

                                                                El hexágono no es un hexágono porque el número seis sea importante, sino más bien para permitir que la gente que hace uso del esquema tenga espacio para insertar puertos y adaptadores cuando lo necesite, sin estar restringido a un esquema unidimensional en capas. El término “arquitectura hexagonal” viene de este efecto visual.


                                                                Odoo text and image block

                                                                Puertos y adaptadores


                                                                El término “puerto y adaptadores” reúne los “propósitos” de las partes del esquema. Un puerto identifica una comunicación útil. Típicamente, habrá muchos adaptadores para cualquier puerto, para varias tecnologías que puedan conectarse a un puerto.

                                                                Estas podrían ser: un contestador automático, un teléfono táctil o por voz, una GUI, un test harness, un batch driver, una interfaz http, una interfaz directa programa a programa (i.e. Llamadas a Procedimientos Remotos- RPC), una base de datos mock (en memoria) o una real (quizá distintas bases de datos para el desarrollo, pruebas y producción).

                                                                Un puerto es un consumidor agnóstico, un punto de entrada a la aplicación. Si buscamos una analogía, podría ser una interfaz en muchos lenguajes de programación. Podremos utilizar esta interfaz sin saber nada de cómo es su implementación concreta.

                                                                Los adaptadores funcionan como puente entre la aplicación y el servicio que esta necesita. Su función es transformar la comunicación entre actores externos y la lógica de la aplicación. Se corresponden con la implementación de los puertos.

                                                                La principal motivación de esta arquitectura es exponer los puertos de entrada o primarios, en una API que pueda ser ejecutada indistintamente por usuarios, programas o procesos. Esto nos da la ventaja de que el núcleo de nuestra aplicación no conoce lo que tiene a su alrededor ni se interesa en implementar su lógica de mensajes, de esto se encargarán los adaptadores.

                                                                Un evento entra a la aplicación desde el exterior y la aplicación ignora la naturaleza de la entrada. Esta llamada ha venido dada por un adaptador que ya se encargó de convertir la llamada en un procedimiento utilizable. En el momento que la aplicación necesita comunicar algo hacia el exterior, lo hace a través de un puerto y luego este puerto lo envía a un adaptador que se encargará de convertir la
                                                                llamada saliente para que el dispositivo receptor la entienda. 



                                                                Odoo text and image block

                                                                Desventajas de las Arquitecturas Hexagonales

                                                                - Como para comunicar entre las diferentes capas hace falta el uso de puertos (interfaces) la complejidad suele aumentar con frecuencia. Hay que tener muy claros los principios básicos y cómo implementarlos ya que si no podríamos incurrir en los problemas históricos.

                                                                - En aplicaciones grandes, habrá un gran número de capas, con sus correspondientes interfaces e implementaciones. Esto supone un mayor nivel de Mantenimiento debido al aumento (por ejemplo en Java) de clases.


                                                                Arquitecturas Hexagonales y DDD

                                                                Al ser una arquitectura que fomenta el que nuestro dominio sea el núcleo de todas las capas, y que no se acople a nada externo, encaja muy bien con la idea del DDD. Al fin y al cabo, la parte táctica del Domain-Driven Design no es más que la agrupación de muchos conceptos y patrones de diseño ya existentes. Así entonces, podríamos decir que el DDD se basa en la Arquitectura Hexagonal como pilar central en términos de arquitectura.

                                                                 


                                                                A su vez, también cabe destacar el hecho de que, al estar basada en los contratos establecidos por los puertos que definamos, nos permite posponer decisiones a nivel de implementación (qué adaptador implementaremos para ese puerto). Esto facilita el desarrollo dirigido por test (TDD) ya que nos podemos centrar en la clase que estamos desarrollando sin necesidad de implementar sus colaboradores en ese estricto momento.

                                                                 


                                                                ¿Cómo podemos dividir el código?

                                                                Capa de Dominio
                                                                 

                                                                La capa de dominio es el núcleo de la aplicación, contiene las reglas de negocio, es responsable de mantener la consistencia del estado de los objetos del Dominio, en pocas palabras serían tus clases modelos. La capa de Dominio y su lógica de negocio definen el comportamiento y las restricciones de tu aplicación en cuanto a la forma en que se van a comunicar las demás capas con esta. . El estado que refleja el dominio se controla y utiliza en el modelo, aunque los detalles técnicos de su almacenamiento, se delegan a la infraestructura.


                                                                Capa de Aplicación
                                                                 

                                                                Es el lado del usuario. Habitualmente es dónde se encuentran los controladores o servicios que permiten la conexión con el exterior  y la validación de los datos que estos manejan


                                                                Capa de Dominio
                                                                 

                                                                En esta capa se encuentran las implementaciones de las conexiones con terceros exteriores que normalmente en el resto del proyecto están representadas mediante interfaces. Serían por ejemplo las clases que implementan los repositorios de dominio. Esto permite cambiar de framework siempre y cuando el contrato se cumpla, por lo que podrías tener un RedisUserRepository o

                                                                MongoUserRepository sin necesidad de que afecte al Dominio, incluso podrías llegar a crear InMemoryUserRepository que almacene los usuarios en una lista en memoria y también funciona (en este caso no habría persistencia).


                                                                Conclusiones

                                                                • La Arquitectura Hexagonal propone un uso de forma escrupulosa de los principios SOLID, que nos guían para construir mejor software.

                                                                • Nuestro Dominio no está acoplado a nada externo, ya que dispone de puertos que deben ser implementados por los elementos externos.

                                                                • Facilita estar desacoplado del método de entrega haciendo un caso de uso sea válido para una APP móvil, una API, una web tradicional…

                                                                • Está preparada para cambiar detalles de la implementación como la persistencia o el framework.

                                                                • Los elementos pueden ser fácilmente testados mediante pruebas unitarias.


                                                                Blog elaborado por Jorge Aranda

                                                                 

                                                                ¿Quieres saber más sobre Arquitecturas Hexágonales y DDD?

                                                                Pregunta sin compromiso a nuestro equipo técnico

                                                                Escriba un comentario

                                                                Usted debe ser registrado escribir un comentario.