CQRS.
Separa el modelo que cambia el estado (comandos) del modelo que lee el estado (consultas), de modo que cada lado pueda modelarse, escalarse y optimizarse de forma independiente.
##Intent
Usa un modelo para actualizar la información y un modelo distinto para leerla. Los comandos expresan la intención de cambiar el estado; las consultas devuelven datos con la forma adecuada para mostrarlos. Ambos ya no tienen que llegar a un compromiso en torno a una única representación compartida.
##Problem
En un diseño tradicional, un mismo modelo sirve tanto para las escrituras como para las lecturas. Las escrituras necesitan validación e invariantes ricos; las lecturas necesitan formas desnormalizadas y listas para mostrar, a menudo muchas distintas para diferentes pantallas e informes.
Forzar ambos a través de los mismos objetos y tablas conduce a compromisos incómodos: sobreobtención de datos (over-fetching), mapeos ORM complejos, contención de bloqueos y un modelo que no es bueno en ninguna de las dos tareas.
##Solution
CQRS divide el sistema en dos. El lado de escritura gestiona los comandos mediante manejadores que cargan un agregado, imponen invariantes y persisten el cambio (emitiendo eventos opcionalmente). El lado de lectura sirve consultas desde uno o varios modelos de lectura con una forma diseñada específicamente para las vistas que los consumen.
Ambos lados pueden compartir una base de datos o usar almacenes separados. Cuando están separados, los modelos de lectura se mantienen actualizados proyectando los eventos del lado de escritura, aceptando la consistencia eventual a cambio de un escalado independiente y consultas más simples.
##Structure
- Comando — una solicitud para cambiar el estado, nombrada según su intención (
PlaceOrder). - Manejador de comandos — valida y aplica el comando al modelo de escritura.
- Modelo de escritura — agregados que imponen invariantes; pueden emitir eventos.
- Modelo de lectura / proyección — vistas desnormalizadas construidas para las consultas, actualizadas a partir de eventos.
- Consulta & manejador de consultas — solicitudes de solo lectura servidas desde el modelo de lectura.
##Applicability
- Úsalo donde las lecturas y las escrituras tengan formas o cargas muy diferentes: muchas vistas de lectura, generación intensiva de informes o una proporción de lecturas frente a escrituras elevada.
- Úsalo para interfaces basadas en tareas y dominios colaborativos, donde se combina de forma natural con el diseño guiado por el dominio (DDD) y el event sourcing.
- Evítalo para un CRUD sencillo; un único modelo es más simple y la separación añade coste sin recompensa.
##How to Implement
- Modela los comandos como intenciones explícitas en lugar de actualizaciones genéricas.
- Encamina cada comando a un manejador que cargue el agregado pertinente e imponga sus invariantes.
- Persiste el cambio y, si usas eventos, publica lo que ocurrió.
- Construye modelos de lectura adaptados a tus vistas; si están separados, actualízalos proyectando eventos.
- Sirve las consultas directamente desde los modelos de lectura: nada de lógica de dominio en el lado de lectura.
##Pros & Cons
- Los lados de lectura y escritura pueden modelarse, optimizarse y escalarse de forma independiente.
- Cada modelo se mantiene pequeño y centrado en una sola tarea.
- Encaja con las interfaces basadas en tareas y se compone bien con el event sourcing y el DDD.
- Los modelos de lectura pueden adaptarse por vista, eliminando joins incómodos.
- Más piezas móviles y más código que un único modelo CRUD.
- Los almacenes de lectura separados introducen consistencia eventual, que la experiencia de usuario debe gestionar.
- Es fácil caer en la sobreingeniería; rara vez se justifica en dominios sencillos.
- Sobrecarga operativa de las proyecciones y de la fontanería de mensajes.