Nivel 3 · 30 min
Event Sourcing
Event Sourcing almacena el estado de un sistema como una secuencia ordenada de domain events inmutables en lugar del estado actual. El estado actual se deriva reproduciendo los eventos. Esto desbloquea queries temporales, historial de auditoría completo y proyecciones desacopladas — a costa de complejidad y consistencia eventual.
Event Store y Append-Only
El event store es un log append-only de domain events. Los eventos son hechos inmutables en tiempo pasado: OrderPlaced, PaymentReceived, OrderShipped. Nunca actualizás ni eliminás eventos — solo agregás nuevos. El estado actual de un agregado se deriva reproduciendo sus eventos en orden. Esto significa que tenés una historia completa por diseño. Implementaciones de event store: EventStoreDB (propósito específico), PostgreSQL (tabla events con stream_id + version), Kafka (topics compactados), o AWS DynamoDB Streams.
Event Replay y Proyecciones
El event replay reconstruye el estado de un agregado aplicando eventos secuencialmente. Al iniciar, cargar todos los eventos para un aggregate ID y aplicarlos a un objeto de estado vacío. Las proyecciones (read models) se construyen consumiendo el stream de eventos y construyendo vistas denormalizadas optimizadas para queries. Múltiples proyecciones pueden construirse del mismo stream de eventos — una proyección OrderSummary, una OrderByCustomer, una Analytics — todas de los mismos eventos OrderPlaced/OrderShipped. Las proyecciones pueden reconstruirse desde cero reproduciendo todos los eventos — poderoso para migraciones de esquema.
Snapshots y Versionado de Eventos
Los snapshots capturan el estado del agregado en un punto en el tiempo, almacenado junto a los eventos. Al cargar: obtener último snapshot + reproducir solo los eventos desde el snapshot. Esencial para agregados con miles de eventos. El versionado de eventos es un desafío crítico: ¿qué pasa cuando el esquema de un evento cambia? Upcasting: transformar versiones antiguas del evento a la versión actual al leer. Estrategias de versionado: schema registry, nombres de evento versionados (OrderPlacedV2), o upcasters en runtime.
Code example
// Agregado event-sourced
class OrderAggregate {
private String id;
private OrderStatus status;
private List<DomainEvent> uncommittedEvents = new ArrayList<'>();
// Reconstruir desde eventos
static OrderAggregate rehydrate(List<DomainEvent> events) {
OrderAggregate order = new OrderAggregate();
events.forEach(order::apply);
return order;
}
void placeOrder(PlaceOrderCommand cmd) {
apply(new OrderPlaced(cmd.getOrderId(), cmd.getItems()));
}
private void apply(OrderPlaced event) {
this.id = event.getOrderId();
this.status = OrderStatus.PLACED;
uncommittedEvents.add(event);
}
}