Domain Events
En este artículo, exploraremos el concepto de Eventos de Dominio en el contexto del Domain-Driven Design (DDD). Aprenderás sobre su propósito, cómo se estructuran y cómo se utilizan en la librería CodeDesignPlus.Net.Core
. También proporcionaremos ejemplos prácticos de implementación para ayudarte a entender su funcionalidad.
¿Qué es un Evento de Dominio?
Un Evento de Dominio es una notificación que indica que algo significativo ha ocurrido en el dominio de una aplicación. Estos eventos son utilizados para representar cambios importantes en el estado del modelo de dominio, y sirven como una forma de comunicar esas modificaciones a otros componentes del sistema.
Importancia de los Eventos de Dominio
-
Desacoplamiento: Los eventos de dominio ayudan a desacoplar diferentes partes de la aplicación. Al emitir eventos, las clases que los generan no necesitan saber quién los escucha, lo que permite una mayor flexibilidad y escalabilidad.
-
Auditoría y Trazabilidad: Los eventos de dominio facilitan el seguimiento de cambios en el sistema, permitiendo la auditoría de acciones importantes y el rastreo de su origen.
-
Reactividad: Los eventos permiten que otros componentes del sistema reaccionen ante cambios, lo que es esencial en sistemas que requieren un alto grado de interactividad.
-
Integración: En arquitecturas distribuidas, los eventos de dominio pueden ser utilizados para integrar diferentes sistemas, permitiendo que se comuniquen a través de eventos en lugar de llamadas directas.
Abstracciones
La librería CodeDesignPlus.Net.Core
proporciona las siguientes abstracciones para trabajar con eventos de dominio:
IDomainEvent
Esta interfaz define las propiedades básicas que debe tener un evento de dominio:
namespace CodeDesignPlus.Net.Core.Abstractions;
/// <summary>/// Represents a domain event./// </summary>public interface IDomainEvent{ /// <summary> /// Gets the unique identifier of the event. /// </summary> Guid EventId { get; }
/// <summary> /// Gets the date and time when the event occurred. /// </summary> Instant OccurredAt { get; }
/// <summary> /// Gets the unique identifier of the aggregate associated with the event. /// </summary> Guid AggregateId { get; }
/// <summary> /// Gets the metadata associated with the event. /// </summary> Dictionary<string, object> Metadata { get; }}
DomainEvent
La clase base para todos los eventos de dominio, que implementa la interfaz IDomainEvent
y proporciona funcionalidades adicionales:
namespace CodeDesignPlus.Net.Core.Abstractions;
/// <summary>/// Represents a base class for domain events./// </summary>/// <remarks>/// Domain events are used to represent significant changes or occurrences in a domain model./// </remarks>/// <seealso cref="IDomainEvent"/>/// <remarks>/// Initializes a new instance of the <see cref="DomainEvent"/> class./// </remarks>/// <param name="aggregateId">The identifier of the aggregate associated with the event.</param>/// <param name="eventId">The identifier of the event (optional). If not provided, a new GUID will be generated.</param>/// <param name="occurredAt">The date and time when the event occurred (optional). If not provided, the current UTC date and time will be used.</param>/// <param name="metadata">Additional metadata associated with the event (optional).</param>public abstract class DomainEvent( Guid aggregateId, Guid? eventId = null, Instant? occurredAt = null, Dictionary<string, object>? metadata = null) : IDomainEvent{
/// <summary> /// Gets the identifier of the aggregate associated with the event. /// </summary> public Guid AggregateId { get; private set; } = aggregateId;
/// <summary> /// Gets or sets the identifier of the event. /// </summary> /// <remarks> /// This property is internal and can only be set within t /// <summary> /// Gets or sets the identifier of the event. /// </summary> /// <remarks> /// This property is internal and can only be set within the assembly. /// If not provided during initialization, a new GUID will be generated. /// </remarks>he assembly. /// If not provided during initialization, a new GUID will be generated. /// </remarks> public Guid EventId { get; internal set; } = eventId ?? Guid.NewGuid();
/// <summary> /// Gets or sets the date and time when the event occurred. /// </summary> /// <remarks> /// This property is internal and can only be set within the assembly. /// If not provided during initialization, the current UTC date and time will be used. /// </remarks> public Instant OccurredAt { get; internal set; } = occurredAt ?? SystemClock.Instance.GetCurrentInstant();
/// <summary> /// Gets or sets the additional metadata associated with the event. /// </summary> public Dictionary<string, object> Metadata { get; set; } = metadata ?? [];}
Ejemplo Práctico
A continuación, veremos ejemplos concretos de eventos de dominio específicos para un agregado de pedidos (OrderAggregate
).
OrderCreatedDomainEvent
Este evento se emite cuando se crea un nuevo pedido:
using CodeDesignPlus.Net.Core.Abstractions;using CodeDesignPlus.Net.Core.Abstractions.Attributes;using CodeDesignPlus.Net.Core.Sample.Resources.Aggregate;
namespace CodeDesignPlus.Net.Core.Sample.Resources.DomainEvents;
[EventKey<OrderAggregate>(1, "created")]public class OrderCreatedDomainEvent( Guid aggregateId, string name, string description, decimal price, Instant createdAt, Guid createBy, Instant? updatedAt, Guid? eventId = null, Instant? occurredAt = null, Dictionary<string, object>? metadata = null ) : DomainEvent(aggregateId, eventId, occurredAt, metadata){ public string Name { get; private set; } = name; public string Description { get; private set; } = description; public decimal Price { get; private set; } = price; public Instant CreatedAt { get; private set; } = createdAt; public Guid CreateBy { get; private set; } = createBy; public Instant? UpdatedAt { get; private set; } = updatedAt;}
OrderUpdatedDomainEvent
Este evento se emite cuando se actualiza un pedido:
using CodeDesignPlus.Net.Core.Abstractions;using CodeDesignPlus.Net.Core.Abstractions.Attributes;using CodeDesignPlus.Net.Core.Sample.Resources.Aggregate;
namespace CodeDesignPlus.Net.Core.Sample.Resources.DomainEvents;
[EventKey<OrderAggregate>(1, "updated")]public class OrderUpdatedDomainEvent( Guid id, string name, string description, decimal price, Instant? updatedAt, Guid UpdatedBy, Guid? eventId = null, Instant? occurredAt = null) : DomainEvent(id, eventId, occurredAt){ private readonly Guid updatedBy = UpdatedBy;
public string Name { get; private set; } = name; public string Description { get; private set; } = description; public decimal Price { get; private set; } = price; public Instant? UpdatedAt { get; private set; } = updatedAt;}
OrderDeletedDomainEvent
Este evento se emite cuando se elimina un pedido:
using CodeDesignPlus.Net.Core.Abstractions;using CodeDesignPlus.Net.Core.Abstractions.Attributes;using CodeDesignPlus.Net.Core.Sample.Resources.Aggregate;
namespace CodeDesignPlus.Net.Core.Sample.Resources.DomainEvents;
[EventKey<OrderAggregate>(1, "deleted")]public class OrderDeletedDomainEvent( Guid id, long? deletedAt, Guid? eventId = null, Instant? occurredAt = null) : DomainEvent(id, eventId, occurredAt){ public long? DeletedAt { get; private set; } = deletedAt;}
Conclusiones
Los eventos de dominio son un componente esencial del Domain-Driven Design, ya que permiten la comunicación de cambios significativos en el modelo de dominio de una manera desacoplada y eficiente. En este artículo, hemos explorado las interfaces y clases que facilitan el uso de eventos de dominio en la librería CodeDesignPlus.Net.Core
, junto con ejemplos concretos que ilustran su implementación.
Al comprender y aplicar los eventos de dominio, podrás construir aplicaciones más robustas y flexibles que respondan adecuadamente a los cambios en el sistema. Si deseas aprender más sobre la gestión de eventos de dominio o su integración con otros patrones de diseño, no dudes en contactarnos. ¡Estamos aquí para ayudarte!