What are events in DDD?

Eventos de Dominio en DDD: La Clave para un Código Escalable

hace 2 años

Valoración: 4.06 (4335 votos)

En el mundo del desarrollo de software, la búsqueda de código limpio, eficiente y escalable es constante. Dentro de este panorama, Domain Driven Design (DDD) emerge como una filosofía y un conjunto de patrones que nos guían hacia la creación de software que no solo cumple con su función, sino que también refleja de manera precisa el dominio del negocio que representa. En este artículo, nos adentraremos en uno de los pilares fundamentales de DDD: los eventos de dominio.

Índice de Contenido

¿Qué son los Eventos de Dominio?

Los eventos de dominio son, en esencia, tal como su nombre lo indica, eventos que ocurren dentro de nuestro dominio de negocio. Son notificaciones de que algo significativo ha sucedido, y estas notificaciones se transmiten a las partes interesadas dentro del mismo dominio que necesiten reaccionar ante estos sucesos. Imaginemos un escenario de comercio electrónico: ¿cómo sabría el servicio de marketing que se ha realizado una nueva venta si el servicio de ventas no le informa una vez que el pago ha sido procesado? La respuesta radica en los eventos de dominio.

What is DDD in data?
Domain-driven design (DDD) is a major software design approach, focusing on modeling software to match a domain according to input from that domain's experts. DDD is against the idea of having a single unified model; instead it divides a large system into bounded contexts, each of which have their own model.

Estos eventos nos permiten desacoplar componentes dentro de nuestra aplicación, promoviendo una arquitectura más flexible y mantenible. En lugar de que un componente dependa directamente de otro para realizar una acción secundaria, el primero simplemente levanta un evento que indica que algo ha ocurrido. Otros componentes, interesados en ese tipo de evento, pueden suscribirse a él y reaccionar de la manera que consideren oportuna.

El Caos de los Sistemas Legacy: Un Ejemplo Práctico

Para entender mejor la importancia de los eventos de dominio, comparemos su implementación con el enfoque común en los sistemas legacy. En estos sistemas, a menudo nos encontramos con código desordenado donde los controladores de la capa de infraestructura asumen responsabilidades que no les corresponden. Continuando con el ejemplo del e-commerce, consideremos un controlador llamado `AddItemToShoppingCartController`.

What does DDD stand for in development?
Domain-Driven Design (DDD) is a software development philosophy that emphasizes the importance of understanding and modeling the business domain. It is a strategy aimed at improving the quality of software by aligning it more closely with the business needs it serves.

Idealmente, este controlador debería enfocarse exclusivamente en añadir un ítem al carrito de compras. Sin embargo, en la práctica, es común que termine realizando acciones adicionales, como notificar al equipo de marketing sobre el ítem añadido. El objetivo de esta notificación podría ser, por ejemplo, enviar un correo electrónico al usuario si no completa la compra, recordándole los artículos que dejó en el carrito. De igual manera, podríamos querer notificar al equipo de Business Intelligence para fines estadísticos y de seguimiento de leads.

El resultado final es un controlador inflado, que se asemeja al siguiente ejemplo (en Typescript):

export class AddItemToShoppingCartController { constructor( private readonly addItemToShoppingCartHandler: AddItemToShoppingCartHandler, private readonly marketingEmailSender: MarketingEmailSender, private readonly salesBITracker: SalesBITracker ) {} async run(req: Request, res: Response): Promise<void> { const { item, userId } = req.body; await this.addItemToShoppingCartHandler.addItem(item, userId); await this.marketingEmailSender.send(item, userId); await this.salesBITracker.track(item); res.sendStatus(200); } } 

Este código, aunque funcional, presenta varios problemas:

  • Acoplamiento Fuerte: El controlador depende directamente de los servicios `MarketingEmailSender` y `SalesBITracker`. Cualquier cambio en estos servicios puede afectar al controlador.
  • Responsabilidad Única Violada: El controlador, que originalmente debía solo añadir ítems al carrito, ahora también se encarga de notificaciones de marketing y BI.
  • Dificultad para Pruebas: Probar este controlador de manera aislada se vuelve más complejo debido a sus dependencias adicionales.

Visualmente, la arquitectura resultante podría representarse de la siguiente manera, mostrando la sobrecarga del controlador y el acoplamiento generado:

(Descripción del diagrama: Un diagrama que muestra el `AddItemToShoppingCartController` conectado directamente a `MarketingEmailSender` y `SalesBITracker`, además del `AddItemToShoppingCartHandler`. Esto ilustra el rol de orquestación del controlador y el acoplamiento fuerte.)

DDD al Rescate: El Poder de los Eventos de Dominio

Domain-Driven Design, o Diseño Guiado por el Dominio, nos ofrece una alternativa elegante y efectiva para solucionar este tipo de problemas. DDD es una filosofía de desarrollo de software que pone el foco en el entendimiento y modelado del dominio del negocio. Su objetivo principal es mejorar la calidad del software alineándolo estrechamente con las necesidades del negocio.

Introducido por Eric Evans en 2003 en su libro "Domain-Driven Design: Tackling Complexity in the Heart of Software", DDD propone un conjunto de patrones y prácticas para gestionar la complejidad en el desarrollo de software, especialmente en dominios de negocio complejos.

What is strategic DDD?
Definition: Strategic DDD focuses on the high-level design of a software system. It involves understanding the business domain, defining bounded contexts, and mapping the relationships between them. Strategic DDD helps teams organize their work around the business's core needs.

Conceptos y Principios Clave de DDD

DDD se basa en una serie de principios fundamentales que guían el proceso de desarrollo:

  • Dominio Central (Core Domain): Identificar y priorizar el dominio central del negocio, aquel que realmente genera valor y diferencia a la organización.
  • Diseño Guiado por el Modelo (Model-Driven Design): Crear un modelo del dominio que sea la base del software, reflejando con precisión los conceptos y reglas del negocio.
  • Lenguaje Ubicuo (Ubiquitous Language): Establecer un lenguaje común compartido por desarrolladores y expertos del dominio, utilizado en el código, la documentación y la comunicación.
  • Colaboración Iterativa (Iterative Collaboration): Fomentar la colaboración continua entre técnicos y expertos del dominio para refinar el modelo y el software de manera iterativa.

Bloques de Construcción de DDD

Para construir software guiado por el dominio, DDD nos proporciona una serie de bloques de construcción:

  • Contextos Delimitados (Bounded Contexts): Definir límites lógicos dentro del sistema donde un modelo de dominio específico es aplicable. Cada contexto delimitado tiene su propio lenguaje ubicuo.
  • Entidades (Entities): Objetos con una identidad única y persistente a lo largo del tiempo, independientemente de sus atributos. Ejemplo: un cliente, un producto.
  • Objetos de Valor (Value Objects): Objetos definidos por sus atributos, sin identidad única. Son inmutables y reemplazables. Ejemplo: una dirección, un rango de fechas, una cantidad de dinero.
  • Agregados (Aggregates): Grupos de entidades y objetos de valor que se tratan como una unidad coherente. Tienen una entidad raíz (Aggregate Root) que controla el acceso y la consistencia del agregado.
  • Eventos de Dominio (Domain Events): Representaciones de sucesos significativos que ocurren dentro del dominio. Se utilizan para comunicar cambios entre diferentes partes del sistema de manera desacoplada.

Implementando DDD: Un Proceso Iterativo

La implementación de DDD es un proceso iterativo que se centra en:

  • Entender el Dominio: Trabajar estrechamente con expertos del dominio para comprender los procesos, reglas y entidades del negocio.
  • Crear el Modelo del Dominio: Desarrollar un modelo conceptual que represente el dominio, utilizando entidades, objetos de valor y agregados.
  • Desarrollar el Lenguaje Ubicuo: Establecer un vocabulario común que sea utilizado por todos los miembros del equipo.
  • Definir Contextos Delimitados: Identificar y delimitar los diferentes contextos dentro del dominio.
  • Implementar el Modelo: Traducir el modelo del dominio a código, utilizando los bloques de construcción de DDD.
  • Refinamiento Iterativo: Refinar continuamente el modelo y el software basándose en la retroalimentación de los expertos del dominio y los usuarios.

Tipos de Eventos de Dominio

Dentro del ámbito de los eventos de dominio, podemos distinguir principalmente dos tipos:

  • Eventos de Dominio Propiamente Dichos: Ocurren dentro de un mismo contexto delimitado. Son eventos internos que señalan cambios importantes dentro de ese contexto y se utilizan para mantener la consistencia y la lógica de negocio dentro del mismo. Suelen tener una carga útil (payload) ligera, ya que los suscriptores (listeners) se encuentran generalmente dentro del mismo servicio y sus necesidades son más conocidas.
  • Eventos de Integración: Se utilizan para comunicar cambios entre diferentes contextos delimitados. Son cruciales para mantener la consistencia de datos y la comunicación entre diferentes partes del sistema. Tienden a tener una carga útil más compleja y rica en información, ya que los suscriptores pueden estar en otros servicios o contextos, con necesidades diversas. A menudo, esto lleva a una comunicación más exhaustiva para asegurar que toda la información relevante se comparte eficazmente.

Volviendo al Ejemplo: Eventos de Dominio en Acción

Ahora, veamos cómo los eventos de dominio pueden mejorar nuestro ejemplo del carrito de compras. En lugar de que el `AddItemToShoppingCartController` se encargue de enviar notificaciones directamente, podemos hacer que levante un evento de dominio, por ejemplo, `ItemAddedToShoppingCartEvent`.

Este evento se publicaría dentro del dominio, y los servicios de marketing y BI, interesados en este tipo de evento, se suscribirían a él y reaccionarían de manera independiente. El controlador se simplificaría considerablemente:

export class AddItemToShoppingCartController { constructor( private readonly addItemToShoppingCartHandler: AddItemToShoppingCartHandler, private readonly domainEventPublisher: DomainEventPublisher ) {} async run(req: Request, res: Response): Promise<void> { const { item, userId } = req.body; await this.addItemToShoppingCartHandler.addItem(item, userId); this.domainEventPublisher.publish(new ItemAddedToShoppingCartEvent(item, userId)); res.sendStatus(200); } } 

Y la arquitectura se volvería más limpia y desacoplada:

(Descripción del diagrama: Un diagrama que muestra el `AddItemToShoppingCartController` publicando el `ItemAddedToShoppingCartEvent`. El 'Servicio de Marketing' y el 'Servicio de BI' están suscritos a este evento, mostrando una comunicación desacoplada.)

Las ventajas de este enfoque son evidentes:

  • Desacoplamiento: El controlador ya no depende de servicios externos. La comunicación se realiza a través de eventos.
  • Responsabilidad Única: El controlador se enfoca en su tarea principal: añadir ítems al carrito.
  • Mayor Escalabilidad y Mantenibilidad: Añadir nuevos suscriptores al evento no afecta al controlador ni a los suscriptores existentes. Los componentes se pueden desarrollar y desplegar de forma más independiente.
  • Mejoras en Pruebas: El controlador es más fácil de probar de manera aislada.

DDD y Otras Aproximaciones al Desarrollo de Software

DDD se complementa muy bien con otras metodologías y patrones:

  • Programación Orientada a Objetos (OOP): DDD y OOP se utilizan a menudo juntos. Los conceptos de DDD como entidades, objetos de valor y agregados se mapean naturalmente a clases en OOP.
  • Ingeniería Dirigida por Modelos (MDE): MDE se centra en crear modelos abstractos del sistema y generar código automáticamente a partir de ellos. DDD puede beneficiarse de MDE para la creación del modelo de dominio.
  • Segregación de Responsabilidad de Comando y Consulta (CQRS): CQRS separa las operaciones de lectura (consultas) de las operaciones de escritura (comandos). Aunque no es un requisito para DDD, CQRS puede complementar DDD proporcionando una separación clara de responsabilidades.
  • Event Sourcing: Este patrón almacena los cambios de estado del sistema como una secuencia de eventos. Combinado con DDD, proporciona una forma confiable y rastreable de gestionar los cambios de estado.

Críticas y Limitaciones de DDD

Si bien DDD ofrece numerosos beneficios, también presenta algunas limitaciones y críticas:

  • Complejidad: DDD es más adecuado para organizaciones complejas con un profundo conocimiento del dominio. Puede no ser necesario para aplicaciones sencillas.
  • Requiere Expertos del Dominio: DDD depende en gran medida de la colaboración con expertos del dominio. La falta de acceso a estos expertos puede dificultar la implementación de DDD.
  • Intensivo en Tiempo y Recursos: Desarrollar un lenguaje ubicuo, crear un modelo de dominio y refinarlo continuamente puede ser costoso en tiempo y recursos.
  • No Adecuado para Todos los Proyectos: DDD es más beneficioso en dominios complejos con lógica de negocio intrincada. Para aplicaciones simples, puede ser excesivo.
  • Curva de Aprendizaje: DDD tiene una curva de aprendizaje pronunciada para los desarrolladores.

DDD en Datos

DDD no se limita al código de la aplicación, sino que también se extiende al manejo de datos. El modelo de dominio debe reflejarse en la estructura de los datos, y las operaciones de acceso a datos deben realizarse a través de repositorios que abstraigan la persistencia. Esto permite que el dominio se mantenga agnóstico a la tecnología de base de datos.

What are events in DDD?
Domain events are quite literal — they are the events or occurrences within our domain that are then broadcasted to the rest of the domain experts in case these need to react to them. Dec 28, 2023

Mapeo de Contextos Delimitados a Microservicios

En arquitecturas de microservicios, los contextos delimitados de DDD a menudo se mapean a microservicios individuales. Esta correspondencia uno a uno es ideal, ya que mantiene los límites claros, reduce el acoplamiento y permite el despliegue y escalado independiente de cada microservicio. Sin embargo, también pueden existir relaciones uno a muchos o muchos a uno, dependiendo de las necesidades específicas del sistema.

Herramientas y Frameworks para DDD

Aunque DDD no depende de herramientas específicas, existen algunas que pueden facilitar su implementación, como:

  • Actifsource: Plugin para Eclipse que combina DDD con ingeniería dirigida por modelos y generación de código.
  • Context Mapper: Lenguaje específico de dominio y herramientas para DDD estratégico y táctico.
  • CubicWeb: Framework de código abierto para la web semántica, impulsado por un modelo de datos.
  • OpenMDX: Framework MDA de código abierto basado en Java.
  • Restful Objects: Estándar para mapear una API RESTful a un modelo de objetos de dominio.

Conclusión

Los eventos de dominio son una herramienta poderosa dentro del arsenal de DDD. Permiten construir sistemas más desacoplados, escalables y mantenibles, al tiempo que facilitan la comunicación entre diferentes partes del dominio. Si bien DDD puede tener una curva de aprendizaje y no ser adecuado para todos los proyectos, en dominios complejos, su aplicación, y en particular el uso de eventos de dominio, puede marcar una diferencia significativa en la calidad y el éxito del software.

Preguntas Frecuentes (FAQ)

  1. ¿Cuándo debo usar Eventos de Dominio?
    Debes usar eventos de dominio cuando necesites comunicar que algo importante ha ocurrido dentro de tu dominio a otras partes del sistema de manera desacoplada. Son especialmente útiles para implementar lógica de negocio que involucre efectos secundarios o notificaciones a otros componentes.
  2. ¿Cuál es la diferencia entre Eventos de Dominio e Eventos de Integración?
    Los eventos de dominio ocurren dentro de un mismo contexto delimitado, mientras que los eventos de integración se utilizan para comunicar cambios entre diferentes contextos delimitados. Los eventos de integración suelen ser más complejos y ricos en información.
  3. ¿Cómo implemento Eventos de Dominio en mi código?
    Existen diversas formas de implementar eventos de dominio, pero una común es utilizar un patrón de publicación/suscripción (publish/subscribe). Se puede crear una interfaz para un publicador de eventos y un mecanismo para que los componentes se suscriban a eventos específicos. También se pueden utilizar bibliotecas o frameworks que faciliten la gestión de eventos de dominio.
  4. ¿DDD es adecuado para proyectos pequeños?
    DDD puede ser beneficioso incluso en proyectos pequeños si se espera que crezcan en complejidad. Sin embargo, para proyectos muy simples, la sobrecarga de DDD podría no ser necesaria. Es importante evaluar la complejidad del dominio y las necesidades del proyecto antes de decidir implementar DDD.
  5. ¿Necesito usar un framework específico para implementar DDD?
    No, DDD es una filosofía y un conjunto de patrones, no un framework. Se puede implementar DDD utilizando diferentes lenguajes y frameworks de programación. Sin embargo, existen herramientas y frameworks que pueden facilitar la implementación de ciertos aspectos de DDD.

Subir