Sobre eventos y orquestación de componentes
Un artículo de Rafa G. Blanes
Los que hayan leído mi último libro ("El Arte del Emprendedor Digital"), habrán comprobado por qué es una buena estrategia desglosar la arquitectura de un proyecto software en componentes (sobre todo si el proyecto es de tamaño medio o grande y va a evolucionar mucho). De este modo (y sin entrar en demasiado detalle), la funcionalidad del sistema está ordenada en responsabilidades independientes, fácilmente localizable y modificable.
La clave está en que cada componente (llámalo módulo si quieres), sea pequeño, se encargue de algo muy concreto y específico, y que cuando haya que afrontar una funcionalidad más amplia, se pueda distribuir ésta en varios componentes que se hablan entre ellos. ¿Cómo? Pues según la tecnología y el framework de trabajo que se haya utilizado para implementar este esquema.
Hub de Libros cuenta ahora mismo con más de ochenta componentes, mientras que un proyecto sencillo en el que he trabajado recientemente, tiene ya unos treinta (muchos de ellos reutilizados de otros proyectos).
Puede parecer que se desmadra un poco la cosa cuando hablamos de decenas de módulos independientes, aunque quizá solo los que (como yo) hayan sufrido en alguna ocasión una solución monolítica con mucha funcionalidad (cientos de miles de líneas de código), podrán comprobar las bondades de esta arquitectura. En otro proyecto diferente que he dirigido en Solid Stack, actualmente cuenta ya con más de cien (y subiendo).
Si te enfrentas a un proyecto con cientos de kloc (1 kloc = mil líneas de código) y en él no hueles nada a componente o módulos independientes, malo.
Ahora bien, en todo sistema grande existe funcionalidad de alto nivel que afecta o utiliza un conjunto de funcionalidades de bajo nivel. Tenemos siempre la tentación de implementarla directamente y por separado, y aunque esté encapsulada en su propio componente, finalmente lo que tenemos es, de nuevo, un componente grande y monolítico, más difícil de cambiar, de probar y de evolucionar, y que es justo lo que queremos evitar.
Existe otro enfoque para implementar esa funcionalidad de mayor nivel basado en eventos, esto es, cuando ocurre algo en el sistema, un componente hace algo en concreto y simple, tan solo emite el evento correspondiente por si hay otra parte del sistema que necesita saber que ese evento se ha producido. La gestión de ese evento ni siquiera se tiene que producir en la misma aplicación, sino que pueden existir auténticas infraestructuras software para gestionar eventos en aplicaciones independientes. Redis, sin ir más lejos, permite un esquema de suscripción/publicación que facilita esa comunicación entre procesos para casos en los que hay que gestionar cientos o miles de eventos por segundo.
Por poner un ejemplo, si cuando un usuario se loguea en el sistema hay que guardar cierta información en el log de actividad, o lanzar un informe para su panel de control personalizado o cualquier otra cosa, todo eso no se debe implementar en el mismo componente que se encarga de la seguridad de los usuarios, éste tan solo emite un evento de tipo "users.userloggedin" (es tan solo un nombre descriptivo), y algo en alguna parte del sistema se encargará de realizar lo que haya que hacer cuando eso ocurre.
De este modo, existen componentes base que implementan funcionalidades muy canónicas, pero también, y como parte de una arquitectura bien estructurada en responsabilidades, existen otros componentes que se encargan de implementar funcionalidad de más alto nivel que afecta a grupos de componentes. ¿Cómo? Gestionando eventos y orquestando la funcionalidad de diversos componentes del primer tipo.
Rara es la funcionalidad de alto nivel que no se pueda implementar de este modo. En ocasiones, toda esa funcionalidad de ese tipo, se incluye en lo que se denomina capa de integración, e incluso se implementa bajo el concepto de flujo de trabajo o proceso de negocio.
La gestión de esos eventos no tiene por qué ser siempre síncrona (retrasando quizá la interacción del usuario con el sistema), sino que se puede plantear hacerla en segundo plano.
Con esta estrategia, todo sigue encapsulado en componentes sencillos, mientras que aquellos que se encargan de integrar funcionalidad más compleja tan solo orquestan los primeros, manteniendo incluso una implementación sencilla: ante el evento tal, hago esto y después lo otro.
Sin duda, la gestión de eventos y su orquestación son herramientas fundamentales para implementar sistemas software grandes.