Documentación de Arquitectura Event-Driven con el Modelo C4
La arquitectura event-driven se ha convertido en el estándar para construir sistemas escalables y poco acoplados. Los servicios publican eventos cuando algo sucede. Otros servicios se suscriben a esos eventos y reaccionan. El publicador no sabe quién está escuchando. El suscriptor no sabe quién publicó. El sistema está desacoplado, es resiliente y flexible.
También es casi invisible.
Cuando miras un diagrama C4 tradicional de un sistema event-driven, ves servicios con flechas apuntando a un message broker. El Servicio A publica a Kafka. El Servicio B consume de Kafka. Pero, ¿qué eventos fluyen entre ellos? ¿Cuál es el esquema? ¿Quién más está escuchando? ¿Qué pasa si un consumidor falla? El diagrama muestra la infraestructura pero oculta el comportamiento.
Documentar la arquitectura event-driven requiere técnicas que hagan visible lo invisible -- que muestren no solo la infraestructura (brokers, colas, topics) sino los eventos en sí, sus flujos, sus esquemas y sus garantías. Esta guía cubre cómo hacerlo usando el modelo C4 y cómo las funciones de event channel de Archyl hacen de los sistemas event-driven ciudadanos de primera clase en tu documentación de arquitectura.
Por Qué los Sistemas Event-Driven Son Difíciles de Documentar
La arquitectura event-driven introduce varios desafíos de documentación que no existen en sistemas síncronos de petición-respuesta. (Para la parte de petición-respuesta, consulta cómo documentar una arquitectura de microservicios.)
Flujo de Control Invisible
En un sistema síncrono, puedes rastrear una petición del cliente al servidor siguiendo la cadena de llamadas. El Servicio A llama al Servicio B, que llama al Servicio C. El flujo de control es explícito y visible en el código.
En un sistema event-driven, el flujo de control es implícito. El Servicio A publica un evento OrderCreated. En algún lugar, el Servicio B reacciona a ese evento reservando inventario. En otro lugar, el Servicio C reacciona enviando un email de confirmación. El Servicio A no sabe sobre B o C. El flujo de control está definido por las suscripciones a eventos, no por el código del publicador.
Esta indirección significa que no puedes entender el comportamiento del sistema leyendo el código de un solo servicio. Necesitas una vista de nivel más alto que muestre los flujos de eventos a través de los servicios -- y esa vista es exactamente lo que la documentación de arquitectura debería proporcionar.
Relaciones Muchos-a-Muchos
En arquitecturas síncronas, las relaciones son típicamente uno-a-uno o uno-a-pocos. El Servicio A llama al Servicio B. La relación es directa y documentada por la llamada API.
En arquitecturas event-driven, las relaciones son muchos-a-muchos. Un solo tipo de evento puede tener un productor y cinco consumidores. Un solo servicio puede consumir eventos de diez productores diferentes. El grafo de relaciones es más denso y complejo que en sistemas síncronos.
Los diagramas de arquitectura tradicionales luchan con esta densidad. Dibujar una flecha de cada productor a cada consumidor a través de cada topic crea un diagrama que parece un plato de spaghetti. Necesitas un enfoque de documentación que muestre los flujos de eventos en el nivel correcto de abstracción.
Evolución de Esquemas
Los esquemas de eventos evolucionan con el tiempo. El evento OrderCreated puede empezar con cinco campos y crecer a quince en dos años. Los consumidores pueden depender de campos específicos. Los cambios de esquema pueden romper consumidores si no son retrocompatibles.
Documentar el esquema actual es necesario pero no suficiente. También necesitas documentar la estrategia de versionado de esquemas, las garantías de compatibilidad y el historial de cambios incompatibles.
Consistencia Eventual
Los sistemas event-driven son eventualmente consistentes por naturaleza. Cuando el Servicio A publica un evento, el Servicio B puede procesarlo milisegundos después o minutos después (si el consumidor está atrasado o si se necesitan reintentos). El sistema está en un estado inconsistente durante esa ventana.
La documentación debería capturar estos límites de consistencia. ¿Qué partes del sistema son fuertemente consistentes? ¿Cuáles son eventualmente consistentes? ¿Cuál es el retraso de propagación esperado? ¿Qué sucede durante la ventana de inconsistencia?
Dead Letter Queues y Manejo de Errores
Cuando un consumidor de eventos falla al procesar un mensaje, el evento típicamente va a una dead letter queue (DLQ). Pero, ¿qué sucede después? ¿Quién monitorea la DLQ? ¿Cuál es la estrategia de reintentos? ¿Cómo se manejan los mensajes envenenados?
Estos patrones de manejo de errores son críticos para el comportamiento del sistema pero rara vez se documentan. Son parte de la arquitectura y deberían ser visibles en la documentación.
Modelando Sistemas Event-Driven con C4
El modelo C4 puede representar arquitecturas event-driven de forma efectiva con algunas adaptaciones en como usas cada nivel.
System Context: Enfócate en Flujos de Datos, No en Llamadas
A nivel de System Context, las arquitecturas event-driven y síncronas se ven similares. Tu sistema interactúa con usuarios y sistemas externos. La diferencia clave está en como etiquetas las relaciones.
En lugar de "llama" o "consulta," usa etiquetas que describan flujos de datos:
- "Envía eventos de pedido a"
- "Recibe confirmaciones de pago de"
- "Publica eventos de analytics a"
Estas etiquetas insinúan la naturaleza asíncrona de la comunicación sin saturar la vista de alto nivel con detalles de implementación.
Diagrama de Container: Haz Visible el Broker
El diagrama de Container es donde la arquitectura event-driven se vuelve distintiva. El message broker (Kafka, RabbitMQ, Amazon SQS/SNS, Google Pub/Sub) debería ser un container de primera clase en tu diagrama, no un detalle de implementación invisible.
Así es como podría verse un diagrama de Container para un sistema de e-commerce event-driven:
systems:
- name: E-Commerce Platform
type: software_system
containers:
- name: Order Service
type: service
technologies: [Go, PostgreSQL]
- name: Inventory Service
type: service
technologies: [Java, PostgreSQL]
- name: Notification Service
type: service
technologies: [Python, Redis]
- name: Analytics Service
type: service
technologies: [Python, ClickHouse]
- name: Event Bus
type: queue
technologies: [Apache Kafka]
relationships:
- from: Order Service
to: Event Bus
label: "Publica OrderCreated, OrderCancelled"
- from: Event Bus
to: Inventory Service
label: "Entrega eventos de pedido"
- from: Event Bus
to: Notification Service
label: "Entrega eventos de pedido y pago"
- from: Event Bus
to: Analytics Service
label: "Entrega todos los domain events"
- from: Inventory Service
to: Event Bus
label: "Publica InventoryReserved, InventoryReleased"
Observa cómo el Event Bus está en el centro del diagrama, y las relaciones nombran explícitamente los tipos de eventos que fluyen a través de él. Esto hace visibles los flujos de eventos sin crear flechas directas entre cada productor y cada consumidor.
Event Channels: Un Concepto de Primera Clase
Los topics, colas y streams individuales dentro del message broker merecen su propia documentación. Cada event channel tiene propiedades que importan para entender el sistema:
- Nombre del channel: El topic de Kafka, cola de RabbitMQ o cola de SQS
- Tipos de eventos: Qué eventos fluyen a través de este channel
- Productores: Qué servicios publican en este channel
- Consumidores: Qué servicios consumen de este channel
- Serializacion: Cómo se codifican los eventos (JSON, Avro, Protobuf)
- Estrategia de particionamiento: Cómo se distribuyen los eventos entre particiones
- Política de retención: Cuánto tiempo se conservan los eventos
- Garantías de ordenamiento: Si se preserva el orden y a que granularidad
En Archyl, los event channels son un tipo de entidad dedicado. Creas un event channel, específicas sus propiedades y lo vinculas a los servicios que producen y consumen de él. Esto crea un modelo estructurado y consultable de tus flujos de eventos.
Por ejemplo, un event channel "orders" podría documentarse así:
- Nombre: orders
- Broker: Kafka
- Productores: Order Service
- Consumidores: Inventory Service, Notification Service, Analytics Service, Billing Service
- Tipos de Eventos: OrderCreated, OrderUpdated, OrderCancelled, OrderCompleted
- Serializacion: Avro con Schema Registry
- Particionamiento: Por order ID
- Retención: 7 días
Este nivel de detalle hace visible y consultable la infraestructura invisible. Cuando un desarrollador necesita saber quién está consumiendo eventos de pedido, la respuesta está documentada y es localizable.
Diagrama de Componentes: Event Handlers y Publishers
A nivel de Componentes, los servicios event-driven tienen estructuras internas distintivas que vale la pena documentar para servicios complejos:
- Event Handlers: Componentes que consumen y procesan tipos de eventos específicos
- Event Publishers: Componentes que producen eventos
- Sagas / Process Managers: Componentes que orquestan flujos de trabajo de múltiples pasos a través de eventos
- Proyecciones: Componentes que construyen modelos de lectura a partir de flujos de eventos
Un diagrama de Componentes para el Order Service podría incluir:
- Order Controller -- maneja peticiones HTTP para la gestión de pedidos
- Order Processor -- lógica de negocio central para creación y validación de pedidos
- Event Publisher -- publica OrderCreated, OrderUpdated, OrderCancelled a Kafka
- Payment Event Handler -- consume eventos PaymentProcessed y PaymentFailed
- Order Saga -- gestiona el flujo de trabajo de cumplimiento de pedidos a través de servicios
Documenta estos componentes cuando el servicio es lo suficientemente complejo como para justificarlo -- particularmente para servicios que participan en patrones de coreografía u orquestación.
Documentando Patrones Event-Driven Comunes
Ciertos patrones aparecen repetidamente en los sistemas event-driven. Documentarlos explícitamente ahorra a los equipos tener que hacer ingeniería inversa de los patrones desde el código.
Event Sourcing
En sistemas con event sourcing, el estado de una entidad se deriva de una secuencia de eventos en lugar de almacenarse como una instantánea. El flujo de eventos es la fuente de verdad, y el estado actual es una proyección.
Documenta event sourcing mediante:
- Identificar que entidades usan event sourcing
- Listar los tipos de eventos en el flujo de eventos de cada entidad
- Documentar las proyecciones que derivan modelos de lectura de los flujos
- Anotar la estrategia de snapshotting (si la hay)
CQRS (Command Query Responsibility Segregation)
CQRS separa las operaciones de escritura (commands) de las operaciones de lectura (queries), a menudo usando eventos para mantener el modelo de lectura sincronizado con el modelo de escritura.
Documenta CQRS mediante:
- Separar claramente los containers del lado de escritura de los containers del lado de lectura en el modelo C4
- Documentar el flujo de eventos del lado de escritura al lado de lectura
- Anotar el modelo de consistencia (que tanto atraso puede tener el modelo de lectura)
Coreografía vs. Orquestación
En la coreografía, los servicios reaccionan a eventos de forma independiente. No existe un coordinador central. En la orquestación, un servicio central (el orquestador o saga) coordina el flujo de trabajo enviando commands y escuchando respuestas.
Documenta qué patrón usa tu sistema para cada flujo de trabajo. Si usas coreografía, documenta la secuencia esperada de eventos y los servicios que participan. Si usas orquestación, documenta la máquina de estados de la saga y los commands que emite.
Dead Letter Queues y Patrones de Reintentos
Documenta tu estrategia de manejo de errores para el procesamiento de eventos:
- ¿Qué eventos tienen dead letter queues?
- ¿Cuál es la política de reintentos (cantidad, estrategia de backoff)?
- ¿Quién es responsable de monitorear y reprocesar eventos de la DLQ?
- ¿Qué alertas están configuradas para la acumulación en la DLQ?
En Archyl, puedes modelar DLQs como event channels adicionales vinculados a los channels primarios. Esto hace visible la infraestructura de manejo de errores en la documentación de arquitectura.
Documentando Esquemas de Eventos
Los esquemas de eventos son contratos entre productores y consumidores. Merecen el mismo nivel de documentación que los contratos de API en sistemas síncronos.
Documentación de Esquemas
Para cada tipo de evento, documenta:
- Nombre del evento: Un nombre claro y específico del dominio (OrderCreated, no GenericEvent)
- Versión del esquema: La versión actual del esquema
- Campos: Todos los campos con sus tipos, descripciones y si son requeridos u opcionales
- Payload de ejemplo: Un ejemplo representativo en JSON/Avro/Protobuf
- Compatibilidad: Si el esquema es compatible hacia adelante, hacia atrás o completamente compatible
La función de API Contract de Archyl puede usarse para documentar esquemas de eventos junto con especificaciones REST y gRPC. Vincula el contrato al event channel para crear una conexión directa entre el esquema y la infraestructura.
Estrategia de Evolución de Esquemas
Documenta el enfoque de tu equipo para la evolución de esquemas:
- ¿Usan un schema registry (Confluent Schema Registry, AWS Glue)?
- ¿Qué modo de compatibilidad se aplica (backward, forward, full)?
- ¿Cómo se comunican los cambios incompatibles a los consumidores?
- ¿Cuál es el proceso de deprecación para versiones antiguas de esquemas?
Esta información pertenece a un ADR vinculado a tu infraestructura de eventos. Es una decisión que afecta a todo el sistema y debería documentarse una vez, claramente, y ser referenciada por todos los equipos.
Visualizando Flujos de Eventos
Los diagramas estáticos pueden mostrar la infraestructura de eventos, pero luchan por mostrar los flujos de eventos -- la secuencia de eventos que implementa un proceso de negocio.
Usa Flows para Procesos de Negocio
La función de Flow de Archyl te permite documentar la secuencia de eventos que implementa un proceso de negocio. Por ejemplo, un flow de "Realización de Pedido" podría mostrar:
- El cliente envía el pedido vía la Web App
- El API Gateway reenvía la petición al Order Service
- El Order Service valida y persiste el pedido
- El Order Service publica el evento OrderCreated a Kafka
- El Inventory Service consume OrderCreated, reserva inventario
- El Inventory Service publica el evento InventoryReserved
- El Payment Service consume InventoryReserved, procesa el pago
- El Payment Service publica el evento PaymentProcessed
- El Notification Service consume PaymentProcessed, envía email de confirmación
Este flow muestra el comportamiento end-to-end que emerge de la arquitectura event-driven. Ningún código de un solo servicio revela este flow -- solo existe a nivel de arquitectura.
Usa Overlays para Diferentes Vistas
Crea overlays para mostrar diferentes aspectos de tu arquitectura event-driven:
- Overlay de Flujo de Eventos: Resalta solo las relaciones relacionadas con eventos, ocultando la comunicación síncrona
- Overlay de Productor/Consumidor: Colorea servicios basado en si producen, consumen o ambos
- Overlay de Manejo de Errores: Muestra DLQs, rutas de reintentos y monitoreo
Los overlays te permiten crear vistas enfocadas desde un único modelo de arquitectura, evitando la necesidad de múltiples diagramas redundantes.
Buenas Prácticas
Nombra los Eventos Según Acciones del Dominio, No Operaciones Técnicas
Usa nombres como OrderCreated, PaymentFailed, InventoryReserved -- no DataUpdated, MessageSent o RecordInserted. Los nombres específicos del dominio hacen legibles los flujos de eventos a nivel de arquitectura.
Documenta la Decisión de "Por Qué No Síncrono"
Para cada interacción event-driven, hubo una decisión de usar comunicación asíncrona en lugar de síncrona. Documenta esa decisión. ¿Por qué el Order Service publica un evento en lugar de llamar al Inventory Service directamente? La respuesta (desacoplamiento, resiliencia, escalabilidad) debería capturarse en un ADR.
Mantén la Documentación de Event Channels Cerca del Código
Si tus esquemas de eventos están definidos en el código (archivos Protobuf, esquemas Avro, JSON Schema), vincula la documentación de arquitectura a esos archivos. Esto crea una conexión entre la documentación abstracta y la implementación concreta.
Revisa los Flujos de Eventos Durante las Revisiones de Arquitectura
Durante las revisiones de arquitectura trimestrales, repasa tus flujos de eventos documentados. Pregunta:
- ¿Hay nuevos tipos de eventos que no están documentados?
- ¿Hay tipos de eventos documentados que ya no se usan?
- ¿Se han agregado nuevos consumidores sin actualizar la documentación?
- ¿Los esquemas documentados siguen siendo precisos?
La detección de drift de Archyl ayuda a responder estas preguntas automáticamente, pero la revisión humana periódica detecta cosas que las verificaciones automatizadas no captan.
Conclusión
La documentación de arquitectura event-driven requiere un esfuerzo intencional para hacer visible lo invisible. Los eventos, por diseño, desacoplan productores de consumidores. Esta es una fortaleza arquitectónica pero un desafío de documentación.
El modelo C4 proporciona el framework: System Context para la visión general, diagramas de Container con el message broker como elemento de primera clase, event channels para documentación detallada de topics y colas, y diagramas de Componentes para event handlers y sagas complejos.
Archyl proporciona las herramientas: event channels como entidades de primera clase, flows para documentar procesos de negocio event-driven, contratos de API para esquemas de eventos, overlays para vistas enfocadas y detección de drift para detectar cambios no documentados.
Documenta tu arquitectura event-driven de la misma forma en que la diseñas: con intención, estructura y la comprensión de que el comportamiento del sistema emerge de las interacciones entre servicios, no de ningún servicio individual.
Comienza con Archyl y haz tu arquitectura event-driven visible, documentada y comprendida.