Read in English · Lire en français · Auf Deutsch lesen
Sección 7.5 de 7.8 · Avanzado · 26 min de lectura
CQRS y event sourcing
Videolección
5 min · narrado en inglés, con subtítulosSolo escuchar (audio)
Leer la transcripción
Esta lección trata dos patrones que suelen usarse juntos: separar el modelo que modifica los datos de los modelos que los leen, y almacenar los datos como un historial de eventos. Ambos son potentes, y ambos añaden una complejidad real.
Piensa en el libro mayor de un banco. Cada depósito y cada retiro se anota, una línea tras otra. Nunca se borra nada. Los errores se corrigen añadiendo una línea de corrección. Tu saldo es simplemente la suma de todas las líneas. Y tu extracto mensual es un resumen ordenado que se prepara a partir del libro mayor. El event sourcing almacena los datos como lo hace el libro mayor. CQRS mantiene el libro mayor separado de los extractos.
En 1988, Bertrand Meyer propuso que un método debía cambiar el estado o devolver una respuesta, pero no ambas cosas. Hacia 2010, Greg Young aplicó esa división a modelos completos y la llamó Command Query Responsibility Segregation, o CQRS. Escribir y leer son trabajos distintos. Escribir necesita reglas estrictas, con cada hecho almacenado una sola vez. Leer necesita velocidad, y formas que coincidan con las pantallas. Un único modelo que intenta hacer ambas cosas tiende a hacer mal las dos.
Así encajan las piezas, con el event sourcing incluido. En el lado de escritura, un comando, como retirar cincuenta libras, llega a un manejador de comandos. Este carga la cuenta, aplica las reglas de negocio y anexa nuevos eventos a un almacén de eventos de solo anexado. Un comando es una solicitud, así que puede rechazarse. En el lado de lectura, un proyector escucha esos eventos y mantiene actualizados los modelos de lectura: aquí, una vista de saldo y una vista de extracto. Las consultas se responden desde esas vistas, sin joins, sin lógica de negocio y sin bloqueos en el lado de escritura. Y como los modelos de lectura son derivados, siempre pueden desecharse y reconstruirse.
La mayoría de los sistemas almacenan el estado actual. Cuando retiras dinero, el saldo cambia y el valor antiguo desaparece. El event sourcing le da la vuelta a esto: cada cambio se almacena como un evento inmutable en un log de solo anexado. Los eventos se nombran en pasado, como dinero retirado, porque registran hechos que ya se han aceptado. Un evento no puede rechazarse, solo compensarse con otro posterior. El estado actual es lo que se obtiene al reproducir los eventos en orden. Los eventos son la fuente de verdad; el saldo es un cálculo. Esa reproducción siempre debe dar la misma respuesta, así que nunca puede llamar a un reloj ni a otro servicio. Cualquier valor que venga del exterior, como un tipo de cambio, se registra dentro del evento.
Sigamos una cuenta. El primer evento la abre, sin descubierto. El segundo deposita quinientas libras. Siguen tres eventos más: un retiro de ciento veinte libras, un depósito de setenta y cinco libras con cincuenta y un retiro de trescientas. El saldo es ahora de ciento cincuenta y cinco libras con cincuenta. Ahora el cliente intenta retirar doscientas libras. Eso dejaría el saldo en menos cuarenta y cuatro libras con cincuenta, por debajo del límite, así que el comando se rechaza y no se anexa nada. Un retiro de veinte libras sí está permitido. El manejador anexa el evento seis, esperando que la versión seis esté libre. Si otro comando se le adelantó, la anexión falla y vuelve a intentarlo. Y si alguien pregunta por qué el saldo es de ciento treinta y cinco libras con cincuenta, los seis eventos son la respuesta completa.
Este diagrama muestra el mismo flujo. Debajo de cada evento está el saldo acumulado después de aplicarlo, paso a paso. Plegar cinco eventos es instantáneo, pero una cuenta con mucho movimiento puede tener cientos de miles. Un snapshot almacena el estado en una versión conocida, así que una reconstrucción solo aplica los eventos posteriores. Un snapshot es una caché, no la fuente de verdad. Y las preguntas sobre el pasado se vuelven fáciles. El saldo en la versión tres es simplemente el plegado de los tres primeros eventos: trescientas ochenta libras. No hace falta ninguna tabla de historial.
Los costos son reales. Cuando las proyecciones se ejecutan en segundo plano, un usuario puede hacer un retiro y luego ver un saldo que todavía no lo incluye. Los eventos se almacenan para siempre, así que su esquema nunca puede cambiarse sin más. Los eventos antiguos se convierten a la forma actual en el momento de leerlos, una técnica llamada upcasting. Borrar datos personales de un log inmutable es difícil. Una técnica habitual es el crypto-shredding: cifrar los campos personales con una clave por cliente y destruir la clave. Si eso cuenta como supresión es una valoración jurídica. Y Martin Fowler advierte que, para la mayoría de los sistemas, CQRS añade una complejidad arriesgada. Usa estos patrones para un área con necesidades de lectura y escritura realmente distintas, como un libro mayor o el ciclo de vida de un pedido, nunca para todo un sistema por defecto.
La sección completa incluye el código, más detalles sobre los snapshots y el versionado de eventos, y una guía de decisión. A continuación, en la Sección siete punto seis, veremos la caché. Nos vemos allí.
Lo que necesitas saber
- La separación comando-consulta (Bertrand Meyer, 1988) dice que un método debe cambiar el estado o devolver una respuesta, pero no ambas cosas; CQRS (Greg Young, hacia 2010) aplica la misma división a modelos completos.
- En CQRS, un modelo de escritura hace cumplir las reglas de negocio sobre los comandos, mientras que las proyecciones mantienen actualizados uno o más modelos de lectura desnormalizados para las consultas; los modelos de lectura son datos derivados que se pueden reconstruir.
- El event sourcing almacena cada cambio como un evento inmutable, con nombre en pasado, en un flujo de solo anexado (append-only) por agregado; el estado actual es un plegado por la izquierda (left fold) determinista de los eventos.
- El event sourcing ofrece una pista de auditoría completa, consultas temporales, modelos de lectura reconstruibles y retroactivos, y la reproducción para depurar; los snapshots (instantáneas) acortan los plegados largos, pero son solo una caché.
- Los costos son reales: complejidad, consistencia eventual de los modelos de lectura, versionado de eventos mediante upcasting o nuevos tipos de evento, y el borrado de datos personales de un log inmutable, normalmente mediante crypto-shredding.
- Martin Fowler advierte que CQRS añade una complejidad arriesgada en la mayoría de los sistemas; aplica cualquiera de los dos patrones a contextos delimitados concretos con necesidades de lectura y escritura realmente distintas, nunca a todo un sistema por defecto.
De la separación comando-consulta a CQRS
La idea empieza siendo pequeña. En Object-Oriented Software Construction (primera edición, 1988), Bertrand Meyer propuso la separación comando-consulta: todo método debe ser o bien un comando que cambia el estado y no devuelve nada, o bien una consulta que devuelve una respuesta y no cambia nada. Hacer una pregunta nunca debería cambiar la respuesta. Martin Fowler señala que la regla tiene excepciones razonables (sacar un elemento de una pila cambia la pila y a la vez devuelve el elemento), pero como norma por defecto hace que sea más fácil razonar sobre el código, porque las consultas pueden llamarse libremente, en cualquier orden, sin efectos secundarios.
Hacia 2010, Greg Young elevó el principio de los métodos a los modelos completos y llamó al resultado Command Query Responsibility Segregation (CQRS). En lugar de un único modelo de objetos, y normalmente un único conjunto de tablas, que sirve tanto para las actualizaciones como para las lecturas, el sistema tiene un modelo de escritura que gestiona los comandos y hace cumplir las reglas de negocio, y uno o más modelos de lectura con la forma de las preguntas que hacen los usuarios. La idea clave es que escribir y leer son trabajos distintos. Escribir necesita reglas estrictas, transacciones pequeñas y una estructura normalizada para que cada hecho se almacene una sola vez. Leer necesita velocidad, formas desnormalizadas que coincidan con las pantallas y los informes, y a menudo mucho más tráfico. Un único modelo que intenta hacer bien ambas cosas tiende a hacer mal las dos en cuanto el dominio se vuelve rico.
Qué cambia realmente CQRS
En el lado de escritura, un comando como WithdrawMoney(account 42, £50) llega a un manejador de comandos. El manejador carga el agregado correspondiente (el conjunto de datos que debe mantenerse consistente dentro de una transacción, un término del diseño guiado por el dominio que se trata en la Sección 5.7), le pide que aplique las reglas de negocio y guarda el resultado. Los comandos son solicitudes y pueden rechazarse: la cuenta puede estar bloqueada o los fondos pueden ser insuficientes. En el lado de lectura, una consulta como muéstrame los últimos 30 movimientos con el saldo acumulado
se responde desde un modelo de lectura construido exactamente para esa pantalla, sin joins, sin lógica de negocio y sin bloqueos sobre las tablas de escritura.
Algo tiene que mantener actualizados los modelos de lectura. Esa tarea corresponde a una proyección: código que escucha los cambios del lado de escritura y actualiza un modelo de lectura. Las proyecciones pueden mantener una tabla de saldos, un índice de búsqueda de movimientos, un documento de extracto mensual y un almacén de características (feature store) para puntuar el fraude, cada uno a partir del mismo flujo de cambios. Por tanto, los modelos de lectura son datos derivados: siempre pueden desecharse y reconstruirse a partir del lado de escritura. Esa propiedad es la que hace seguro añadir un nuevo modelo de lectura el año que viene, o cambiar la forma de uno antiguo.
CQRS admite grados, y el más ligero suele ser todo lo que un sistema necesita. En el grado más ligero, los modelos de escritura y de lectura son clases distintas sobre la misma base de datos, y las lecturas se sirven mediante vistas o código de consulta dedicado. En el grado intermedio, los modelos de lectura viven en tablas separadas que se actualizan en la misma transacción que la escritura. En el grado más pesado, los modelos de lectura viven en almacenes distintos (un motor de búsqueda, una base de datos documental, una caché) y se actualizan de forma asíncrona a partir de eventos, lo que aporta escala y flexibilidad, pero también consistencia eventual. CQRS no requiere event sourcing, un intermediario de mensajes (message broker) ni microservicios; son decisiones independientes que a menudo, aunque no necesariamente, se toman juntas.
CQRS con event sourcing
Event sourcing: el estado como una secuencia de hechos
La mayoría de los sistemas almacenan el estado actual. Cuando Asha retira £120, la fila de accounts pasa de £500 a £380 y el valor antiguo desaparece, a menos que alguien escriba también una fila de auditoría. El event sourcing, descrito por Martin Fowler en 2005, le da la vuelta a esto: el sistema almacena cada cambio como un evento inmutable en un log de solo anexado, y el estado actual es lo que se obtiene al reproducir los eventos en orden. Los eventos son la fuente de verdad; el saldo es un cálculo.
Los eventos se nombran en pasado porque registran hechos que ya han ocurrido y se han aceptado: AccountOpened, MoneyDeposited, MoneyWithdrawn. Un comando (WithdrawMoney) es una solicitud que puede rechazarse; un evento (MoneyWithdrawn) ya no puede rechazarse, solo compensarse con un evento posterior. Cada agregado tiene su propio flujo de eventos, numerado a partir de la versión 1, y el almacén garantiza que los eventos de un flujo se conservan en orden.
Reconstruir el estado es un plegado por la izquierda (left fold): se empieza sin nada, se aplica el primer evento, se aplica el segundo al resultado, y así sucesivamente. La función que aplica los eventos debe ser pura y determinista: no puede llamar a un reloj, a un generador de números aleatorios ni a otro servicio, porque reproducir los mismos eventos siempre debe dar el mismo estado. Cualquier valor que venga del exterior (un tipo de cambio, una marca de tiempo, una puntuación de fraude) se registra dentro del evento en el momento en que se decide por primera vez.
La escritura sigue un ciclo fijo. El manejador de comandos carga el flujo, lo pliega en el estado actual, ejecuta la regla de negocio y anexa los nuevos eventos con la versión que espera escribir. Si entretanto otro comando ha anexado eventos al mismo flujo, la anexión falla y el manejador vuelve a intentarlo con el estado actualizado. Es la concurrencia optimista de la Sección 7.3, aplicada por flujo, y es la razón por la que dos retiros simultáneos no pueden gastar ambos las mismas £100.
Ejemplo práctico
Ejemplo práctico: una cuenta bancaria como eventos
La cuenta corriente de Asha es el flujo account-42. Los importes se almacenan en peniques, como recomienda la Sección 0.2 para el dinero. Se han anexado cinco eventos; luego ella intenta retirar £200.
| v1 AccountOpened (límite de descubierto £0) | Estado: saldo £0.00, versión 1 |
|---|---|
| v2 MoneyDeposited £500.00 | £0.00 + £500.00 = £500.00, versión 2 |
| v3 MoneyWithdrawn £120.00 | £500.00 − £120.00 = £380.00, versión 3 |
| v4 MoneyDeposited £75.50 | £380.00 + £75.50 = £455.50, versión 4 |
| v5 MoneyWithdrawn £300.00 | £455.50 − £300.00 = £155.50, versión 5 |
| Comando: WithdrawMoney £200.00 | Regla: el saldo menos el importe no debe quedar por debajo de menos el límite. £155.50 − £200.00 = −£44.50, por debajo de £0. Comando rechazado; no se anexa ningún evento. |
| Comando: WithdrawMoney £20.00 | £155.50 − £20.00 = £135.50 está permitido. El manejador anexa v6 MoneyWithdrawn £20.00, esperando que la versión 6 esté libre. |
| Consulta temporal: saldo después de v3 | Plegar solo de v1 a v3: £380.00. No hizo falta ninguna tabla de historial. |
| Pregunta de auditoría: ¿por qué el saldo es de £135.50? | Los seis eventos son la respuesta completa, en orden, con quién, cuándo y por qué registrados en cada uno. |
El comando rechazado no dejó rastro en el flujo. Si el banco debe registrar los rechazos (para el análisis de fraude, por ejemplo), anexa un evento WithdrawalRefused aparte, que no cambia el saldo.
Un libro mayor de partida doble es el sistema con event sourcing más antiguo que existe: los contables nunca borran una línea, sino que registran un asiento de corrección. Por eso los dominios bancarios encajan de forma natural con el event sourcing, y por eso suele enseñarse con una cuenta.
# A bank account as a stream of events, folded into current state.
# Amounts are in pence so that no floating-point rounding creeps in.
from functools import reduce
events = [
{"v": 1, "type": "AccountOpened", "overdraft_limit": 0},
{"v": 2, "type": "MoneyDeposited", "amount": 50000},
{"v": 3, "type": "MoneyWithdrawn", "amount": 12000},
{"v": 4, "type": "MoneyDeposited", "amount": 7550},
{"v": 5, "type": "MoneyWithdrawn", "amount": 30000},
]
def apply(state, e): # pure: old state + event -> new state
if e["type"] == "AccountOpened":
return {"balance": 0, "limit": e["overdraft_limit"], "version": e["v"]}
sign = 1 if e["type"] == "MoneyDeposited" else -1
return {**state, "balance": state["balance"] + sign * e["amount"], "version": e["v"]}
def decide_withdraw(state, amount): # command side: check the rule, emit events
if state["balance"] - amount < -state["limit"]:
raise ValueError("insufficient funds")
return [{"v": state["version"] + 1, "type": "MoneyWithdrawn", "amount": amount}]
now = reduce(apply, events, None) # {'balance': 15550, 'limit': 0, 'version': 5}
as_at_v3 = reduce(apply, events[:3], None) # temporal query: balance 38000-- An event store can be an ordinary table. The primary key enforces
-- optimistic concurrency: only one writer can append version 6.
CREATE TABLE account_events (
account_id uuid NOT NULL,
version integer NOT NULL,
event_type text NOT NULL,
data jsonb NOT NULL,
recorded_at timestamptz NOT NULL DEFAULT now(),
PRIMARY KEY (account_id, version)
);
-- The command handler read the stream up to version 5, decided, and now appends:
INSERT INTO account_events (account_id, version, event_type, data)
VALUES ('2f9c0d6e-4a51-4c7e-9a43-6d1f2b7e8a10', 6, 'MoneyWithdrawn', '{"amount": 2000}');
-- If a concurrent command already appended version 6, this fails with a
-- unique violation; the handler reloads the stream and decides again.Plegado, snapshots y consultas temporales
Lo que te da el event sourcing
Una pista de auditoría completa por construcción. En un sistema basado en el estado, el log de auditoría es una segunda escritura que alguien puede olvidar, y puede no coincidir con los datos. En un sistema con event sourcing, el log son los datos, así que no puede desviarse de ellos. Los reguladores de la banca, los seguros y la sanidad lo valoran mucho.
Consultas temporales. ¿Cuál era el saldo a las 23:59 del 31 de marzo?
o ¿Qué pedidos estaban en estado PREPARING cuando falló la pantalla de la cocina?
se convierten en plegados sobre un prefijo de cada flujo, en lugar de en un trabajo forense sobre copias de seguridad.
Reconstrucciones y nuevos modelos de lectura. Como los modelos de lectura son derivados, un equipo puede corregir un bug en una proyección, borrar su salida y reproducir todos los eventos para producir una vista corregida. También puede construir, sobre todo el historial, un modelo de lectura en el que nadie pensó cuando se registraron los eventos, como un informe de la frecuencia con la que los clientes retiran efectivo durante la hora siguiente a cobrar.
Depuración y análisis hipotético (what-if). Copiar un flujo en un entorno de pruebas y reproducirlo recrea el estado exacto que causó un bug. Reproducir los mismos eventos con reglas modificadas muestra lo que habrían hecho las nuevas reglas.
Una fuente natural de eventos de integración. Los eventos pueden alimentar a otros servicios, aunque es mejor tratar los eventos almacenados en un flujo como un detalle privado del servicio propietario. Publicarlos directamente acopla a todos los consumidores al modelo interno; muchos equipos prefieren traducirlos a un conjunto más pequeño de eventos de integración públicos, diseñados como los contratos publicados de larga duración descritos en la Sección 6.4.
Snapshots y flujos largos
Plegar cinco eventos es instantáneo; plegar 400 000 eventos de una cuenta de comercio con mucho movimiento en cada comando no lo es. Un snapshot (instantánea) almacena el estado plegado de un flujo en una versión conocida, de modo que la carga pasa a ser leer el último snapshot y aplicar solo los eventos posteriores
. Los snapshots son una caché, no una fuente de verdad: pueden borrarse y recrearse en cualquier momento, en segundo plano, sin detener el sistema. Tómalos cada N eventos o según un calendario, y guarda junto a ellos la versión del código que aplica los eventos, porque un snapshot producido por código antiguo es incorrecto en cuanto cambia la lógica del plegado.
Antes de recurrir a los snapshots, revisa el diseño del flujo. Los flujos muy largos suelen indicar que el agregado es demasiado grande. Una cuenta bancaria que dura 40 años puede modelarse como una serie de flujos más cortos, uno por periodo de extracto, cada uno abierto con un evento BalanceCarriedForward que registra el saldo de cierre del periodo anterior. Esto refleja cómo cierran los libros los contables, y mantiene cada flujo lo bastante corto como para cargarse rápidamente.
Los costos, dichos con franqueza
Complejidad y falta de familiaridad. El event sourcing cambia la forma en que cada desarrollador del equipo piensa en la persistencia. Preguntas sencillas como ¿qué clientes viven en Leeds?
no pueden plantearse en absoluto al almacén de eventos; necesitan una proyección. Las herramientas para inspeccionar, migrar y reparar almacenes de eventos están menos maduras que las de las tablas relacionales, y menos ingenieros han operado un sistema así en producción.
Consistencia eventual de los modelos de lectura. Cuando las proyecciones se ejecutan de forma asíncrona, un usuario puede hacer un retiro y luego ver un saldo que todavía no lo incluye. Las mitigaciones habituales son devolver la nueva versión del flujo desde el comando y hacer que el lado de consulta espere hasta que su proyección haya procesado esa versión (una garantía de leer tus propias escrituras, como en la Sección 7.4); actualizar la interfaz de usuario de forma optimista a partir del resultado del comando; o actualizar los modelos de lectura críticos de forma síncrona en la misma transacción que la anexión. Las proyecciones también deben ser idempotentes y registrar la posición que han procesado, porque los eventos pueden entregarse más de una vez tras una caída.
Versionado de eventos. Los eventos se almacenan para siempre, así que su esquema nunca puede cambiarse sin más. Cuando MoneyDeposited incorpora un campo de moneda, años de eventos antiguos siguen sin tenerlo. Las técnicas habituales, catalogadas por Greg Young en Versioning in an Event Sourced System, incluyen los lectores tolerantes, que aportan valores por defecto para los campos que faltan; el upcasting (una función que convierte una versión antigua de un evento a la forma actual en el momento de leerlo, de modo que el código del dominio solo ve una versión); la introducción de un nuevo tipo de evento junto al antiguo; y, como último recurso, la copia de un flujo entero en uno nuevo con los eventos transformados. La Sección 7.7 trata las reglas generales de compatibilidad.
Borrar datos personales. Un log inmutable choca con el derecho de supresión que establece la legislación de protección de datos. La técnica habitual es el crypto-shredding (destrucción criptográfica): los campos personales de los eventos se cifran con una clave guardada por cliente en un almacén de claves aparte, y la supresión consiste en destruir esa clave para que el texto cifrado ya no pueda leerse. La alternativa es mantener los datos personales totalmente fuera de los eventos y almacenar solo una referencia a un registro que pueda borrarse. Si destruir una clave cuenta o no como supresión es una valoración jurídica más que técnica, así que acuerda el enfoque con el delegado de protección de datos; la Sección 8.7 trata las obligaciones más amplias.
Carga operativa. Reconstruir una proyección sobre mil millones de eventos puede llevar horas, así que los equipos necesitan una forma de ejecutar la nueva proyección junto a la antigua y cambiar a ella cuando se ponga al día. Los almacenes de eventos crecen sin límite, y con ellos crecen el almacenamiento y los tiempos de copia de seguridad y de reproducción.
Guía de decisión
Guía de decisión: ¿debería esta parte del sistema usar CQRS o event sourcing?
Hazte estas preguntas sobre un contexto delimitado, no sobre todo el sistema.
- ¿Esta área consiste sobre todo en operaciones sencillas de crear, leer, actualizar y borrar, con pocas reglas de negocio?SíUsa un modelo convencional con una base de datos. Aquí ninguno de los dos patrones compensará su costo.NoContinúa: el dominio tiene un comportamiento real que merece la pena modelar.
- ¿Las lecturas y las escrituras difieren mucho en forma o en volumen (por ejemplo, muchas pantallas desnormalizadas, búsquedas, o mil lecturas por cada escritura)?SíConsidera CQRS. Empieza por la forma más ligera: código de lectura separado o vistas sobre la misma base de datos.NoMantén un único modelo; añade una réplica de lectura o una caché si el único problema es la carga de lectura.
- ¿Tiene valor el propio historial: auditoría regulatoria, consultas temporales, reproducción con la lógica corregida o muchos modelos de lectura futuros a partir de los mismos hechos?SíConsidera el event sourcing para este contexto, idealmente un dominio parecido a un libro mayor, como las cuentas, los pagos o los ciclos de vida de los pedidos.NoAlmacena el estado actual; publica eventos con una bandeja de salida (outbox) si otros servicios necesitan enterarse de los cambios.
- ¿Tiene el equipo la experiencia, las herramientas y el tiempo necesarios para gestionar el versionado de eventos, las reconstrucciones de proyecciones y la consistencia eventual?SíAdelante: mantén pequeña el área con event sourcing y registra la decisión y sus motivos en un ADR.NoAlmacena el estado actual más una tabla de auditoría de solo anexado, que aporta la mayor parte del beneficio de auditoría por una fracción del costo.
Cuándo no usar ninguno de los dos, y errores comunes
Ninguno de los dos patrones encaja en un dominio que consiste sobre todo en formularios sobre datos, en un equipo pequeño que construye su primera versión, ni en un sistema cuyo único problema es la carga de lectura (una réplica de lectura o una caché es mucho más barata). El event sourcing también encaja mal donde los datos deben borrarse de verdad bajo demanda y en gran volumen, o donde la mayoría de las consultas abarcan muchos agregados, ya que cada una de esas consultas necesita su propia proyección.
Los errores comunes son previsibles. Los equipos aplican los patrones a todo el sistema en lugar de a un contexto. Exponen los eventos almacenados como contrato público, lo que congela su modelo interno. Ponen valores derivados o llamadas externas en la función que aplica los eventos, de modo que la reproducción da respuestas distintas. Diseñan los eventos como blobs genéricos AccountUpdated, que registran que algo cambió, pero no qué ocurrió ni por qué, y pierden la mayor parte del valor. Y olvidan que un modelo de lectura es una caché: empiezan a escribir en él directamente, y a partir de ese momento ya no puede reconstruirse.
Usada de forma selectiva, la combinación es potente. Una plataforma de reparto de comida podría aplicar event sourcing al ciclo de vida del pedido (realizado, aceptado, en preparación, recogido, entregado, reembolsado), porque las disputas y los reembolsos necesitan el historial exacto, y mantener las cartas, los perfiles de los restaurantes y la configuración de los usuarios como tablas ordinarias. Un banco podría aplicar event sourcing al libro mayor y a los pagos y almacenar de forma convencional los datos de contacto de los clientes, lo que además mantiene la mayor parte de los datos personales fuera del log inmutable.
Comprueba lo que has entendido
¿Por qué la función que aplica los eventos al estado nunca debe llamar al reloj del sistema?
Porque reproducir los mismos eventos siempre debe producir el mismo estado. Un reloj (o un número aleatorio, o una llamada externa) haría que la reproducción diera respuestas distintas; cualquier valor así debe capturarse dentro del evento en el momento en que se decide por primera vez.
¿Cuál es la diferencia entre el comando WithdrawMoney y el evento MoneyWithdrawn?
El comando es una solicitud que las reglas de negocio pueden rechazar; el evento es un hecho registrado que ya se ha aceptado y que solo puede compensarse con un evento posterior, nunca eliminarse.
Una proyección tiene un bug que ha producido extractos erróneos durante tres meses. ¿Cómo ayuda el event sourcing?
Como el modelo de lectura es derivado, el equipo corrige la proyección, construye un nuevo modelo de lectura reproduciendo todos los eventos (normalmente junto al antiguo) y cambia al nuevo, sin necesidad de reparar los datos a mano.
¿Forma parte un snapshot de la fuente de verdad?
No. Es un plegado en caché de un flujo en una versión dada, que puede borrarse y recrearse a partir de los eventos en cualquier momento.
Fuentes y lecturas recomendadas
¿Tienes una pregunta sobre esta sección? ArchitectBot, el asistente de estudio con IA del curso, responde primero a partir del curso.
Pregunta: “Nuestro equipo de pagos quiere aplicar event sourcing a toda la plataforma. ¿Qué partes se beneficiarían de verdad, y cómo gestionaríamos las solicitudes de supresión del RGPD (GDPR)?”