Hace unos días os contamos en qué consisten las arquitecturas EDA y qué hay que tener en cuenta para trabajar con ellas. Ahora, toca dejar a un lado esa teoría para ver un caso práctico. Usaremos el ejemplo de un proceso (light) de alta de un cliente u onboarding en una entidad financiera en la que se necesita un proceso de validación de la información.

Veremos cómo pasar del caso de uso de Negocio a un diseño de eventos y servicios, publicando los contratos y esquemas utilizando herramientas como AsyncAPI o Apicurio.

El caso de uso

Para aplicar la teoría, vamos a modelar un proceso de alta de clientes que tiene la peculiaridad de que la información debe ser verificada antes de que el usuario pueda acceder al sistema de forma normal.

Para entender bien el problema, decidimos hablar con las personas de Negocio para que nos cuenten de primera mano el proceso, el cual podemos ver en la siguiente imagen:

Los pasos que se realizan son los siguientes:

  1. El cliente solicita el alta mediante un wizard en el que tiene que introducir datos personales, adjuntar una serie de documentos y crear una password.
  2. Los datos son guardados en el sistema generando un cliente con estado “en espera de validación”. La documentación aportada se clasifica y se envía al gestor documental.
  3. Además, el cliente crea una password durante este proceso. Las credenciales (su NIF y esa password) se establecen en modo “inactivo”
  4. La información del cliente tiene que ser validada por una empresa externa. Se crea una solicitud de validación a la empresa externa para que proceda a validar la información.
  5. Cuando el sistema verifica la información, la solicitud queda resuelta y el proceso de validación queda finalizado.

En ese momento, si la resolución es OK, se disparan una serie de acciones para dar el alta por finalizada:

  1. Se activan las credenciales y se activa el cliente a nivel interno
  2. Se guarda y se genera la documentación adicional que sea necesaria

Estos pasos, aunque los enumeramos de forma secuencial, se realizan en paralelo.

Cuando ambos pasos se completan, se realizan los siguientes pasos:

  1. Se envía la notificación de cliente listo.
  2. Marketing, cada vez que un alta se finaliza, genera el welcome pack, lo manda al cliente y notifica que lo ha enviado.

Asociado al punto 9 (enviar welcome pack), Negocio comenta que en Marketing no se tiene información del cliente y se tiene que consultar cada vez que se necesita hacer una comunicación o envío de cualquier tipo (siendo el welcome pack un ejemplo de ello). Debido a esto, se están produciendo errores al obtener los datos de los clientes cuando el sistema está saturado, perjudicando a esos envíos de información a cliente. También comenta que solo desea tener información de los clientes activos, ya que un porcentaje de clientes no finalizan el proceso de onboarding.

Por otro lado, se comenta que existe un área de Auditoría y Calidad de Procesos que necesita medir los tiempos y calidad del proceso de alta. Para ello, necesita conocer la siguiente información:

Descubriendo eventos

Después de trabajar con Negocio, podemos identificar los siguientes eventos de dominio a lo largo del proceso de onboarding de un cliente:

Debemos recordar que estos eventos nos dicen “cómo funciona” un sistema a nivel de Negocio. No todos los eventos son de “interés” de todo el mundo o en todos los contextos.

Por lo tanto, tenemos que dar un paso más para agrupar los eventos por dominio, identificar los comandos que los generan cada evento, las entidades relacionadas y modelar las interacciones. El resultado es el siguiente:

Dentro del problema de “onboarding”, en la imagen anterior hemos identificado tres contextos importantes, como son:

Después podemos ver otros dominios secundarios o de soporte, como son “Notificaciones”, “Documentación” y “Seguridad”. En este post, los vamos a tratar como una caja negra y no vamos a entrar en detalles de los mismos.

Por otro lado, observando la imagen podemos ver cómo interactúan los contextos. Si recordamos el post anterior, en la imagen podemos ver cierto acoplamiento funcional. Veamos un par de ejemplos muy claros de este acoplamiento funcional que nos podría traer problemas en el futuro:

Por otro lado, si recordamos el caso de Negocio, se necesita informar al área de Auditoría sobre el inicio y fin del proceso de alta y el inicio y fin de la validación de documentación. Según está diseñado en este punto, también tendríamos que “incluir” lógica de los dominios de “Alta de Clientes” y “Calidad de información” en el área de Auditoría para que esta pueda saber cuándo se producen los hechos que quiere observar.

Mejorando el diseño

Como es un escenario mejorable, vamos a hacer una iteración más y para incluir otros tipos de eventos que faciliten la interacción entre contextos:

Como se puede ver en la imagen, hemos incluido una serie de eventos para relacionar los dominios:

Como trade-off a la hora de incluir estos eventos de notificación, puede ser necesario que el origen proporcione un endpoint (puede ser síncrono o asíncrono) para que el receptor de la notificación pueda preguntar por los detalles del hecho indicado en el evento. Esto es así porque los eventos de notificación son eventos muy ligeros, incluyendo solo la información necesaria para poder realizar esa consulta posterior a demanda, si fuera necesario. Por ejemplo, cuando se notifica “Onboarding iniciado” se incluye el identificador de cliente en el evento. Con este identificador, si algún consumidor necesita conocer los detalles de ese cliente puede realizar la petición usando ese identificador.

Incluyendo vistas de lectura

Ahora ya tenemos un diseño más aterrizado, pero todavía queda pendiente satisfacer el requisito de que, ahora mismo, Marketing necesita consultar siempre los datos de la base de datos de clientes utilizando un servicio para ello, queriendo minimizar estas consultas. Para ello, lo que haremos será crear una vista de clientes propia de Marketing, solo con la información que necesite. Esta vista se refrescará cada vez que haya un cambio en la información de un cliente.

Como por requisito está que solo se quiere alimentar la vista con clientes completos, el evento “Datos de cliente actualizados” solo se emite cuando el cliente queda activado, no antes.

Identificando servicios

En problemas más complejos, es mejor identificar primero las relaciones entre dominios y contextos y, después, identificar servicios y sus relaciones. En este caso, al ser un ejemplo sencillo, nos saltamos algún paso y vamos a realizar ya una primera identificación de servicios, estableciendo relaciones entre ellos:

Como podemos ver en la imagen, identificamos tres servicios que corresponden a su vez con los contextos identificados. Debemos decir que no es algo absoluto y que se puede pensar en otro tipo de divisiones. En este caso, optamos por tres por los siguientes motivos:

Además, hemos marcado con puntos las E/S de cada servicio:

Aunque la interacción con eventos suele ser de naturaleza asíncrona y la de comandos de naturaleza síncrona, no siempre es así y tenemos que evaluar los pros y contras en cada caso. Por ejemplo, el servicio de Marketing necesita interactuar con el servicio de notificaciones para comunicar al cliente que ya es un cliente real y que tiene disponible el welcome pack (se envíe por correo electrónico o correo postal). En este caso, puede ser conveniente que la ejecución del comando sea de forma asíncrona.

Diseño de los servicios

Vamos a dar otro paso más y vamos a realizar un diseño lógico de la solución por cada servicio.

Servicio de clientes

Empecemos por el servicio de clientes:

Como podemos observar en la imagen, la parte central corresponde a la parte de dominio como tal (al Negocio) y las partes rojas serían los puntos de E/S, siendo los de la parte superior de entrada y los de la parte inferior de salida. Partiendo de este punto, es relativamente fácil ir hacia una arquitectura hexagonal o de ports & adapters.

Además, como se puede ver, lo que queda dentro del servicio, como son las entidades y los eventos que se publican, son responsabilidad del propio servicio. Lo que queda fuera, como los eventos que consume, no son responsabilidad del servicio, sino de los productores.

La siguiente tabla resume estas capacidades de E/S del servicio:

Tipo Publica/expone o consume/accede Nombre Contenido
Comando (escritura) Expone Iniciar alta - Datos del cliente (personales y contacto)
- Documentación requerida
- Password deseada
Evento de Notificación Publica Onboarding iniciado Identificador de cliente
Comando (query) Expone Obtener datos cliente - Datos del cliente (personales y contacto)
Evento de Notificación Consume Validación finalizada - Identificador del cliente
- Resultado (OK/KO)
Evento de cambio de contenido (ecst) Publica Datos de cliente actualizados - Datos del cliente (personales y contacto)
Evento de Notificación Publica Onboarding finalizado - Identificador de cliente

Servicio de calidad de información

El siguiente servicio es el de Calidad de Información. Como hemos comentado se encarga de interactuar con el sistema externo, evitando que lo haga directamente el servicio de Clientes y, de este modo, proporcionar capacidades de evolución futura que no afecten al core. El servicio queda de la siguiente manera:

De forma similar al servicio anterior, la parte central es la que representa al dominio como tal mientras que las partes superiores e inferiores, representan los puntos de E/S. La siguiente tabla resume estas capacidades de E/S:

Tipo Publica/expone o consume/accede Nombre Contenido
Evento de Notificación Consume Onboarding iniciado - Identificador de cliente
Comando (query) Consume Obtener datos cliente - Datos del cliente (personales y contacto)
Evento de Notificación Publica Validación iniciada - Identificador del cliente
Evento de Notificación Publica Validación finalizada - Identificador del cliente
- Resultado (OK/KO)

Servicio de Marketing

Por último, el Servicio de Marketing queda de la siguiente forma:

La siguiente tabla resume estas capacidades de E/S:

Tipo Publica/expone o consume/accede Nombre Contenido
Evento de cambio de contenido (ecst) Publica Datos de cliente actualizados - Datos del cliente (personales y contacto)
Evento de Notificación Expone Onboarding finalizado - Identificador del cliente

Definiendo los canales o topics

En los apartados anteriores hemos identificado los eventos que se van a intercambiar mediante el broker de mensajería, pero debemos definir cómo se van a intercambiar, es decir, qué canales o topics se van a usar. Para definir los topics vamos a fijarnos en la semántica del evento y al grupo lógico al que pertenecen, teniendo también en cuenta el orden de los eventos dentro de un marco temporal.

Podemos agrupar los eventos de forma semántica de la siguiente manera:

Una vez que hemos evaluado la distribución de los eventos en tópicos vamos a ponerlos nombre. Como ya comentamos, vamos a establecer un patrón de nombrado general. En este caso, adoptamos el siguiente patrón:

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

Por lo tanto, nuestros topics serán:

Diseñando los contratos con AsyncAPI

Por último, vamos a diseñar los contratos de los servicios. Nos vamos a centrar en lo relativo a eventos, mediante AsyncAPI, no haciendo foco en los contratos basados en OpenAPI.

Si recuerdas el post anterior, hablábamos de un contrato operacional y de un contrato informacional. Prácticamente, con el desarrollo que hemos hecho en los apartados anteriores los tenemos prácticamente definidos ya a alto nivel, quedando únicamente declararlos usando AsyncAPI y esquemas AVRO.

Si quieres ir directo al final, los contratos y los esquemas los puedes encontrar en el siguiente repositorio, dentro de las carpetas “contracts” y “schemas”:

Esquemas que puedes encontrar el repositorio dentro de las carpetas.

Hemos separado los esquemas en Avro de los ficheros de AsyncAPI, de forma que pueden evolucionar por separado. La referencia la hacemos al propio repositorio de código:

Esquemas en Avro de los ficheros de AsyncAPI,

Publicando los contratos en Apicurio

Finalmente, vamos a publicar los contratos en Apicurio para que estén disponibles para productores y consumidores de modo que puedan empezar los desarrollos de forma independiente.

Sigue las instrucciones del Readme del repositorio para levantar un entorno con Apicurio. Una vez arrancado, puedes acceder a Apicurio con la siguiente url: http://localhost:8080

Levantar el entorno Apicurio.

Para publicar los contratos y los esquemas puedes hacerlo a mano, con el botón “Upload Artifact” o bien ejecutar el script “upload.sh” que encontrarás en el repositorio. Simplemente ejecuta:

sh upload.sh

Y si refrescas la consola de Apicurio verás los diferentes esquemas y contratos cargados:

Si refrescas, verás los esquemas Apicurio

Si hacemos click en cualquiera de ellos, podemos ver sus detalles:

Ya tenemos los contratos publicados. A partir de este momento, publicadores y consumidores pueden desarrollar de forma independiente sus servicios con la garantía de que no habrá problemas de integración.

Como puedes ver en la imagen anterior, en el contrato se incluye tanto las cabeceras, como el payload y como la clave. En nuestro caso, como clave siempre incluimos en identificador de cliente. Aunque pueda parecer redundante incluirlo también en el payload, creemos que es interesante incluirlo porque la key se utiliza principalmente para efectos de particionado y, en un caso real, sería más compleja.

Otra herramienta interesante para publicar los contratos es Event Catalog. No la incluimos en este post debido a que en el momento de creación existe un bug no resuelto a la hora de importar ficheros AsyncAPI con referencias a esquemas Avro.

Conclusión

Espero que os haya gustado el post. Hemos visto cómo aterrizar un caso de uso mediante una orientación a eventos y cómo llegar a diseñar y definir los contratos de los servicios y eventos. Como hemos comentado, este post tiene carácter divulgativo, buscando incluir conceptos relacionados con EDA. Se podría hacer perfectamente con otro tipo de orientación y diseño.

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.

Suscríbete