Documentacion de Arquitectura Event-Driven con el Modelo C4 - Archyl Blog

Las arquitecturas event-driven son poderosas pero notoriamente dificiles de documentar. Los eventos son invisibles, asincronos y desacoplados por diseno. Esta guia muestra como usar el modelo C4 para documentar flujos de eventos, event channels y patrones asincronos -- y como Archyl hace visibles los sistemas event-driven.

Documentacion de Arquitectura Event-Driven con el Modelo C4

La arquitectura event-driven se ha convertido en el estandar 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 quien esta escuchando. El suscriptor no sabe quien publico. El sistema esta desacoplado, es resiliente y flexible.

Tambien 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, ¿que eventos fluyen entre ellos? ¿Cual es el esquema? ¿Quien mas esta escuchando? ¿Que pasa si un consumidor falla? El diagrama muestra la infraestructura pero oculta el comportamiento.

Documentar la arquitectura event-driven requiere tecnicas que hagan visible lo invisible -- que muestren no solo la infraestructura (brokers, colas, topics) sino los eventos en si, sus flujos, sus esquemas y sus garantias. Esta guia cubre como hacerlo usando el modelo C4 y como las funciones de event channel de Archyl hacen de los sistemas event-driven ciudadanos de primera clase en tu documentacion de arquitectura.

Por Que los Sistemas Event-Driven Son Dificiles de Documentar

La arquitectura event-driven introduce varios desafios de documentacion que no existen en sistemas sincronos de peticion-respuesta.

Flujo de Control Invisible

En un sistema sincrono, puedes rastrear una peticion 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 explicito y visible en el codigo.

En un sistema event-driven, el flujo de control es implicito. El Servicio A publica un evento OrderCreated. En algun lugar, el Servicio B reacciona a ese evento reservando inventario. En otro lugar, el Servicio C reacciona enviando un email de confirmacion. El Servicio A no sabe sobre B o C. El flujo de control esta definido por las suscripciones a eventos, no por el codigo del publicador.

Esta indireccion significa que no puedes entender el comportamiento del sistema leyendo el codigo de un solo servicio. Necesitas una vista de nivel mas alto que muestre los flujos de eventos a traves de los servicios -- y esa vista es exactamente lo que la documentacion de arquitectura deberia proporcionar.

Relaciones Muchos-a-Muchos

En arquitecturas sincronas, las relaciones son tipicamente uno-a-uno o uno-a-pocos. El Servicio A llama al Servicio B. La relacion 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 mas denso y complejo que en sistemas sincronos.

Los diagramas de arquitectura tradicionales luchan con esta densidad. Dibujar una flecha de cada productor a cada consumidor a traves de cada topic crea un diagrama que parece un plato de spaghetti. Necesitas un enfoque de documentacion que muestre los flujos de eventos en el nivel correcto de abstraccion.

Evolucion de Esquemas

Los esquemas de eventos evolucionan con el tiempo. El evento OrderCreated puede empezar con cinco campos y crecer a quince en dos anos. Los consumidores pueden depender de campos especificos. Los cambios de esquema pueden romper consumidores si no son retrocompatibles.

Documentar el esquema actual es necesario pero no suficiente. Tambien necesitas documentar la estrategia de versionado de esquemas, las garantias 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 despues o minutos despues (si el consumidor esta atrasado o si se necesitan reintentos). El sistema esta en un estado inconsistente durante esa ventana.

La documentacion deberia capturar estos limites de consistencia. ¿Que partes del sistema son fuertemente consistentes? ¿Cuales son eventualmente consistentes? ¿Cual es el retraso de propagacion esperado? ¿Que 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 tipicamente va a una dead letter queue (DLQ). Pero, ¿que sucede despues? ¿Quien monitorea la DLQ? ¿Cual es la estrategia de reintentos? ¿Como se manejan los mensajes envenenados?

Estos patrones de manejo de errores son criticos para el comportamiento del sistema pero rara vez se documentan. Son parte de la arquitectura y deberian ser visibles en la documentacion.

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: Enfocate en Flujos de Datos, No en Llamadas

A nivel de System Context, las arquitecturas event-driven y sincronas se ven similares. Tu sistema interactua con usuarios y sistemas externos. La diferencia clave esta en como etiquetas las relaciones.

En lugar de "llama" o "consulta," usa etiquetas que describan flujos de datos:

  • "Envia eventos de pedido a"
  • "Recibe confirmaciones de pago de"
  • "Publica eventos de analytics a"

Estas etiquetas insinuan la naturaleza asincrona de la comunicacion sin saturar la vista de alto nivel con detalles de implementacion.

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) deberia ser un container de primera clase en tu diagrama, no un detalle de implementacion invisible.

Asi es como podria 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 como el Event Bus esta en el centro del diagrama, y las relaciones nombran explicitamente los tipos de eventos que fluyen a traves de el. 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 documentacion. 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: Que eventos fluyen a traves de este channel
  • Productores: Que servicios publican en este channel
  • Consumidores: Que servicios consumen de este channel
  • Serializacion: Como se codifican los eventos (JSON, Avro, Protobuf)
  • Estrategia de particionamiento: Como se distribuyen los eventos entre particiones
  • Politica de retencion: Cuanto tiempo se conservan los eventos
  • Garantias 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, especificas sus propiedades y lo vinculas a los servicios que producen y consumen de el. Esto crea un modelo estructurado y consultable de tus flujos de eventos.

Por ejemplo, un event channel "orders" podria documentarse asi:

  • 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
  • Retencion: 7 dias

Este nivel de detalle hace visible y consultable la infraestructura invisible. Cuando un desarrollador necesita saber quien esta consumiendo eventos de pedido, la respuesta esta 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 especificos
  • Event Publishers: Componentes que producen eventos
  • Sagas / Process Managers: Componentes que orquestan flujos de trabajo de multiples pasos a traves de eventos
  • Proyecciones: Componentes que construyen modelos de lectura a partir de flujos de eventos

Un diagrama de Componentes para el Order Service podria incluir:

  • Order Controller -- maneja peticiones HTTP para la gestion de pedidos
  • Order Processor -- logica de negocio central para creacion y validacion 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 traves de servicios

Documenta estos componentes cuando el servicio es lo suficientemente complejo como para justificarlo -- particularmente para servicios que participan en patrones de coreografia u orquestacion.

Documentando Patrones Event-Driven Comunes

Ciertos patrones aparecen repetidamente en los sistemas event-driven. Documentarlos explicitamente ahorra a los equipos tener que hacer ingenieria inversa de los patrones desde el codigo.

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 instantanea. El flujo de eventos es la fuente de verdad, y el estado actual es una proyeccion.

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)

Coreografia vs. Orquestacion

En la coreografia, los servicios reaccionan a eventos de forma independiente. No existe un coordinador central. En la orquestacion, un servicio central (el orquestador o saga) coordina el flujo de trabajo enviando commands y escuchando respuestas.

Documenta que patron usa tu sistema para cada flujo de trabajo. Si usas coreografia, documenta la secuencia esperada de eventos y los servicios que participan. Si usas orquestacion, documenta la maquina 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:

  • ¿Que eventos tienen dead letter queues?
  • ¿Cual es la politica de reintentos (cantidad, estrategia de backoff)?
  • ¿Quien es responsable de monitorear y reprocesar eventos de la DLQ?
  • ¿Que alertas estan configuradas para la acumulacion 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 documentacion de arquitectura.

Documentando Esquemas de Eventos

Los esquemas de eventos son contratos entre productores y consumidores. Merecen el mismo nivel de documentacion que los contratos de API en sistemas sincronos.

Documentacion de Esquemas

Para cada tipo de evento, documenta:

  • Nombre del evento: Un nombre claro y especifico del dominio (OrderCreated, no GenericEvent)
  • Version del esquema: La version 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 atras o completamente compatible

La funcion 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 conexion directa entre el esquema y la infraestructura.

Estrategia de Evolucion de Esquemas

Documenta el enfoque de tu equipo para la evolucion de esquemas:

  • ¿Usan un schema registry (Confluent Schema Registry, AWS Glue)?
  • ¿Que modo de compatibilidad se aplica (backward, forward, full)?
  • ¿Como se comunican los cambios incompatibles a los consumidores?
  • ¿Cual es el proceso de deprecacion para versiones antiguas de esquemas?

Esta informacion pertenece a un ADR vinculado a tu infraestructura de eventos. Es una decision que afecta a todo el sistema y deberia documentarse una vez, claramente, y ser referenciada por todos los equipos.

Visualizando Flujos de Eventos

Los diagramas estaticos 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 funcion de Flow de Archyl te permite documentar la secuencia de eventos que implementa un proceso de negocio. Por ejemplo, un flow de "Realizacion de Pedido" podria mostrar:

  1. El cliente envia el pedido via la Web App
  2. El API Gateway reenvía la peticion al Order Service
  3. El Order Service valida y persiste el pedido
  4. El Order Service publica el evento OrderCreated a Kafka
  5. El Inventory Service consume OrderCreated, reserva inventario
  6. El Inventory Service publica el evento InventoryReserved
  7. El Payment Service consume InventoryReserved, procesa el pago
  8. El Payment Service publica el evento PaymentProcessed
  9. El Notification Service consume PaymentProcessed, envia email de confirmacion

Este flow muestra el comportamiento end-to-end que emerge de la arquitectura event-driven. Ningun codigo 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 comunicacion sincrona
  • 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 unico modelo de arquitectura, evitando la necesidad de multiples diagramas redundantes.

Buenas Practicas

Nombra los Eventos Segun Acciones del Dominio, No Operaciones Tecnicas

Usa nombres como OrderCreated, PaymentFailed, InventoryReserved -- no DataUpdated, MessageSent o RecordInserted. Los nombres especificos del dominio hacen legibles los flujos de eventos a nivel de arquitectura.

Documenta la Decision de "Por Que No Sincrono"

Para cada interaccion event-driven, hubo una decision de usar comunicacion asincrona en lugar de sincrona. Documenta esa decision. ¿Por que el Order Service publica un evento en lugar de llamar al Inventory Service directamente? La respuesta (desacoplamiento, resiliencia, escalabilidad) deberia capturarse en un ADR.

Manten la Documentacion de Event Channels Cerca del Codigo

Si tus esquemas de eventos estan definidos en el codigo (archivos Protobuf, esquemas Avro, JSON Schema), vincula la documentacion de arquitectura a esos archivos. Esto crea una conexion entre la documentacion abstracta y la implementacion 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 estan documentados?
  • ¿Hay tipos de eventos documentados que ya no se usan?
  • ¿Se han agregado nuevos consumidores sin actualizar la documentacion?
  • ¿Los esquemas documentados siguen siendo precisos?

La deteccion de drift de Archyl ayuda a responder estas preguntas automaticamente, pero la revision humana periodica detecta cosas que las verificaciones automatizadas no captan.

Conclusion

La documentacion de arquitectura event-driven requiere un esfuerzo intencional para hacer visible lo invisible. Los eventos, por diseno, desacoplan productores de consumidores. Esta es una fortaleza arquitectonica pero un desafio de documentacion.

El modelo C4 proporciona el framework: System Context para la vision general, diagramas de Container con el message broker como elemento de primera clase, event channels para documentacion 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 deteccion de drift para detectar cambios no documentados.

Documenta tu arquitectura event-driven de la misma forma en que la disenas: con intencion, estructura y la comprension de que el comportamiento del sistema emerge de las interacciones entre servicios, no de ningun servicio individual.

Comienza con Archyl y haz tu arquitectura event-driven visible, documentada y comprendida.