Este documento detalla foodtruacker, un proyecto que implementa diseño basado en dominios (DDD), CQRS y Event Sourcing. Utiliza ASP.NET Core y se centra en mejorar la capacidad de mantenimiento en dominios empresariales complejos. El proyecto utiliza un caso de negocio ficticio simplificado con fines ilustrativos. Esta explicación detallada cubre las motivaciones, las características, los detalles de implementación y las tecnologías relevantes.
foodtruacker - Implementación de DDD, CQRS y Event Sourcing
Este proyecto impulsado por eventos utiliza principios, marcos y arquitecturas, todos centrados en la idea de mejorar la mantenibilidad cuando se trata de sistemas que reflejan dominios comerciales complejos. La API web de la aplicación se basa en el marco ASP.NET Core de Microsoft e implementa un diseño basado en dominios, así como los patrones CQRS y Event Sourcing. Un caso de negocio ficticio sienta las bases de este proyecto y es el resultado de un taller de eventos.
Tenga en cuenta: el dominio empresarial ficticio introducido en este proyecto está muy simplificado y solo debe verse como un proveedor de casos de uso identificables.
Motivación
Dado que no siempre es mejor utilizar operaciones CRUD y objetos POCO en proyectos con dominios comerciales bastante complejos, decidí crear este proyecto como una implementación práctica de mi investigación e interés en el diseño impulsado por dominios (DDD). enfoque de desarrollo de software.
Dado que el caso de negocio ficticio presentado en este proyecto está fuertemente impulsado por eventos, decidí implementar también los patrones CQRS y Event Sourcing. Ambos me llamaron la atención mientras investigaba para este proyecto y van bien con DDD.
Características
Descripción general
Este proyecto consta de una aplicación API web ejecutable y varios componentes funcionales, cada uno de ellos proporcionado a través de bibliotecas de clases. El código está organizado por espacios de nombres. En las aplicaciones ASP.NET Core creadas en Visual Studio, los espacios de nombres, de forma predeterminada, se crean automáticamente a partir de la estructura de carpetas de los proyectos. Consulte el siguiente diagrama para obtener una descripción general de la estructura de carpetas (y espacio de nombres) de este proyecto:
Introducción
Asalto de eventos
Un formato de taller flexible para la exploración colaborativa de dominios empresariales complejos, inventado por Alberto Brandolini. Es una metodología extremadamente liviana para mejorar, visualizar, explorar y diseñar rápidamente flujos y procesos comerciales dentro de su organización.
El taller consta de un grupo de personas con diferentes conocimientos que utilizan notas adhesivas de colores para diseñar de forma colaborativa procesos comerciales relevantes. Es obligatorio que un taller de EventStorming tenga presentes a las personas adecuadas y tenga suficiente superficie para colocar las notas adhesivas. Las personas requeridas suelen incluir aquellas que conocen las preguntas a formular (normalmente desarrolladores) y aquellas que conocen las respuestas (expertos en el dominio, propietarios de productos).
El objetivo de este taller es que los participantes aprendan unos de otros, revelen y refuten conceptos erróneos y, por ejemplo, en este proyecto de GitHub, sientan las bases para el desarrollo de una solución de software basada en eventos que refleje un dominio empresarial correlacionado.
Diseño basado en dominio (DDD)
Un enfoque para el desarrollo de software que centra el desarrollo en la programación de un modelo de dominio que tiene una rica comprensión de los procesos y reglas de un dominio empresarial correlacionado. El término "Diseño impulsado por dominios" fue acuñado por Eric Evans en su libro del mismo título.
DDD tiene como objetivo facilitar la creación de aplicaciones complejas y se centra en tres principios básicos:
El libro de Eric Evans define algunos términos comunes para el diseño basado en dominios:
Modelo de dominio
Un sistema de abstracciones que describe los procesos y políticas de un dominio empresarial y se utiliza para manejar las tareas requeridas asociadas a ese dominio.
Lenguaje ubicuo
Palabras y declaraciones para ciertos elementos del ámbito empresarial. Para evitar conceptos erróneos, todos los miembros del equipo deben adoptar ciertos términos, generalmente los utilizados por los expertos en el dominio.
Contexto acotado
Un límite conceptual dentro del cual se define y es aplicable un modelo de dominio particular. Por lo general, esto representa un subsistema o un campo de trabajo. Se trata principalmente de una delimitación lingüística, en la que cada contexto delimitado tiene su propio lenguaje ubicuo.
Por ejemplo: Gestión de clientes donde un usuario se llama "cliente".
El libro de Eric Evans diferencia aún más ciertas partes del modelo de dominio. Por nombrar algunos:
Entidad
Un objeto que se define por su identidad más que por sus atributos.
Ej: Una persona siempre seguirá siendo la misma, sin importar la elección de chaqueta, color de cabello o idioma que hable en un momento determinado.
Objeto de valor
Un objeto que se define únicamente por el valor de sus atributos. Los objetos de valor son inmutables y no tienen una identidad única. Los objetos de valor pueden ser reemplazados por otros objetos de valor con los mismos atributos.
Por ejemplo: al enfocar a una persona, un par de gafas de sol rotas se puede reemplazar fácilmente por un par de gafas de sol nuevas y de igual apariencia.
Agregar
Un grupo de una o más Entidades y Objetos de Valor opcionales, unificados para ser una única unidad transaccional. Una Entidad formará la base del Agregado y, por lo tanto, se declara raíz del Agregado. Todas las propiedades de sus Entidades colaboradoras y Objetos de valor solo pueden ser accesibles a través de esta única Entidad base. Un Agregado siempre debe estar en un estado consistente. En la programación orientada a objetos, esto normalmente se hace mediante el uso de configuradores privados y captadores protegidos.
Por ejemplo: en un contexto de venta de automóviles, un automóvil (Entidad) se define por su número de identificación del vehículo. Este automóvil puede tener cuatro ruedas (Objetos de valor), que pueden necesitar ser reemplazadas después de un cierto tiempo.
Evento de dominio
Un objeto que se crea como resultado de la actividad dentro del Modelo de Dominio. Se utiliza para almacenar y reenviar información relacionada con esta actividad. Los eventos de dominio generalmente se crean para aquellas actividades que los expertos del dominio consideran relevantes.
Arquitectura hexagonal (Puertos y Adaptadores)
Un patrón de arquitectura utilizado en el diseño de software, propuesto por Alistair Cockburn en 2005. El patrón tiene como objetivo lograr un alto grado de mantenibilidad y describe una aplicación en tres capas. Cada capa se comunica con las capas adyacentes mediante interfaces (puertos) e implementaciones (adaptadores):
La regla clave en este patrón de arquitectura es que las dependencias sólo pueden apuntar hacia adentro. Nada en un círculo interno puede saber nada acerca de algo en un círculo externo. Cualquier dependencia que desee apuntar hacia afuera, por ejemplo, llamar a una base de datos desde la capa de aplicación, debe crearse una instancia mediante inversión de control (IoC) o inyección de dependencia (DI).
CQRS usando MediatR (un marco de mensajería prediseñado)
CQRS significa Segregación de responsabilidad de comando/consulta y fue descrito por primera vez por Greg Young en 2010. Se basa en el principio de Separación de consulta de comando (CQS) y permite la separación de operaciones de lectura y escritura. CQS afirma:
La mejora de CQRS sobre CQS es que esos comandos y consultas se tratan como modelos en lugar de métodos. Estos modelos se pueden enviar como objetos en un punto, para luego ser manejados por sus respectivos controladores requeridos en otro punto del sistema, cada uno de los cuales devuelve sus modelos de respuesta para una segregación clara de cada acción.
El patrón mediador permite implementar comandos/consultas y controladores débilmente acoplados, utilizando un objeto mediador. Los objetos ya no se comunican directamente entre sí, sino a través del mediador.
El marco MediatR es una implementación de código abierto del patrón mediador, creado por Jimmy Bogard. Se utilizará en este proyecto para la comunicación entre la capa de marco y la capa de aplicación. También se utilizará para proyectar datos desde la base de datos de Comando a la base de datos de Consulta.
Abastecimiento de eventos
Un patrón de diseño arquitectónico para almacenar cada cambio en el estado de una aplicación, en lugar de almacenar solo el estado actual de los datos en un dominio. Este patrón fue introducido por Greg Young y desde entonces ha sido testigo de numerosas adopciones.
El patrón pretende capturar cada cambio en el estado de una aplicación como un objeto de evento. Estos objetos de evento luego se almacenan, en la secuencia de ocurrencia, de manera que solo se agreguen. Esto no sólo permite recrear el estado actual de un objeto a lo largo de la secuencia de eventos que han sucedido hasta el momento, sino que, en última instancia, permite retroceder en el tiempo y recrear el estado del objeto en un momento dado.
Una cuenta bancaria puede ser un buen ejemplo del principio de Event Sourcing. Cada vez que se retira o deposita dinero, en lugar de simplemente actualizar el saldo actual, se registra el monto del cambio. Luego, el saldo actual se calcula repasando la secuencia de eventos, con su correspondiente información sobre cuánto dinero se retiró o depositó cada vez.
El abastecimiento de eventos funciona bien con el diseño basado en dominios, ya que es ideal para almacenar eventos de dominio, activados por el modelo de dominio con cada solicitud de cambio.
Event Sourcing también se beneficia enormemente de CQRS. En lugar de tener que realizar una consulta en la base de datos de abastecimiento de eventos, que tendría que revisar todos los eventos registrados relacionados con el objeto que se solicita para recrear el estado actual, esta consulta se puede realizar en una base de datos de consultas dedicada. Esta base de datos de consultas se actualiza mediante sus propios controladores de eventos, escuchando los mismos eventos que se envían inmediatamente después de agregarlos a la base de datos de abastecimiento de eventos. Estos procesos de actualización se denominan Proyecciones.
Esta separación de bases de datos también sienta las bases para un enorme potencial en escalabilidad y optimización del rendimiento. Se pueden crear y mantener sincronizadas varias instancias de la base de datos de Query simplemente haciendo que sus controladores de eventos escuchen los eventos que se envían desde el cliente de base de datos de suministro de eventos justo después de que se produzca un cambio relevante en el estado de una aplicación. La elección del tipo de base de datos, así como el grado de desnormalización de los datos, optimizados por consulta, pueden mejorar enormemente el rendimiento.
Esta actualización constante del modelo de lectura puede ocurrir de forma sincrónica o asincrónica. Esto último tiene el costo de la coherencia final, ya que el modelo de lectura no está sincronizado con el modelo de escritura durante un pequeño lapso de tiempo (generalmente milisegundos).
Núcleo compartido
Una biblioteca común para la capa de dominio, que contiene clases base comunes de diseño basado en dominio, entidades de dominio, objetos de valor, etc., que se comparten entre contextos delimitados.
Empezando
Para que este proyecto esté en funcionamiento tal como está, no dude en seguir estos pasos:
Requisitos previos
Configuración
Inicie https://localhost:5001/swagger/index.html en su navegador para ver la documentación Swagger de su API.
Utilice Swagger, Postman o cualquier otra aplicación para enviar una solicitud POST a https://localhost:5001/api/Administration/Register para registrar su cuenta de administrador inicial. Envía el siguiente objeto:
Busque en la aplicación de consola o cualquier salida reconfigurada para los registros de la aplicación. Después de cualquier registro exitoso de un usuario, debe haber un enlace de verificación de correo electrónico, proporcionado por EmailService, escrito en los registros. Copie y pegue esta URL en su navegador y presione Intro para completar el registro. Siéntase libre de cambiar o ampliar esta implementación incorrecta de un servicio de correo electrónico ;-)
Ya está todo listo. Inicie sesión a continuación.
Inicie http://localhost:2113/ en su navegador para ver la GUI de EventStoreDB. Abra la pestaña "Explorador de transmisiones" para ver todos los eventos almacenados.
Las pruebas se pueden ejecutar ejecutando:
Tecnologías
Este proyecto utiliza las siguientes tecnologías/paquetes NuGet:
Recursos / Lectura recomendada
Alberto Brandolini:
https://www.eventstorming.com
Vaughn Vernon:
https://dddcommunity.org/wp-content/uploads/files/pdfarticles/Vernon2011_1.pdf
https://dddcommunity.org/wp-content/uploads/files/pdfarticles/Vernon2011_2.pdf
https://dddcommunity.org/wp-content/uploads/files/pdfarticles/Vernon2011_3.pdf
Alistair Cockburn:
https://web.archive.org/web/20180822100852/http://alistair.cockburn.us/Hexagonal+architecture
Robert C. Martin (tío Bob):
https://blog.cleancoder.com/uncle-bob/2012/08/13/the-clean-architecture.html
César de la Torre, Bill Wagner, Mike Rousos:
https://docs.microsoft.com/en-us/dotnet/architecture/microservices/
Greg joven
https://cqrs.files.wordpress.com/2010/11/cqrs_documents.pdf
https://cqrs.wordpress.com/documents/building-event-storage/
https://msdn.microsoft.com/en-us/library/jj591559.aspx
Martín Fowler:
https://www.martinfowler.com/bliki/CQRS.html
Jimmy Bogard:
https://github.com/jbogard/MediatR
https://www.youtube.com/watch?v=SUiWfhAhgQw
Diseño basado en dominios:
https://dddcommunity.org
https://thedomaindrivendesign.io
https://dotnetcodr.com/2013/09/12/a-model-net-web-service-based-on-domain-driven-design-part-1-introduction/
https://dotnetcodr.com/2015/10/22/domain-driven-design-with-web-api-extensions-part-1-notifications/
Arquitectura hexagonal:
https://fideloper.com/arquitectura-hexagonal
https://herbertograca.com/2017/09/14/ports-adapters-architecture/
Créditos
http://www.andreavallotti.tech/es/2018/01/event-sourcing-and-cqrs-in-c/
https://www.exceptionnotfound.net/real-world-cqrs-es-with-asp-net-and-redis-part-1-overview/
https://buildplease.com/pages/fpc-1/
https://dotnetcoretutorials.com/2019/04/30/the-mediator-pattern-in-net-core-part-1-whats-a-mediator/
https://itnext.io/why-and-how-i-implemented-cqrs-and-mediator-patterns-in-a-microservice-b07034592b6d