ConstructiCat Logo
CodeBust.
Browse section ▾

CQRS.

Also known as — Command Query Responsibility Segregation

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

  1. Modela los comandos como intenciones explícitas en lugar de actualizaciones genéricas.
  2. Encamina cada comando a un manejador que cargue el agregado pertinente e imponga sus invariantes.
  3. Persiste el cambio y, si usas eventos, publica lo que ocurrió.
  4. Construye modelos de lectura adaptados a tus vistas; si están separados, actualízalos proyectando eventos.
  5. Sirve las consultas directamente desde los modelos de lectura: nada de lógica de dominio en el lado de lectura.

##Pros & Cons

Pros
  • 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.
Cons
  • 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.