CQRS y Event Sourcing en C++: Arquitectura para sistemas complejos

Entrenador de Python en Línea para Principiantes

Aprende Python fácilmente sin sobrecargarte de teoría. Resuelve tareas prácticas con verificación automática, recibe pistas y escribe código directamente en el navegador, sin instalar nada.

Start Course

Cuando el CRUD convencional deja de funcionar: conociendo CQRS y Event Sourcing en C++



¿Alguna vez se ha enfrentado a una situación en la que su programa en C++, que funciona perfectamente con datos de prueba, comienza a "ralentizarse" en producción? ¿O cuando los analistas de negocio le piden ver el historial de cambios, pero usted solo tiene el último estado? ¿Le suena familiar? Entonces, bienvenido al mundo de CQRS (Command Query Responsibility Segregation) y Event Sourcing.



Estos dos patrones no son solo palabras de moda del mundo de los microservicios. Son herramientas potentes que permiten construir sistemas escalables, auditables y flexibles. Y sí, se adaptan perfectamente a C++, un lenguaje donde el rendimiento y el control de la memoria son cruciales.



En este artículo, no leeremos conferencias aburridas. Analizaremos cómo implementar CQRS y Event Sourcing en C++ puro, sin la magia de los frameworks, con ejemplos reales y plantillas listas para usar.



CQRS: Separamos la lectura y la escritura



En la arquitectura clásica CRUD (Create, Read, Update, Delete), usamos el mismo modelo tanto para leer como para escribir. Esto es conveniente hasta que el sistema comienza a crecer. Los problemas surgen cuando:



  • El objeto en memoria es demasiado complejo para serializarse rápidamente para la lectura.
  • La lógica de negocio de escritura requiere una validación que ralentiza la lectura.
  • Diferentes partes del sistema quieren ver los mismos datos de diferentes maneras.


CQRS propone una solución simple pero genial: dividir el modelo en dos partes: Command (comando) para cambiar el estado y Query (consulta) para la lectura. Pueden usar diferentes almacenes, diferentes estructuras de datos e incluso implementarse en diferentes máquinas.



Implementación básica de CQRS en C++



Empecemos con algo simple. Imagine que estamos escribiendo un sistema de gestión de pedidos. En lugar de almacenar todo en una sola clase Order, separaremos las responsabilidades.



Primero, definamos las interfaces para comandos y consultas:



#include <memory>#include <vector>#include <string>

// Clase base para todos los comandosclass Command {public: virtual ~Command() = default; virtual void execute() = 0;};

// Clase base para todas las consultastemplate <typename TResult>class Query {public: virtual ~Query() = default; virtual TResult execute() = 0;};


Ahora, creemos un comando concreto para agregar un artículo al pedido:



class AddItemCommand : public Command {private:    std::string orderId_;    std::string productId_;    int quantity_;    // Referencia al repositorio (o bus de comandos)    OrderRepository& repository_;

public: AddItemCommand(const std::string& orderId, const std::string& productId, int quantity, OrderRepository& repo) : orderId_(orderId), productId_(productId), quantity_(quantity), repository_(repo) {}

void execute() override { // Lógica de negocio: verificar si el artículo está en stock if (quantity_ <= 0) { throw std::invalid_argument("Quantity must be positive"); } // Llamar al servicio de dominio o agregado auto& order = repository_.getById(orderId_); order.addItem(productId_, quantity_); repository_.save(order); }};


Y así es como se ve una consulta para obtener un resumen del pedido:



class OrderSummaryQuery : public Query<OrderSummary> {private:    std::string orderId_;    ReadModelDatabase& db_;

public: OrderSummaryQuery(const std::string& orderId, ReadModelDatabase& db) : orderId_(orderId), db_(db) {}

OrderSummary execute() override { // Leer desde la base de datos optimizada para lectura return db_.getOrderSummary(ord

Blogs

Book Recommendations