Este post es el primero de una serie dedicada a las arquitecturas orientadas a eventos. En este post vamos a hablar brevemente de las arquitecturas EDA, en qué consisten y qué hay que tener en cuenta a la hora de trabajar en este tipo de arquitecturas.

¿Qué es EDA?

El término EDA es uno de los más populares hoy día si hablamos de software y, en concreto, de arquitectura.

Podemos pensar que lo que define a una arquitectura de este tipo es el intercambio de mensajes entre múltiples servicios, de forma asíncrona, usando un bus de mensajería. Asociado a este pensamiento, también encontramos la creencia de que intercambiar cualquier tipo de mensaje de forma asíncrona favorece un menor acoplamiento y, por ello, se tiende a diseñar los sistemas utilizando solo intercambio asíncrono. Esto lleva a verdaderas obras de ingeniería para implementar comportamientos de negocio que requieren de sincronía mediante soluciones de naturaleza asíncrona, soportadas en herramientas de intercambio de mensajes de este tipo.

EDA significa “Event Driven Architecture”, que traducido literalmente sería “Arquitectura Guiada por Eventos”. Como su propio nombre indica, la clave en este tipo de arquitectura son los eventos (de negocio) como principio de diseño. La clave no es usar microservicios que se comunican de forma asíncrona, sino identificar y definir correctamente los eventos que se producen en el sistema, qué acción los desencadena (y cuándo) y qué se produce a raíz de esos eventos.

Es cierto que, en este tipo de arquitecturas, el intercambio de información suele ser de naturaleza asíncrona, pero esto no quiere decir que no pueda haber intercambio de información de forma síncrona o que haya que forzar a utilizar una herramienta concreta.

Por lo tanto, EDA implica entender muy bien la sucesión y gestión de eventos (de negocio) que se realizan dentro del contexto de un problema o necesidad.

Definiendo “evento”

Como hemos dicho, cuando trabajamos con arquitecturas orientadas a eventos, el elemento principal, valga la redundancia, es el evento. Pero… ¿qué es un evento?

En muchas ocasiones se puede confundir el término y llamar “evento” a un mensaje intercambiado mediante una plataforma o bus de eventos. Cuando hablamos de eventos, la semántica importa, y mucho. Un evento es algo que ha sucedido, un hecho. A veces, los eventos se producen como resultado de acciones que se ejecutan, como resultado de otros eventos o simplemente por cumplirse una condición temporal.

Por tanto, al trabajar en arquitecturas orientadas a Eventos tenemos que ser cuidadosos a la hora de identificar hechos que suceden en el sistema, teniendo claro su origen y si se producen como respuesta a la ejecución de una acción, como resultado de otro evento o como el cumplimiento de una acción temporal. Por lo tanto, tenemos que distinguir entre comandos para ejecutar acciones y eventos. Veamos la diferencia:

  • Un comando es una petición de ejecución de una orden, de una acción. La ejecución puede realizarse o no y, de realizarse, puede terminar con un estado satisfactorio o no. Es la declaración de una intención, de un deseo. Además, un comando suele ir dirigido (implícita o explícitamente) a un único receptor: el ejecutor del comando. Por ejemplo, un comando puede ser: “quiero crear un usuario con este conjunto de datos”. Si trabajamos con un API síncrono, sabemos perfectamente a quién enviamos el comando pero, en un escenario asíncrono en el que el mensaje se envía a un bus de mensajería y cualquiera podría escucharlo, nos interesa que sea escuchado por el receptor capaz de ejecutar la acción.
    En algunos documentos podemos encontrar la distinción entre comando y query, siendo el primero para acciones de escritura y el segundo para acciones de lectura.
  • Un evento es la constatación de que algo ha sucedido realmente. No es una intención, es un hecho. No se puede cancelar ni cambiar. Es inmutable. Además, a diferencia del comando, un evento no suele ir dirigido a un único receptor, sino que es una publicación de algo que ha pasado para que, quien deba o quiera, reaccione ante ese hecho. Siguiendo con el ejemplo anterior, el evento resultado del comando de creación de usuario puede ser “nuevo usuario creado (en el sistema)”. Este evento podría dar lugar a un nuevo comando “enviar una notificación al usuario”, “preparar kit de bienvenida”, “actualizar estadísticas”, etc.
    Ambos, comandos y eventos, pueden ser mensajes que se publican y consumen en un broker de mensajería como puede ser Kafka o RabbitMQ. Pero, como hemos explicado, existe una importante diferencia semántica entre comandos y eventos. Esta diferencia semántica es clave a la hora de diseñar soluciones dentro de arquitecturas EDA.

Tipos de eventos

Un evento es algo que sucede en el sistema, un hecho consumado, inmutable. Esto no quiere decir que todo lo que suceda en el sistema “importe” a todo el mundo. Habrá eventos que sean únicamente importantes dentro de determinados contextos y habrá otros que interesen fuera de esos contextos. Por ello, a la hora de diseñar sistemas basados en eventos, podemos encontrar diferentes “tipos de eventos” según el escenario y caso de uso:

  • Evento de dominio: este evento se lanza cuando se produce un hecho importante dentro de un dominio o contexto. En algunos sitios se limitan o conocen como eventos privados dentro de un dominio o contexto, aunque no es del todo estricto. Son muy importantes porque describen el negocio (los hechos) dentro de un dominio. Los nombres de los eventos de dominio tienen significado en el dominio o contexto en el que se declaran, dentro de su lenguaje ubicuo.
    Contienen toda la información asociada al hecho, ya que la intención del evento es comunicar que ha sucedido algo importante en el dominio y poder reaccionar.
  • Evento de notificación: este tipo de evento se utiliza cuando se quiere notificar que ha ocurrido un hecho en un dominio o contexto que puede ser “interesante” para otros dominios o contextos. También los podemos encontrar como eventos de integración. Al igual que los eventos de dominio, su intención es difundir un hecho ocurrido en un dominio, pero la diferencia está en que ese hecho es importante no solo para el dominio, sino para otros dominios del sistema.
    A nivel de contenido, contienen la información mínima que identifica a los hechos a los que se asocian, como el identificador de la entidad o el agregado. En el caso de que el consumidor necesite más información, debe pedirla explícitamente al dominio origen del evento. La principal motivación de este evento es que cualquiera, en un sistema, puede estar informado de que algo ha ocurrido, pero no todo el mundo debería tener acceso a los detalles. De ahí, que un consumidor de un evento de notificación tenga que pedir los detalles explícitamente a la “fuente de la información” y, podrá recibirla o no.
    Esto quiere decir que, si optamos por este tipo de eventos, debemos disponer además de un API que proporcione información sobre la entidad o agregado al que referencia el evento, a partir del id de entidad que está incluido en la información del evento.
  • Evento de cambio de estado (event-carried state transfer): en este caso, el evento informa de un cambio de estado en un agregado o en una entidad importante del dominio, conteniendo la información asociada al cambio.
    La intención de este tipo de eventos es proporcionar a los consumidores información completa para que puedan mantener vistas materializadas dentro de sus dominios para evitar tener que acceder a otros dominios a consultar información. De este modo, eliminamos latencias y favorecemos la autonomía y la resiliencia, ya que no es necesario acceder siempre al dominio origen para obtener información. A nivel de contenido, se puede adoptar un enfoque de incluir siempre todo el contenido o incluir solo la información que ha cambiado.
    A la hora de usar este tipo de eventos en el diseño de soluciones, hay que tener en cuenta la consistencia eventual asociada a las vistas que alimentan. Esto quiere decir que puede haber momentos en los que esas vistas no estén actualizadas 100%. Determinados casos de uso de Negocio pueden exigir una sincronización del 100% por lo que en esos casos, estas vistas no son útiles, teniendo que ir directamente a la fuente de la información.

Me gustaría comentar que no es necesario forzar esta distinción de eventos si vemos que añade complejidad al diseño del sistema. A veces no está muy clara la diferencia entre unos y otros o se pueden usar indistintamente siempre que tengamos cuidado con el acoplamiento funcional.

Acoplamiento en EDA

A la hora de modelar sistemas mediante eventos siempre tenemos que tener el objetivo de modelar dominios y contextos lo más independientes posible. Muchas personas mantienen la teoría de que si estamos en una arquitectura EDA utilizando comunicaciones asíncronas, eliminamos el acoplamiento entre sistemas, ya que productores y consumidores no están directamente enlazados, sino que se comunican mediante un broker de mensajería.

Este principio de que no existe acoplamiento no es del todo correcto. Por ejemplo, imaginemos un sistema dividido en dos dominios: selección y empleados. Aunque ambos podrían caer dentro de un mismo dominio padre, que podría ser “Personas”, Negocio los considera contextos diferentes:

  • Selección: se encarga de la búsqueda y selección de candidatos para que se incorporen a la empresa. Su responsabilidad termina con la firma del contrato. Dentro de este contexto tiene sentido hablar de candidato, “entrevista”, “oferta”, “precontrato” o “incorporación”.
  • Empleados: se encarga de gestionar y facilitar la vida dentro de la empresa, una vez que una persona forma parte de ella. En este contexto tienen sentido términos como “kit de bienvenida” o “mentor”.

Si analizamos el negocio y contexto de “selección” podemos observar la siguiente secuencia de eventos:

Secuencia de eventos en el negocio y selección

Como podemos observar, eventos como “entrevista realizada” o “precontrato firmado” no tienen importancia o significado dentro del contexto de “empleados”. Además, en ese dominio tampoco necesitan enterarse de ellos. En el dominio de “empleados” sólo se necesita saber que se ha contratado a una persona para preparar el “kit de bienvenida” y asignar un mentor.

Imaginemos que, cuando estamos diseñando el sistema, establecemos que una contratación se ha realizado sí y solo sí cuando se han dado los siguientes eventos:

  • Documentación recibida.
  • Precontrato firmado.
  • Documentación validada.

Se tienen que dar los tres, pero la secuencia temporal no es siempre la misma.

Al hacer esto, lo primero que podemos observar es que se está trasladando lógica de negocio o detalles del contexto de “selección” a “empleados”, ya que “empleados” debe implementar una lógica propia de “selección”. Lo segundo que nos debe llamar la atención es que “empleados” no sabe qué significan realmente esos términos porque no son objeto de su negocio.

Teniendo en cuenta estos dos puntos, ¿qué sucedería si mañana se decide que para dar una contratación por realizada, además de esos tres requisitos o eventos (precontrato firmado, fecha cerrada y documentación validada) se necesita que el nuevo empleado rellene un formulario de incorporación? Tendríamos que modificar la lógica que hemos incluido en el dominio de “empleados” porque con la decisión que hemos tomado anteriormente hemos acoplado ambos dominios desde el punto de vista funcional.

El uso de un broker de mensajería proporciona un bajo acoplamiento técnico, pero no evita los acoplamientos funcionales fuertes, perdiendo la independencia de dominios y contextos. ¿Cómo podríamos evitar ese acoplamiento funcional fuerte? Usando un evento de notificación.

Por ejemplo, podemos plantear el evento “Contratación realizada”:

Evento Contratación realizada

El término “Contratación” sí es algo que interesa a ambos contextos porque marca la relación entre ambos contextos (se puede conocer como “pivote”). Es un concepto que no va a cambiar e identifica de forma inequívoca que una persona pasa de candidato a empleado, independientemente de si “selección” necesita previamente realizar una o quince acciones dentro de su contexto. De este modo, no acoplamos los contextos y pueden evolucionar de forma independiente:

  • No revelamos detalles de “selección” a “personas”
  • La arquitectura es evolucionable porque “selección” puede cambiar el proceso las veces que quiera, de forma independiente y unilateralmente, sin depender de que otros dominios realicen acciones como consecuencia de esa evolución.
  • “Empleados” solo tiene que escuchar un único evento que, además, tiene significado para ambos contextos.

Estructura de un evento

Cuando estamos diseñando una arquitectura orientada a eventos, un punto de discusión habitual es el contenido de un evento porque realmente no hay un estándar oficial dentro de la comunidad. Por ello, la Cloud Native Computing Foundation (CNCF) trabaja en un estándar bajo el proyecto CloudEvent.

Si consultamos la especificación 1.0.2 de CloudEvent core, podemos ver que todo evento debe contener información sobre el hecho (datos) que referencia y sobre el contexto (metadatos) en que se produce el hecho.

A continuación, vamos a detallar qué puede contener cada sección tomando como punto de partida la especificación de CloudEvents. El objetivo de este apartado no es establecer una única estructura de mensaje, sino que pueda servir como punto de partida en cada contexto.

Metadatos

Dentro de los metadatos o información de contexto tenemos que incluir información que nos ayude a conocer el origen del evento, su posible relación con otros eventos o hechos:

  • Origen: indica dónde o quién ha producido el evento (dominio o subdominio). Si queremos identificar la aplicación o servicio que produce el evento se podría añadir un metadato más en vez de utilizar este. La razón es que, a lo largo del tiempo, es más probable que los productores cambien que cambien los dominios.
  • Identificador único del evento: debe ser único dentro del sistema. Se puede usar una combinación de origen e identificador para lograr la unicidad. Tener identificadores únicos de eventos nos ayuda a gestionar la trazabilidad o la idempotencia.
  • Tipo: tipo de evento, según los tipos que se hayan acordado en la organización.
  • Fecha: fecha de creación del evento. Es aconsejable usar un formato estándar como el ISO 8601.

Es importante que se defina una estructura clara de metadatos obligatorios que sea la base de la estructura de todos los eventos dentro de una compañía.

Por otro lado, si necesitamos enriquecer estos metadatos y poder dar información adecuada del contexto en cada escenario, se pueden incluir otros datos para dar más información del contexto como, por ejemplo:

  • Información de trazabilidad.
  • Identificador de correlación.
  • Identificador de transacción.
  • Identificador de sesión.
  • Identificador de dispositivo (casos de IoT).
  • Localización.
  • Tags.

Datos

Los datos que contiene el evento dependen del hecho al que referencia, por lo que establecer una estructura común para todos no es viable. Se debe definir un esquema concreto para cada evento.

A la hora de definir ese esquema, hay que tener en cuenta que la información sea la adecuada según el tipo o intención del evento para evitar verbosidad y asegurar la seguridad y privacidad de la información que contienen. Dentro de este punto, se puede optar por cifrar la información que no sea pública o restringir el acceso a cierto tipo de eventos solo a los consumidores que lo necesiten.

Contratos en EDA

Cuando trabajamos en arquitecturas que se basan en el intercambio de mensajes, sea de forma síncrona o asíncrona, disponer de mecanismos formales para establecer cómo va a ser ese intercambio de información es clave. Este mecanismo se conoce como contrato.

Un contrato es un documento que dice cómo vas a intercambiar la información (contrato operacional) y qué información vas a intercambiar (contrato informacional):

Contrato que nos dice cómo intercambiar la información

Cuando trabajamos con APIs tradicionales o síncronas, estamos muy acostumbrados a los contratos y a adoptar un enfoque “API (Contract) First” y sus ventajas (“acelerar” el desarrollo, consenso, autonomía, etc.). En EDA, también podemos y debemos trabajar de esta forma, utilizando contratos. Veamos en qué consiste un contrato en EDA.

Contrato operacional: definiendo tópicos o canales

En una arquitectura EDA, los eventos se distribuyen por medio de unos canales o tópicos a los que se suscriben los consumidores. El acceso a estos tópicos puede tener ciertos requisitos de seguridad. Esta información es la que encontraremos dentro del contrato operacional.

Tópicos o canales

Si trabajas con Kafka seguro que el término “tópico” te resulta bastante familiar. Un tópico es el canal dónde se publican eventos. Es aconsejable que un tópico esté asociado a un único tipo de evento. Es decir, debemos evitar usar “tópicos comodín”, en el que se pueda publicar cualquier evento, siendo un cajón desastre ingobernable.

Además, es importante decidir una estrategia de nombrado desde el primer momento para que el sistema sea usable, consistente y evolucionable. Al igual que con la estructura de los eventos, no hay un estándar y podemos encontrar diversas tendencias. En este post tampoco vamos a fijar un estándar, sino que vamos a enumerar una serie de buenas prácticas en el nombrado:

  • No incluyas nada que pueda cambiar, como nombres de servicios, de equipos, owners, etc. Si necesitas o quieres incluir esta información, puedes incluirla en los metadatos.
  • No incluyas información verbosa que pueda ir en los metadatos, como el nombre del esquema, versión, etc. Al igual que en el punto anterior, esta información se puede incluir en los metadatos
  • Usa minúsculas y “.” como separador de bloques principales.

Por tanto, lo ideal es que el nombre del topic represente su propósito de forma inequívoca. Por ejemplo, podemos adoptar la siguiente convención:

<dominio>.<subdominios>.<tipo>.<clasificación>.<nombre>

Donde:

  • <dominio> y <subdominios> indican el origen del dato,
  • <tipo> indica si es comando o evento,
  • <clasificación> puede tomar valores como “domain”, “esct”, “notificacion” o incluso “public” o “private”,
  • <nombre> es el propio nombre del topic.

De esta forma, con el nombre del tópico podemos saber qué tipo de información se publica en él. Por ejemplo, dentro del proceso de contratación, podríamos tener los siguientes topics:

  • recruiting.events.domain.interviews-scheduled
  • recruiting.events.domain.interviews-done
  • recruiting.events.notification.hirings

Podemos encontrar convenciones en las que se aconseja añadir un bloque final con la versión del evento asociado para gestionar mejor la evolución de los eventos y los problemas de compatibilidad hacia atrás. También, en el caso de estar en un escenario multi-tenant, en el que el broker de eventos es “compartido” por varias compañías o entornos, puede ser útil añadir un bloque que permita diferenciar de forma sencilla.

Una ventaja de la organización en bloques es que es mucho más fácil la gestión de seguridad o ACLs en caso de ser necesario. Por ejemplo, podemos definir una regla de seguridad que restrinja la escritura de los topics de dominio solo a los componentes del dominio “recruiting” mediante el uso de wildcards: “permitir escritura en recruiting.events.domain.* solo a ciertos usuarios”

Contrato informacional: esquemas

Ya hemos visto cómo distribuir la información, pero todavía no sabemos qué información se va a distribuir. Dentro de esta parte del contrato se especifica el contenido en sí del evento, incluyendo nombre y tipo de los campos, cuáles son obligatorios y cuáles opcionales y también, podemos especificar restricciones de valores para los campos. Todo esto lo definimos mediante esquemas.

Cuando hablamos de eventos y esquemas, los esquemas son la definición inequívoca de la estructura del contenido de esos eventos. Como ya hemos visto anteriormente, el contenido de un evento se define por sus datos y sus metadatos.

Como buena práctica, es aconsejable definir una estructura de metadatos fija para todos los eventos y mensajes, de modo que se facilite su gestión y su explotación. Podríamos decir que los metadatos son las “condiciones generales” del contrato. Los datos, como su estructura es única de cada evento, serían las “condiciones particulares”:

Estructura de datos y metadatos para un contrato y evento

La definición de esquemas permite que tanto productores como consumidores puedan desarrollarse por separado con garantías, de forma autónoma e independiente, sabiendo que van a entenderse porque se eliminan los problemas de integración.

Registro de esquemas

Seguramente hayas oído hablar de los registros de esquemas o incluso ya has trabajado con ellos. Es algo habitual si trabajas con Kafka, por ejemplo.

Cuando un productor diseña el contrato de un evento lo debe publicar en un registro de esquemas para que esté a disposición de toda la organización. El registro de esquemas actúa como la fuente de la verdad de contratos dentro de la organización, soportando también la posterior evolución de los eventos.

Los desarrolladores lo usan para construir tanto productores como consumidores. En tiempo de ejecución, esos productores y consumidores lo usan para construir y validar los mensajes, basándose en los esquemas publicados.

Esquemas que usan los productores y consumidores

Por tanto, el registro de esquemas es una pieza fundamental para garantizar la autonomía e independencia entre los diferentes productores y consumidores permitiendo que el sistema sea gobernable y evolucionable en el futuro. Sin un registro de esquemas, nos encontraremos en poco tiempo con una arquitectura EDA ingobernable.

Evolución y versionado de eventos

Siempre que diseñemos un sistema tenemos que pensar en los requisitos actuales pero teniendo en cuenta la evolución futura del sistema. En el caso de EDA, como en el de cualquier otra arquitectura, es aconsejable que las evoluciones surjan de manera natural, basándose en las necesidades de cada momento.

Aunque parezca obvio, no pensemos en versionar eventos que no estamos usando en producción. Una vez estemos produciendo y consumiendo eventos en producción, sí tenemos que tener cuidado a la hora de evolucionar los eventos.

Una vez más, nos apoyamos en los contratos. Evolucionar un evento implica diseñar un nuevo contrato. Lo normal es que solo modifiquemos el contrato informacional para modificar la información que incluye.

A la hora de modificar este contrato informacional, como buenas prácticas podemos destacar:

  • No rompas producción: el nuevo contrato debería siempre intentar ser compatible con el anterior. Un contrato que es compatible con las versiones anteriores nunca va a causar problemas en los consumidores. Un contrato que no lo es puede echar abajo un sistema.
    Si el cambio de información es tal que no puede ser compatible (cambio de tipos, cambios en la obligatoriedad de la información, eliminación de campos…) deberás pasar a una versión “mayor” del evento. A la hora de estos cambios, puede ser más sencillo que también cambies el contrato operacional proporcionando un nuevo canal en el que publicar la nueva versión y determinar una ventana de tiempo en la que los consumidores puedan pasar ordenadamente al nuevo canal. Por este motivo, algunas personas recomiendan añadir el número mayor de versión al nombre del topic (recruiting.events.notification.hirings.v1).
  • No tengas más de dos versiones de un mismo evento en producción: relacionado con el punto anterior, determina una ventana temporal en la que se desechará la versión antigua.

Evolución en los eventos de notificación: a tener en cuenta

Una evolución natural en este tipo de arquitecturas es incluir más información en los eventos de notificación o integración a medida que se dispone más información del uso en producción.

Si usas eventos de notificación, debes incluir solo la mínima información que permita que si el consumidor necesita más información pueda realizar una petición (síncrona o asíncrona) al origen.

Ahora bien, podemos caer en la tentación de reducir llamadas incluyendo más información en esos eventos y así reducir latencia y tráfico en la red. A la hora de hacer esto, si “eliminamos” la petición extra para solicitar información a demanda, tenemos que tener en cuenta que:

  • Puede que no toda la información que nos pide el cuerpo añadir deba ser pública para los consumidores actuales de esos eventos, incluso perdiendo información de auditoría (quién ha consultado qué).
  • Puede que cierta lógica de negocio requiera una petición explícita para garantizar que se accede a la versión más reciente del dato.

Por ejemplo, tenemos un evento “contratación realizada” en la que actualmente solo se incluye el NIF. Estudiando producción vemos que un gran porcentaje de llamadas posteriores al evento son para pedir el nombre, apellidos y datos de contacto del contratado. Antes de eliminar esa llamada a demanda, tenemos que evaluar si es rentable y aconsejable incluir esa información en el evento que ya se está consumiendo y que pondremos a disposición de todos los consumidores actuales.

Herramientas

Por último, vamos a hablar de herramientas. Cuando trabajamos con arquitecturas más tradicionales o con mensajería síncrona, las herramientas de las que disponemos son más abundantes y maduras. En arquitecturas EDA todavía no hay tanta madurez de herramientas y estándares, pero ya podemos decir que hay un base suficiente y estable. Vamos a ver algunas herramientas que podemos usar.

Registro de esquemas

El registro de esquemas nos permite compartir los esquemas de los metadatos y datos de los eventos entre productores y consumidores, sirviendo además como validadores.

El registro de esquemas es una herramienta muy usada habitualmente, pero que presenta el gap de que no ofrece contratos completos realmente, ya que no proporciona información sobre los canales o tópicos y, en muchas ocasiones, incluso deberíamos consultar varios esquemas para saber la estructura completa de un evento o mensaje:

Registro de esquemas

Dentro de los registros de esquemas típicos podemos encontrar Apicurio y Confluent.

AsyncAPI

Por si no lo conoces, AsyncAPI es un proyecto que nace para describir las APIs asíncronas, sean eventos o no, de forma similar a como describimos las APIs síncronas con OpenAPI. No voy a entrar en detalles de la especificación porque está muy bien explicado en la página oficial. Simplemente, me gustaría comentar que AsyncAPI se ha convertido en el estándar de facto para describir los contratos de las APIs asíncronas.

Podemos utilizar AsyncAPI para definir los contratos de los eventos que se intercambian entre los servicios, referenciando los esquemas publicados en el registro de esquemas y, de esta forma, poder proporcionar contratos completos:

Utilizamos AsyncAPI para definir los contratos de los eventos

A partir de esta definición, se puede incluso generar mocks para poder desarrollar de forma independiente los consumidores.

¿Por qué referenciar los esquemas en vez de crear documentos de AsyncAPI autocontenidos?

Algunas razones para ello son:

  • El registro de esquemas solo necesita los esquemas, no el resto del contrato.
  • El registro de esquemas es un componente que seguramente ya se esté usando y que disponga de muchos esquemas registrados y en uso. No tiene sentido reescribirlos en documentos de AsyncAPI.
  • Los esquemas pueden ser reutilizables, incluso dividir esquemas en partes e ir creando esquemas más grandes a partir de elementos pequeños.
  • Separando los esquemas del contrato podemos reutilizar esquemas entre contratos.
  • Mantenemos independencia entre contrato operacional y contrato informacional.

Event Catalog

Una vez que podemos definir los contratos de forma completa, nos queda el gap de cómo publicarlos de forma amigable y fácil para que puedan ser consultados por cualquier persona de la organización.

EventCatalog es un proyecto abierto que nos puede ayudar a documentar tanto nuestros eventos como los servicios que los producen o consumen como los dominios a los que pertenecen. Podemos utilizarlo de varias maneras, desde incluir nosotros toda la información a utilizar las definiciones de AsyncAPI para que alimenten el portal. Para ello, es necesario instalar el plugin de integración con AsyncAPI.

EventCatalog nos ayuda a documentar eventos y servicios

En el momento de desarrollo de este post, Event Calaog no soporta documentos AsyncAPI con esquemas en AVRO. Esta incidencia está pendiente de resolución.

Apicurio, que lo hemos nombrado como registro de esquemas, permite importar documentos AsyncAPI y utilizarlo como API Portal.

Cerrando el círculo

Finalmente, vamos a ver cómo podemos integrarlas todas para poder disponer de una solución end-to-end incorporándose dentro de nuestro proceso de CI/CD. La siguiente imagen muestra cómo sería:

Proceso de CI/CD

De esta manera, cuando un desarrollador sube un esquema o un contrato AsyncAPI al repositorio de código, el proceso de CI/CD puede publicarlo en el registro de esquemas o en el Portal para que cualquier persona de la organización pueda disponer del contrato de forma inmediata.

Conclusión

En este post hemos abordado la mayoría de los principios básicos dentro de las arquitecturas EDA, a nivel teórico, desde el diseño de eventos y tópicos hasta un vistazo a las herramientas más habituales. Espero que haya sido de utilidad. En posts posteriores, aterrizaremos todos estos conceptos y principios a nivel práctico, mediante un caso de uso.

Cuéntanos qué te parece.

Los comentarios serán moderados. Serán visibles si aportan un argumento constructivo. Si no estás de acuerdo con algún punto, por favor, muestra tus opiniones de manera educada.