Clean Architecture + Springboot + JPA (Parte 2)

Jesus Ledesma
8 min readNov 29, 2020

--

Repositorio

Esta es la parte 2, la parte 1 es: https://jesusledesma.medium.com/clean-architecture-springboot-jpa-parte-1-458b69bdf06f

Contract Service

Ya tenemos nuestro Product que era uno de los objetos que necesitamos para generar nuestro Contract, ahora necesitamos un servicio que nos brinde un método para efectivamente crear el contrato

La clase ContractService, como es un servicio de un contrato debe estar en core/contract/service

ContractDocumentRepository

Para hacer más didáctico el tutorial guardaremos los contracts en una base de datos documental, esta bueno ver como aplicar Clean Architecture + JPA + NoSql

Comenzaremos creando una interfaz que será usada por los services y casos de usos, tal como hicimos con Product

Recibiremos un Contract en el método save para guardarlo

Reestructuración de paquetes

Si miramos la imagen anterior, podemos intuir que la estructura para nuestra base Documental será muy parecida a la de nuestra base Sql, por el cual reestructuramos los paquetes de la siguiente forma

Esta idea se podría extender a todos los tipos de bases de datos que manejemos como por ejemplo key-value, column-oriented o graph

Modelo JPA

JPA por medio de annotations nos permite a través de un ORM, mapear nuestros objetos a documentos en nuestra base de datos

Creamos un objeto ContractDocument para lograr lo mencionado

JPA Repository DAO

Al igual que con Product crearemos un DAO el cual tendrá los métodos para conectarnos con la base de datos. Esta vez en vez de extender de CrudRepository, lo haremos de MongoRepository teniendo el mismo beneficio de ahorrarnos mucho código

Contract Document Adapter

Llegó el momento de conectar nuestra “capa 2 (Servicios)” con la “capa 4 (F y D)” por medio de nuestro adapter. Podemos ver como los conceptos se repiten

Al igual que con ProductSqlAdapter, tenemos como dependencia el Dao y en mi caso ModelMapper para evitar hacer a mano el mapeo de objeto jpa a objeto de mi dominio y viceversa

Contract Service Terminado

Así luce contractService terminado, haciendo uso de todo lo implementado

Contract Controller Terminado

Recordemos que anteriormente el controller quedó solo usando ProductService para obtener el producto, ya que lo necesitábamos para crear un contrato. Un Contract al crearse se le genera un id que sumado a los templatesNames que obtenemos del producto, logramos generar un ContractOutput que es el objeto de salida del contrato

Este es el código final de ContractController

O una alternativa del mismo código un poco más funcional

Inyección de dependencias

Spring Config

Con spring estamos acostumbrados a usar @Autowire en todos nuestros servicios para que se inyecten los beans, y no estar haciendo a mano los new de cada clase. Pero usar estas annotations en nuestra capa 2 (Servicios) nos acopla a un framework, por eso la inyección de dependencias y creaciones de beans estarán en la capa 4 (F y D)

Lo primero que haremos es crear un nuevo paquete llamado application el cual contendrá la clase SpringConfig

Esta clase es la encargada de crear los beans que nuestro framework necesita y luce así

Importante

Algo conceptual que tenemos que entender en que en este caso la clase se llama SpringConfig, lo cual significa que es una configuración diseñada para este framework, pero en este paquete podriamos tener configuraciones para más de un framework o inclusive ninguno. Es una de las ventajas de usar clean-architecture. Que con unas simples configuraciones tenemos mucha más flexibilidad sin necesidad de cambiar la “capa 1 (Dominio)” y “capa 2 (Servicios)” de nuestras aplicacion

Manual Config

Spring no es la única manera de manejar nuestras dependencias, existen más posibilidades para todos los gustos

Existe una postura que expone no tener ningún framework en nuestra app, y manejarse solo con librerías, ya que los frameworks nos obligan a trabajar a su forma, por el cual no tenemos el 100% del control. Solo usariamos librerías para obtener features sin necesidad de codearlos.

Es una postura válida, en mi opinión, para lenguajes que no tienen un super framework como sucede con spring. Un ejemplo es Scala donde mucha gente no quiere usar Play!

Pero sinceramente para mi, si usamos clean-architecture, nos abstraemos del framework y estaría bueno aprovechar sus features sin acoplarnos gracias a las capas que manejamos

En el caso de nuestra app si usaramos una config manual, sería un código bastante parecido aunque enumerare las diferencias:

  • Crearemos las clases, en base a realizar varios new de objetos
  • Tendríamos métodos al igual que SpringConfig, para usar en la Clase Main
  • No usariamos las annotations de @configuration, @bean, etc
  • No intanciariamos nunca RestTemplate con el restTemplate de spring, si no que nuestra manera de realizar consultas web sería a partir del objeto de alguna librería o de forma nativa en java o con httpClient de java 9. O directamente usar RestTemplates en todos los casos a pesar de no usar el framework (https://stackoverflow.com/questions/39868792/using-spring-resttemplate-in-jax-rs-project)
  • Deberíamos obtener las variables de configuración como las de aplication.properties (RiskUrl) de otra forma, ya que no existiría @Value, o directamente hardcodeadas en el código cosa que no recomiendo
  • Los Dao no se obtendrían con @Autowire, ya que no serían una clase de JPA, si no una clase común de java, que realiza la conexión con la base de datos a partir de un driver, por ejemplo el driver de mySql o de hazelcast. Los Dao se instanciarian con new, al igual que todas las demás dependencias

Guice Config

Existe una tercera postura, también válida. Hace referencia a la idea de manejar nuestras app con la mayor cantidad de librerías posibles, y en el caso de necesitar un framework, que estos sean pequeños y cohesivos, es decir que cumpla una sola función (A diferencia de Spring que tiene muchas como manejo web, dependencias, jpa, etc)

Surgió a partir de criticar como un framework grande (spring por ejemplo), llena el pom de un montón de subdepencias las cuales muchas veces generan conflictos de versión con otras

Y dada situaciones como estas, se planteó no ser tan extremista como el caso anterior, es decir, si usar frameworks pero que sean puntuales y que hagan solo una cosa. En el caso de inyección de dependencias uno de los más conocidos en Guice de Google

Dejo un link para que puedan chequear cómo se usa https://www.baeldung.com/guice

Main

Reestructuración de paquetes

Una cosa es la clase “Main” punto de entrada de nuestro proyecto y otra cosa son las clases de configuración de dependencias. Hacemos esta distinción para tener un código más desacoplado y más claro. Por el cual podemos agrupar nuestras clases de configuración en un paquete y nuestras clases de arranque en otro

Spring Run

En el caso de la configuración de spring, debemos usar las annotations correspondientes para habilitar los repositorios Sql (JPA), Documentales (Mongo) y entidades que estos usan

Esta es nuestra clase de arranque de Spring, pero recordemos que si no usaramos spring, tendríamos otras clases dentro del paquete Run que corresponderian a las ideas mencionadas anteriormente en la sección de inyeccion de dependencias

Ahora solo falta configurar nuestros endpoint y nuestra aplicación estará 100% funcional

Web

Spring Controller

Lo primero que debemos hacer es crear un nuevo paquete dentro de application, lo llamaremos web. En este paquete están los controllers de spring, de otros frameworks o librerías nativas como javax RS

Usaremos @Autowire para inyectar el bean de ContractController que declaramos en un método de la clase de configuración de Spring

Y por medio de @PostMapping configuraremos el endpoint de nuestra spring app

Importante

Si no usaramos spring en el paquete web tendríamos otras clases que configurarian nuestros endpoints por ejemplo

Parte 3

En los próximos capítulos veremos:

  • Implementaciones de config manuales. Implementación manual de un Dao con un driver de H2. Implementación de inyección de dependencias manual. Parte web con java nativo usando java RS
  • Implementaciones usando pequeñas librerías y pequeños frameworks. Parte Web con un pequeño framework llamado spark. Inyección de dependencias con Guice
  • Cómo implementar una UI muy simple usando thymeleaf de Spring sin acoplarnos al framework

--

--

Responses (2)