Marcio Cunha

Modelado de Dominio con Event Sourcing y CQRS en Bases de Datos Relacionales

Aprende a construir sistemas resilientes combinando Event Sourcing y CQRS en bases de datos relacionales tradicionales, garantizando alta disponibilidad y auditoría inmutable.

Marcio Cunha5 min
También disponible en:PortuguêsEnglish
Resumen
  • El registro de eventos inmutables reemplaza las actualizaciones destructivas de estado y garantiza auditoría nativa en sistemas corporativos críticos.
  • La separación de modelos de escritura y lectura elimina cuellos de botella de concurrencia en bases de datos relacionales tradicionales.
  • El uso cuidadoso de índices parciales y tablas optimizadas para anexión resuelve problemas de rendimiento con volúmenes masivos de datos.
  • La consistencia eventual entre escrituras y lecturas exige estrategias claras para mitigar el retraso en la interfaz de usuario.
  • El modelado basado en flujo temporal simplifica la reconstrucción del estado de negocio sin pérdida de contexto histórico.

Fundamentos del Modelado Basado en Eventos

En la ingeniería de software tradicional, solemos guardar únicamente el estado actual de un registro en la base de datos. Cuando un cliente cambia su dirección, sobrescribimos el dato antiguo, perdiendo el rastro de dónde vivía antes. En la práctica, esto significa que perdemos la historia de cómo llegamos hasta aquí. El Event Sourcing, o modelado basado en eventos, propone un cambio radical en esta mentalidad: en lugar de guardar el estado final, guardamos cada acontecimiento importante como un hecho inmutable, como si fuera una bitácora inalterable.

Para un lector sin familiaridad técnica, imagine una cuenta bancaria. En lugar de actualizar el saldo de mil a quinientos pesos tras un retiro, registramos el evento exacto de que un retiro de quinientos pesos ocurrió a las diez de la mañana. El saldo actual no se guarda directamente, sino que se calcula siempre que es necesario sumando y restando los eventos del pasado. Este enfoque garantiza una auditoría perfecta, ya que ningún dato se borra o sobrescribe, permitiendo viajar en el tiempo y entender exactamente qué ocurrió en cualquier momento del ciclo de vida del sistema.

La Arquitectura de Separar Escrituras y Lecturas

Cuando adoptamos el almacenamiento basado en eventos, consultar datos de forma ágil se convierte en un desafío matemático. Leer miles de eventos cada vez que un usuario abre su perfil exigiría un esfuerzo computacional innecesario. Aquí es donde entra CQRS, una sigla en inglés para la separación de responsabilidades entre consultas y comandos. En la práctica, creamos dos caminos separados: un carril exclusivo e hiper-optimizado para recibir nuevas acciones de escritura, y otro carril diseñado a medida para responder rápidamente a las consultas de los usuarios.

En bases de datos relacionales de alta disponibilidad, esta separación evita que consultas complejas bloqueen las operaciones críticas de guardado. Mientras que la tabla de eventos almacena hechos crudos de forma secuencial y extremadamente rápida, tablas separadas o vistas materializadas se actualizan en segundo plano para servir las pantallas del sistema. Esta división de tareas permite escalar cada parte de la aplicación según su necesidad específica, garantizando que el sistema siga respondiendo con agilidad incluso bajo tráfico concurrente pesado.

Implementación Práctica en Bases de Datos Relacionales

Muchos desarrolladores creen que el Event Sourcing exige el uso de bases de datos exóticas o orientadas a documentos. En la práctica, bases de datos relacionales robustas manejan esta carga sin problemas cuando se estructuran con tablas simples de append-only, es decir, tablas donde los registros nunca sufren modificaciones o borrados, solo inserciones. Cada evento se almacena típicamente como un documento JSON que contiene el identificador del agregado, el tipo de evento, la versión y los datos específicos del cambio ocurrido en el sistema.

Para garantizar la integridad transaccional sin sacrificar rendimiento, utilizamos índices en columnas estratégicas y claves de idempotencia que evitan la duplicación de eventos. A continuación se muestra un ejemplo práctico de una estructura relacional en SQL para persistir y consultar eventos de forma segura y eficiente:

CREATE TABLE event_store (
    event_id UUID PRIMARY KEY,
    aggregate_id UUID NOT NULL,
    aggregate_type VARCHAR(255) NOT NULL,
    event_type VARCHAR(255) NOT NULL,
    version INT NOT NULL,
    payload JSONB NOT NULL,
    created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
    CONSTRAINT unique_aggregate_version UNIQUE (aggregate_id, version)
);

CREATE INDEX idx_event_store_aggregate ON event_store (aggregate_id, version);

Con esta estructura simple, garantizamos que ningún evento sea grabado con una versión duplicada para el mismo agregado, manteniendo el orden cronológico estricto necesario para la reconstrucción correcta del dominio de negocio. La base de datos relacional asume el rol de guardiana de la consistencia sin abandonar la flexibilidad exigida por las arquitecturas modernas.

Gestión de Consistencia y Alta Disponibilidad

En los sistemas distribuidos, la ilusión de consistencia inmediata en todas partes cede paso a la realidad de la consistencia eventual. Cuando un evento es grabado en la tabla principal, las proyecciones de lectura tardan milisegundos o fracciones de segundo en reflejar el cambio en las pantallas de los usuarios. En la práctica, esto significa que un cliente puede realizar una compra y, por un intervalo muy breve, no ver el pedido reflejado en su historial reciente si consulta una réplica de lectura desactualizada.

Para mitigar esta sensación de retraso en la interfaz, aplicamos patrones donde el cliente recibe una confirmación optimista inmediata mientras la aplicación procesa el estado en segundo plano. En bases de datos relacionales de alta disponibilidad configuradas con replicación multi-master o réplicas de lectura, el secreto radica en dirigir lecturas críticas justo después de una escritura hacia el mismo nodo o conexión que originó el comando, asegurando una experiencia de usuario fluida y sin sorpresas desagradables.

Consideraciones Finales sobre Escalabilidad y Mantenibilidad

Adoptar Event Sourcing y CQRS en bases de datos relacionales de alta disponibilidad no es una decisión que deba tomarse a la ligera. La complejidad de desarrollo aumenta porque la lógica de negocio debe traducirse en eventos claros y versionables a lo largo del tiempo. Sin embargo, las ganancias en términos de trazabilidad, resiliencia operativa y claridad en el modelado superan ampliamente el esfuerzo inicial de implementación en entornos corporativos que exigen un historial impecable.

El secreto del éxito radica en empezar pequeño, identificando dominios de negocio que realmente se beneficien de una auditoría rigurosa y aislamiento de carga. Al tratar la base de datos relacional no solo como un repositorio estático de planillas, sino como un motor confiable de flujo temporal de eventos, construimos aplicaciones capaces de absorber un crecimiento explosivo sin perder la integridad de los datos.