Ejemplo de Arquitectura Hexagonal con Spring Data
En esta entrada vamos a ver y a definir qué es la Arquitectura o patrón de Puertos y Adaptadores y un ejemplo de Arquitectura Hexagonal en Spring Boot que estará basado en Spring Data.
Uno de los máximos cuando desarrollamos software, es intentar que nuestro código así como las diferentes partes que lo integran se encuentre lo más desacoplado posible. Para así poder por ejemplo, hacer pruebas, verificar y o encontrar problemas en diferentes partes de nuestra aplicación, y aislar la parte de negocio de la parte de infraestructura por ejemplo la conexión con la base de datos. Por lo que entorno a esta idea surge la Arquitectura Hexagonal.
¿Qué es la Arquitectura Hexagonal?
Después de la introducción anterior y ver los motivos para crear este tipo de Arquitectura, podríamos definir la Arquitectura Hexagonal, o la Arquitectura de Puertos y Adaptadores, como un patrón de arquitectura de diseño de software, en el que se busca desacoplar la aplicación por componentes. Estos componentes formarán una serie de capas que serán fácilmente conectables entre si mediante puertos y adaptadores, lo que hará que los componentes puedan llegar a ser intercambiables en cualquier nivel, y ayudará a los test automáticos.
Esta Arquitectura fue introducida por Alistair Cockburn, y según algunos investigadores y autores, podría decirse que ha sido el precursor de la arquitectura orientada a microservicios.
Representación de la Arquitectura Hexagonal
Esta Arquitectura se suele representar mediante un Hexagono, en donde el número de lados representa un puerto, el cual nos permitirá ir hacia una capa interior o exterior de la aplicación, es decir, cada componente se podrá conectar con otro componente a través de un «puerto». La comunicación entre los puertos seguirán siempre un protocolo concreto que dependerá del objetivo o función que tenga. La comunicación será definida a través, por ejemplo de un API.
El número de puertos así como su granularidad o tamaño es algo que puede variar, en algunos casos un único puerto puede ser suficiente, por ejemplo un único consumidor de un evento; y en otras ocasiones podremos tener múltiples puertos por ejemplo por cada caso de uso.
El Adapatador, que aparte define un patrón de software, podríamos definirlo como el pegamento, entre los componentes de nuestra aplicación y el mundo exterior. Pueden existir uno o varios adaptadores, y serán los encargados de intercambiar la información del interior con el exterior y viceversa.
La idea principal detrás de este tipo de arquitectura, es crear un componente central o núcleo rodeados de interfaces a través del cual se pueda acceder. Es decir, lo que se propone es un núcleo central, que ocuparía el hexagono más interior, en el que se tendrían los dominios y los repositorios, que expondrían un API o Interfaces para poder obtener datos a partir de ellos.
DDD en la Arquitectura Hexagonal
Uno de los principios que podrían cuadrar y funcionar muy bien con la Arquitectura Hexagona es el DDD o Domain-driven design. Este tipo de desarrollo de software busca crear capas a través de dominios y desarrollar y envolver el negocio de la aplicación.
Ventajas de la Arquitectura Hexagonal
Cambios de Framework
En muchas ocasiones se podrá querer cambiar de framework por ejemplo de uno no reactivo a uno que permita la programación reactiva. En estos casos este tipo de arquitectura nos facilitará mucho el camino para poder llevar a cabo este tipo de cambios.
Inyección de dependencias
Este tipo de arquitectura esta muy bien definida y acoplada para usarlo con Inyección de Dependencias, ya que nos facilitará la comunicación y el acceso entre las diferentes capas.
Facilitar las labores de Testing
La Arquitectura Hexagonal nos va a permitir a tener el código de nuestra aplicación dividido y separado en capas. Esta separación nos va a permitir y a facilitar el hacer test de las diferentes partes de manera aislada.
Agnóstico al mundo exterior
Como el núcleo de nuestra aplicación va a estar aislado a través de un API o Interfaces, será totalmente agnóstico a la manera en la que se acceda.
La aplicación recibirá una petición de acceso a través de un Script, Http, etc… Y está se irá comunicando entre las diferentes capas a través de sus puertos y adaptadores.
Negocio e Infraestructura diferenciados
Gracias al uso de esta arquitectura, el negocio o lógica de nuestra aplicación se encontrará aislado de la infraestructura siendo totalmente independientes uno del otro .
Desventajas de la Arquitectura Hexagonal
Aumentará la complejidad
Al tener que crear interfaces para comunicar entre las diferentes capas, la complejidad de la aplicación suele aumentar con frecuencia.
El equipo de desarrollo tendrá que tener muy claro los principios básicos y como implementarlos, ya que sino podrá incurrir en errores y hacer una aplicación menos mantenible y difícil de seguir.
Mantenimiento
Si es una aplicación de un considerable tamaño, tendrá muchas capas y estas capas, tendrás sus respectivas Interfaces con sus implementaciones en los diferentes niveles.
Esto provocará un mayor coste en su mantenimiento, debido al aumento por ejemplo de clases si estas en Java. Pero gracias a este sobre esfuerzo tendremos un gran nivel de aislamiento entre las diferentes capas.
Ejemplo de Arquitectura Hexagonal en Spring Boot
A continuación vamos a realizar un ejemplo de este tipo de Arquitectura en Spring Boot. Para ello, vamos a realizar un API en la que se obtendrán los datos de un usuario y se guardará un usuario. Estos datos estarán en una base de datos en memoria como H2 a través de Spring Data.
Vamos a dividir la aplicación en tres capas bien diferenciadas, la primera capa, será el dominio, en la que se encontrará el objeto de dominio de Usuario.
La segunda capa será la capa de infraestructura, que será la responsable del funcionamiento del framework. En nuestro caso se encargar de crear los beans, y las conexiones a base de datos.
Y finalmente la capa de aplicación que será la encargada de tener la lógica de negocio.
En nuestro ejemplo no usamos Domain Drive Design (DDD), por lo que la interfaz del repositorio se encuentra en aplicación, ya que funciona como un puerto. Y el adaptador (su implementación) en infraestructura. En cambio, si nuestro ejemplo se basase en DDD debería ir la interfaz del repositorio en Dominio.
Lo mejor para entender este ejemplo es echar un vistazo en nuestro ejemplo de Github.
La estructura básica del proyecto será la siguiente:
En este ejemplo podemos ver bien diferenciadas las tres capas de una aplicación con Arquitectura Hexagonal. Además te servirá como ejemplo de aplicación con Spring Data.
Como hemos podido ver en el ejemplo que hemos creado haciendo uso de Spring boot y Spring Data, la comunicación entre las diferentes capas ha sido creando interfaces y haciendo uso de mappers para convertir estos objetos.
Conclusión
Si quieres ver un ejemplo de esta arquitectura basada en una aplicación con Spring Data, echa un vistazo en github.
Espero que este artículo de Ejemplo de Arquitectura Hexagonal en Spring Boot, haya sido de utilidad si tienes alguna duda o sugerencia no dudes en comentarlo o contactar a través de Facebook o Twitter. Y si te ha gustado compártelo en tus redes sociales.
Quizás te podrían interesar los siguientes artículos:
Seguridad para desarrolladores en Java
UserRepository no debería estar en la capa de dominio?
Hola Fernando, se establece userRepository en la capa de aplicación porque lleva lógica de negocio, de esta manera se puede aislar tu objeto de dominio de lo que sería lógica de negocio, haciendo este dominio agnóstico a la aplicación. Por qué piensas que debería ir en la capa de Dominio?
Es que al final solo inyecta las operaciones de BD y realmente no lleva logica de negocio, la logica la lleva el Service u otra clase que lleve esa logica por lo que tampoco le veo el caso de que el repository este en la capa de application a menos que sea una implementacion para hacer criterias u otras cosas
Realmente es una interfaz de operaciones de BBDD lo que tienes en el application, no es lógica es únicamente la comunicación que realizarás su inyección en infraestructure.
Nosotros solemos ponerlo siempre en dominio, pero soin embargo, creo que tienes razon y deberían ir en aplicacion… pero cuando podria ir en dominio? o nunca podría/debería ir en dominio?
He visto un caso que tenian algo asi:
INFRA: SingUpController
APPLICATION: SignUpUseCase
DOMAIN: StudentFinder, Student, StudentRepository
Como ves metian el StudenRepository en dominio… aunque ahora mismo no se decirte el porqué…
Otro ejemplo que hacían:
INFRA: VideoPutController
APPLICATION: VideoCreator
DOMAIN: VideoFinder, Video, VideoRepository
El uso de arquitectura hexagonal a veces es muy abierto y en función de las necesidades cada uno hace sus ajuste. Desde mi punto de vista el dominio debería de quedar aislado y no tener una mezcla con el repositorio. Como repositorio, lo puedes ver en el ejemplo, podrías tener una interfaz en application e inyectarlo desde la infraestructura que tendrá comunicación con la Base de Datos. Por ejemplo, así se facilitaría llevarte el dominio a otro framework sin tener que realizar cambios (dentro del mismo lenguaje).
Pero Noel, te contradices.
En el post, la primera imagen con la arquitectura, metes el repositorio en el dominio. Al final comentas que es aplicación.
Yo, creo que en el repositorio nunca vas a acceder a elementos de la aplicación o de la infraestructura.
O sea, en el repositorio no vas a poner una dependencia a un elemento de esas 2 capas.
No sé, yo la veo como dominio y de hecho, en un flujo de datos de ejemplo, se entra por un controlador, de ahí a su caso de uso, que accede a bbdd usando entidades por ejemplo, que se devuelve al servicio y este al controlador. De fuera (controlador) hacia dentro (dominio) y de dentro, hacia afuera.
¡Un saludo!
Hola Marcos
La interfaz de Repositorio va en Dominio si utilizas Domain Driven Design, por lo que en ese caso sí debería ir en Dominio si haces uso de DDD. En cambio, que es el caso del ejemplo, al no hacer uso de DDD la interfaz del repositorio va en la capa de aplicación, ya que es un puerto y luego en infraestructura tenemos la implementación, es decir, el adapatador.
Hola, Noel. Efectivamente, tras mi comentario seguí leyendo información y entendí lo que querías decir y el por qué de tu imagen.
Disculpa el malentendido.