CQRS es un patrón que separa las operaciones de escritura de las de lectura dentro de tu dominio, y entenderlo te ayuda a diseñar aplicaciones más mantenibles y escalables. Si trabajas con arquitecturas limpias o quieres acercarte a una programación orientada a eventos, este concepto te da herramientas para organizar mejor tu código.
El nombre viene del inglés Command Query Responsibility Segregation, que en español traducimos como segregación de responsabilidades de comandos y consultas. Suena enredado, pero en el fondo son solo dos ideas: comandos y consultas [0:11].
Qué diferencia hay entre un comando y una consulta en CQRS
Todo en CQRS gira alrededor de separar dos tipos de operaciones. Los comandos cambian el estado de algo, mientras que las consultas solo obtienen información.
Los comandos son operaciones de escritura: guardar un usuario, modificar una propiedad de un objeto o actualizar un atributo en una tabla de la base de datos. Todo eso cambia el estado del sistema [0:40].
Las consultas son operaciones de lectura que obtienen resultados sin modificar nada. Por ejemplo, pedir todos los usuarios registrados en los últimos 30 días o la fecha de la última venta en un sistema de e-commerce [1:20].
¿Qué es un comando en CQRS? Es una operación de escritura que cambia el estado del sistema, como crear un usuario o actualizar un dato en la base de datos.
Por qué separar el modelo de lectura del de escritura
Normalmente las aplicaciones se diseñan con todo junto: una interfaz, una aplicación y una fuente de datos, donde el modelo de lectura y escritura están unidos [2:04].
En CQRS esto cambia. Tienes dos modelos separados: uno para las consultas y otro para los comandos [2:20]. Las razones para hacer esta separación son varias:
- Una parte puede ser mucho más intensiva que la otra, por ejemplo cuando las operaciones de escritura son más fuertes que las de lectura o al revés.
- Facilita el mantenimiento del código al tener responsabilidades claras.
- Abre la puerta a escalar cada lado de forma independiente.
Esa idea de dividir responsabilidades es el corazón del patrón y lo que lo hace tan útil cuando empiezas a tener problemas de escalabilidad.
Cómo se ve CQRS en código con arquitectura limpia
El ejemplo usa un bloque de código en C# generado con una plantilla especializada en arquitectura limpia con CQRS, aplicado a una aplicación de to-do list [4:10]. Las capas aquí son mucho más explícitas:
- Capa de dominio con entidades, excepciones, enumeraciones y objetos de valor.
- Capa de aplicación donde ya se separa la lógica entre comandos y consultas.
- Capa de infraestructura con gestión de archivos, seguridad o identidad, persistencia y servicios adicionales.
- Un proyecto específico para la parte web de la interfaz.
Y aquí viene lo interesante: el Entity Framework, que es un ORM de Microsoft, se usa para manejar la persistencia dentro del comando [6:30].
Cómo funciona un comando para crear una tarea
El comando para crear un to-do list vive en la capa de aplicación e implementa una interfaz llamada IRequestHandler [6:14]. Curiosamente tiene el mismo nombre que vimos en el ejemplo de casos de uso, lo que demuestra que las implementaciones cambian los nombres pero el trasfondo es el mismo.
El método recibe un comando, que es un objeto con los datos de la solicitud, crea la entidad, le asigna un título, interactúa con la persistencia mediante la dependencia inyectada y retorna un resultado [6:50].
Cómo funciona una consulta para obtener tareas
La consulta sigue un patrón muy similar. El get todos query implementa la misma interfaz y define un método handle que recibe una solicitud con los parámetros necesarios [8:00].
Aquí aparece una consecuencia clave del patrón: si estás haciendo una operación de lectura, no deberías estar haciendo una de escritura en ese mismo lugar [8:40]. Esa es la disciplina que impone CQRS.
Cómo se consumen los comandos y consultas con un mediador
Aquí es donde la implementación realmente varía. Los controladores viven en la capa de interfaz web o en un API REST, y en lugar de llamar directamente a la consulta, usan un mediador [9:30].
El ejemplo usa un framework llamado Mediator. El punto importante es que lanzas un evento: como capa externa no sabes exactamente dónde está el comando o la consulta, solo lanzas un query diciendo que necesitas los todos y el mediador se encarga del resto [10:20].
¿Qué ventaja da usar un mediador en CQRS? Desacopla la capa externa de la lógica interna, porque solo lanzas eventos en lugar de invocar métodos directamente.
Para las operaciones de escritura es igual: mandas el comando como una solicitud para que luego sea ejecutada. El resultado es un código mucho más desacoplado, aunque a cambio se vuelve más complejo de hacerle debugging, porque pierdes la trazabilidad directa de invocar un método y obtener un resultado [11:00].
En qué niveles puedes aplicar CQRS
La separación entre comandos y consultas no se limita a la arquitectura limpia. Puedes llevarla a varios niveles según tus necesidades.
- A nivel de métodos: un método no debería leer y escribir a la vez. Un caso común que rompe esta regla es un método que busca un producto y, si no lo encuentra, lo crea. En CQRS eso no tiene sentido [12:20].
- A nivel de clases: clases de consulta separadas de clases de escritura.
- A nivel de servicios o backends: incluso backends completos dedicados solo a leer u otros solo a escribir, útil cuando aparecen problemas de escalabilidad.
- A nivel de bases de datos: con mucha concurrencia puedes tener bases de datos solo de lectura y otras solo de escritura, con mecanismos que sincronicen la información escrita hacia las de lectura [13:00].
¿Dónde se aplica CQRS? En métodos, clases, servicios y hasta bases de datos, sobre todo cuando aparecen problemas de escalabilidad o concurrencia alta.
Estas implementaciones más complejas suelen vivir a nivel de infraestructura, pero muestran que CQRS tiene implicaciones muy poderosas más allá de las arquitecturas limpias y te acerca a una programación orientada a eventos.
¿Ya habías aplicado CQRS en alguno de estos niveles? Cuéntanos en los comentarios cómo lo implementaste.