Nivel 3 · 30 min
CQRS con Eventos
CQRS (Command Query Responsibility Segregation) separa el modelo de escritura (comandos que mutan estado) del modelo de lectura (queries que devuelven datos). Combinado con una arquitectura event-driven, los domain events del lado de escritura impulsan proyecciones en el lado de lectura. Esto habilita escala masiva y flexibilidad a costa de consistencia eventual.
Split Comando-Query
En arquitecturas tradicionales, el mismo modelo sirve lecturas y escrituras — optimizar uno limita al otro. CQRS los separa: los comandos (CreateOrder, UpdatePaymentStatus) mutan estado via el write model. Los queries (GetOrderSummary, ListCustomerOrders) leen del read model. Cada uno puede usar almacenamiento diferente — el write model puede usar una DB relacional normalizada para integridad; el read model usa tablas denormalizadas, Elasticsearch o Redis para queries rápidas. Los command handlers validan, aplican reglas de negocio y emiten domain events. Los query handlers simplemente leen del read store.
Proyecciones del Read Model
Las proyecciones son event handlers que consumen domain events y actualizan el read model. Cuando se dispara OrderPlaced, la OrderSummaryProjection crea una nueva fila en la tabla order_summaries. Cuando se dispara PaymentReceived, actualiza el payment_status. Las proyecciones se reconstruyen desde cero reproduciendo todos los eventos — habilitando evolución de esquema sin migraciones. Cada proyección está optimizada para un patrón de query específico — OrderByCustomerProjection construye un índice cliente → pedidos; OrderAnalyticsProjection agrega en estadísticas diarias. Múltiples proyecciones de los mismos eventos sin acoplamiento.
Consistencia Eventual e Integración
El write model y los read models tienen consistencia eventual — hay un delay entre que un comando es procesado y el read model lo refleja. En la práctica suele ser millisegundos pero puede ser mayor bajo carga. Manejalo en la UI: actualizaciones optimistas (asumir éxito y mostrar el nuevo estado inmediatamente), consistencia read-your-writes (consultar el write model directamente para el ítem que el usuario acaba de modificar), o mensajería UX (''Tu pedido está siendo procesado...''). Integración con mensajería: domain events publicados a Kafka; projection workers consumen y actualizan read stores. Múltiples servicios independientes pueden construir sus propias proyecciones del mismo topic Kafka.
Code example
// Command handler: write model
@CommandHandler
void handle(CreateOrderCommand cmd) {
Order order = Order.create(cmd); // validar + emitir eventos
eventStore.save(order.getUncommittedEvents());
eventBus.publish(order.getUncommittedEvents());
}
// Projection handler: actualizar read model
@EventHandler
void on(OrderPlaced event) {
orderSummaryRepo.save(OrderSummaryView.from(event));
}