Clean Architecture DDD
Clean Architecture DDD
Clean Architecture DDD
html
https://github.com/ivanpaulovich/clean-architecture-manga
https://github.com/edittler/clean-architecture
Robert Martin (Uncle Bob) analizó las propuestas de las arquitecturas en capas, hexagonal y
screaming (Domain Driven Design), y las combinó para dar lugar a la “arquitectura limpia”.
Robert Martin, más conocido como Tío Bob (Uncle Bob en inglés), plantea que la
arquitectura de un software debe gritar cuál es el uso de dicho software. Así como al ver
planos de edificios, si uno ve que el edificio posee un baño, cocina, comedor,
dormitorios, la arquitectura grita que es una casa familiar. De esta manera, al visualizar
la arquitectura de un software, se debería notar cual es el uso del mismo. La arquitectura
no debería indicar cuál es el framework o herramientas usadas para su construcción.
CONCEPTOS PREVIOS
Arquitectura Hexagonal
El objetivo de esta arquitectura es permitir que una aplicación sea dirigida por usuarios,
programas o pruebas, y desarrollada y probada de forma aislada de cualquiera de sus
dispositivos y bases de datos en tiempo de ejecución.
- La forma de patata azul en el centro es la capa de dominio y hay razones para ello. Cada
dominio de negocios tiene sus propias reglas, reglas de negocios muy específicas, que
es la razón de su forma indefinida. Por ejemplo, diseñé nuestra capa de dominio con
bloques de construcción DDD.
- La aplicación tiene una forma hexagonal porque cada uno de sus lados tiene protocolos
específicos.
- Los puertos y adaptadores se implementan fuera de la aplicación como complementos.
- Externamente tenemos otros sistemas.
La dirección de las dependencias va hacia el centro, por lo que la capa de dominio no conoce la
capa de aplicación, pero la capa de aplicación depende del dominio, la misma regla se aplica a
las capas externas.
Las reglas de negocio son las reglas detalladas, que encapsulan los campos y restricciones de la
entidad. También las reglas de negocios son los casos de uso que interactúan con múltiples
entidades y servicios. Juntos crean un proceso en la aplicación, deben mantenerse durante
mucho tiempo.
Las reglas de negocios y los casos de uso deben implementarse dentro de la capa de aplicación
y deben mantenerse durante la vida del proyecto. Por otra parte, todo lo que da soporte para
capacidades externas son solo detalles externos, pueden ser reemplazados por diferentes
razones, y no queremos que las reglas de negocio se acoplen a ellas.
Detalles externos
Estos son detalles externos comunes que pueden ser burlados, falsificados o que su
implementación concreta puede ser reemplazada por diferentes motivos. Le sugiero que
aplace su implementación mientras descubre más del dominio. Tenga en cuenta la cita del tío
Bob:
Visual Studio facilita la adición de bibliotecas para Reflexión, Serialización, Seguridad y muchos
otros paquetes Nuget en nuestros proyectos. El problema comienza cuando agregamos estas
bibliotecas a nuestra aplicación y dominio. Estas bibliotecas son solo detalles y deben quedar
fuera de la capa de aplicación.
Esa es la idea principal detrás de la Arquitectura Hexagonal, siempre que nuestra aplicación
requiera un servicio externo, usamos el Puerto (una interfaz simple) e implementamos el
Adaptador detrás de la abstracción.
ARQUITECTURA LIMPIA
Todas las arquitecturas tienen el mismo objetivo común, que es la “separación de intereses”,
para dar como resultado sistemas que son:
La regla principal que hace que esta arquitectura funcione es la regla de dependencia. Esta
regla dice que las dependencias del código fuente solo pueden apuntar hacia adentro. Nada en
un círculo interno puede saber nada acerca de algo en un círculo exterior. En particular, el
nombre de algo declarado en un círculo exterior no debe ser mencionado por el código en el
círculo interno. Eso incluye, funciones, clases, variables, o cualquier otra entidad de software
nombrada.
De la misma manera, los formatos de datos utilizados en un círculo exterior no deben ser
utilizados por un círculo interno, especialmente si esos formatos son generados por un
framework en un círculo externo. No queremos que nada en un círculo exterior afecte los
círculos internos.
Entidades
Las entidades encapsulan las reglas de negocio de toda la empresa. Una entidad puede ser un
objeto con métodos, o puede ser un conjunto de funciones y estructuras de datos. No importa,
siempre y cuando las entidades puedan ser utilizadas por muchas aplicaciones diferentes en la
empresa.
Si no tiene una empresa y solo está escribiendo una aplicación, estas entidades son los objetos
comerciales de la aplicación. Encapsulan las reglas más generales y de alto nivel. Es menos
probable que cambien cuando algo externo cambia. Por ejemplo, no esperaría que estos
objetos se vieran afectados por un cambio en la navegación de la página o por la seguridad.
Ningún cambio operacional en ninguna aplicación en particular debe afectar la capa de la
entidad.
Casos de uso
El software en esta capa contiene reglas de negocio específicas de la aplicación. Encapsula e
implementa todos los casos de uso del sistema. Estos casos de uso orquestan el flujo de datos
hacia y desde las entidades, y dirigen a esas entidades a utilizar sus reglas de negocios en toda
la empresa para lograr los objetivos del caso de uso.
No esperamos que los cambios en esta capa afecten a las entidades. Tampoco esperamos que
esta capa se vea afectada por cambios en las externalidades, como la base de datos, la interfaz
de usuario o cualquiera de los marcos comunes. Esta capa está aislada de tales
preocupaciones.
Sin embargo, esperamos que los cambios en el funcionamiento de la aplicación sí afecten a los
casos de uso y, por lo tanto, el software en esta capa. Si los detalles de un caso de uso
cambian, entonces algunos códigos en esta capa ciertamente se verán afectados.
Adaptadores de interfaz
El software en esta capa es un conjunto de adaptadores que convierten los datos desde el
formato más conveniente para los casos de uso y las entidades, al formato más conveniente
para algún agente externo, como la BD o la Web. Es esta capa, por ejemplo, la que contendrá
por completo la arquitectura MVC de una GUI. Los presentadores, vistas y controladores
pertenecen todos a esta capa. Es probable que los modelos sean sólo estructuras de datos que
pasan de los controladores a los casos de uso y luego regresan de los casos de uso a los
presentadores y las vistas.
De manera similar, los datos se convierten, en esta capa, desde la forma más conveniente para
las entidades y los casos de uso, a la forma más conveniente para cualquier estructura de
persistencia que se esté utilizando, es decir, la base de datos. Ningún código hacia el interior
de este círculo debe saber nada sobre la base de datos. Si la base de datos es una base de
datos SQL, entonces todo el SQL debe estar restringido a esta capa, y en particular a las partes
de esta capa que tienen que ver con la base de datos.
También en esta capa se encuentra cualquier otro adaptador necesario para convertir datos de
algún formulario externo, como un servicio externo, al formulario interno utilizado por los
casos de uso y las entidades.
Esta capa es donde van todos los detalles. La web es un detalle. La base de datos es un detalle.
Mantenemos estas cosas en el exterior donde pueden hacer poco daño.
Por ejemplo, considere que el caso de uso debe llamar al presentador. Sin embargo, esta
llamada no debe ser directa porque eso violaría la Regla de dependencia: ningún nombre en
un círculo exterior puede ser mencionado por un círculo interno. Así que tenemos el caso de
uso, llamar a una interfaz (que se muestra aquí como Puerto de salida del caso de uso) en el
círculo interno, y hacer que el presentador en el círculo externo lo implemente.
La misma técnica se utiliza para cruzar todos los límites en las arquitecturas. Aprovechamos el
polimorfismo dinámico para crear dependencias de código fuente que se oponen al flujo de
control para que podamos cumplir con la Regla de dependencia, sin importar en qué dirección
vaya el flujo de control.
Entonces, cuando pasamos datos a través de un límite, siempre será en la forma más
conveniente para el círculo interior.
Conclusión
Cumplir con estas reglas simples no es difícil, y le ahorrará muchos dolores de cabeza en el
futuro. Al separar el software en capas y cumplir con la Regla de dependencia, creará un
sistema que es intrínsecamente comprobable, con todos los beneficios que esto implica.
Cuando cualquiera de las partes externas del sistema se vuelven obsoletas, como la base de
datos o el marco web, puede reemplazar esos elementos obsoletos con un mínimo de
esfuerzo.
POSIBLES IMPLEMENTACIONES
CAPA APPLICATION
Vamos a profundizar en las Reglas de Negocios de Aplicación implementadas por los Casos de
Uso en nuestro Contexto Limitado. Como dijo el tío Bob en su libro Arquitectura limpia:
“Del mismo modo que los planes para una casa o una biblioteca gritan sobre los casos de
uso de esos edificios, también lo debe hacer la arquitectura de una aplicación de software
sobre los casos de uso de la aplicación.”
Las implementaciones de casos de uso son módulos de primera clase en la raíz de esta capa. La
forma de un Caso de Uso es un objeto Interactor que recibe una Entrada, haga un trabajo y
luego pase la Salida a través de la persona que llama. Esa es la razón por la que soy un
defensor de las carpetas de características que describen los casos de uso y dentro de ellas las
clases necesarias:
Con un primer vistazo de las carpetas de soluciones, se puede crear una idea del propósito de
este software. Parece que puede administrar su cuenta de banco, por ejemplo, puede
depositar o retirar dinero. A continuación vemos la comunicación entre las capas:
La aplicación expone una interfaz (puerto) a la capa UI y otra interfaz (otro puerto) a la capa de
infraestructura. Lo que ha visto hasta aquí es que Enterprise + Application Business Rules se
aplica sin dependencias de marcos o sin acoplamiento de base de datos. Todos los detalles
tienen abstracciones que protegen las Reglas de Negocios que deben ser acopladas a cosas
tecnológicas.
En nuestra implementación tenemos las siguientes carpetas de características para cada caso
de uso:
- Request: una estructura de datos para la entrada del usuario (accountId y
monto).
- Un controlador con una acción: este componente recibe el
DepositRequest, llama al caso de uso de depósito apropiado, el cual
realiza un procesamiento y luego pasa la salida a través de la instancia de
Presenter.
- Presentador: convierte la salida al modelo.
- Modelo: esta es la estructura de datos de retorno para aplicaciones MVC.
builder.RegisterType<Context>()
.WithParameter(new
TypedParameter(typeof(DbContextOptions), optionsBuilder.Options))
.InstancePerLifetimeScope();
//
// Register all Types in EntityFrameworkDataAccess namespace
//
builder.RegisterAssemblyTypes(typeof(InfrastructureException).Assembly
)
.Where(type =>
type.Namespace.Contains("EntityFrameworkDataAccess"))
.AsImplementedInterfaces()
.InstancePerLifetimeScope();
}
}