Ir al contenido principal

Visión general de los patrones de arquitectura de software

Existen muchas definiciones sobre lo que es la arquitectura de software y cuál es la importancia de contar con una buena arquitectura en la construcción de una solución. En este artículo, intentaremos encontrar una definición con la que nos sintamos cómodos, describiremos por qué es importante definir una buena arquitectura y mencionaremos algunas de las arquitecturas más comunes en la actualidad.

En primer lugar, nos gustaría definir qué es la arquitectura de software. Podemos aportar una definición propia o, en su lugar, utilizar alguna de los gurús del mundo IT. La idea más extendida sobre la arquitectura de software es "la definición de todos aquellos componentes que, mediante su interconexión, proporcionan una solución que satisface nuestras necesidades". Si nos fijamos en la definición de Martin Fowler: “Architecture is about the important stuff. Whatever that is”.

Cuando hablamos de arquitectura de software, también debemos referirnos a los arquitectos de software, quiénes son y cuál es su rol en cualquier proyecto. Aunque parezca algo que todos tienen claro, creemos que vale la pena reflexionar sobre ello. Un arquitecto de software define, a alto nivel, los componentes y las tecnologías que se utilizarán en la solución, así como los estándares que se seguirán. Además, profundizando un poco más, diseña la solución y sus interacciones con otros componentes, incidiendo también en los estándares técnicos que se deben seguir, como las herramientas, los estándares de codificación o las plataformas a utilizar.

Para desempeñar este rol, un arquitecto de software necesita las siguientes habilidades técnicas:

  • Extenso conocimiento técnico
  • Habilidades en codificación
  • Conocimiento del negocio

También es necesario que tenga otras habilidades no tan técnicas, tales como:

  • Liderazgo de equipos
  • ComunicaciónResolución de problemas
  • Organización y gestión del tiempo
  • Pensamiento creativo

Estas son pinceladas introductorias sobre la arquitectura de software, que nos llevarán a mencionar los patrones más habituales hoy en día. Además de introducir los diferentes patrones, la idea es indicar cuál sería el uso más adecuado para cada uno de ellos. Así, agruparemos los patrones en dos grandes categorías: arquitecturas monolíticas y arquitecturas distribuidas. Dentro de las monolíticas, discutiremos las arquitecturas por capas (Layered), por canalización (Pipeline) y de microkernel. Y en las distribuidas, hablaremos de las arquitecturas basadas en servicios (Service-Based), orientadas a eventos (Event-Driven), basadas en espacio (Space-Based), orientadas a la orquestación de servicios (Orchestration-Driven Service-Oriented) y de microservicios.

 

Arquitecturas monolíticas
 

Entendemos como arquitecturas monolíticas aquellas cuyos componentes forman una única aplicación, estando fuertemente acoplados. Dentro de este grupo, comentaremos diversas aproximaciones como las arquitecturas por capas, por canalización y de microkernel.

Arquitectura por capas (Layered Architecture)

Es uno de los patrones más comunes y se basa en una separación tanto técnica como lógica de la arquitectura en diferentes capas horizontales. Cada capa debe estar aislada de las demás, y las peticiones solo pueden realizarse de una capa a la siguiente. El esquema más habitual de capas sigue la siguiente estructura:

Su uso se recomienda para aplicaciones pequeñas y simples, donde la facilidad de construcción es prioritaria. Sin embargo, esta simplicidad puede comprometer el mantenimiento, la escalabilidad y las pruebas del sistema. Por eso, para aplicaciones más grandes que requieran mantenimiento constante, se recomiendan arquitecturas más modulares.

 

Arquitectura por canalización (Pipeline Architecture)

Estas arquitecturas funcionan como un canal donde se produce una señal o mensaje que es modificado a través de diferentes filtros, obteniendo finalmente un resultado en la salida. 

Entrando un poco más en detalle de cada uno de los componentes del canal, pueden ser de los siguientes tipos:

  • Producers: Generan los mensajes que se procesan.
  • Consumers: Consumen los mensajes y no tienen canal de salida.
  • Transformers: Modifican los mensajes y escriben los resultados.
  • Testers: Validan los mensajes sin modificarlos, descartando aquellos que no cumplen con lo esperado.

Este tipo de arquitecturas son muy comunes como ETLs, proceso de datos en Stream e incluso en compiladores. Por lo que difícilmente podremos aplicar este tipo de arquitecturas fuera de este ámbito, aunque nos haga entrever un atisbo de lo que serían las arquitecturas de eventos que veremos más adelante. 

 

Arquitectura de microkernel

Las arquitecturas basadas en un microkernel se componen de un pequeño sistema central de la solución y sobre el cual se van añadiendo nuevas funcionalidades sin realizar modificaciones significativas en él. 

Este tipo de arquitecturas son la solución natural para implementar aplicaciones basadas en el producto. Una aplicación de este tipo es aquella que está diseñada para ser entregada en versiones como lo son la mayoría de productos de terceros. En estas aplicaciones, al sistema central se le suelen poder añadir funcionalidades a través de diferentes Plugins. Unos ejemplos muy conocidos de productos basados en esta arquitectura son Eclipse o Visual Studio Code, donde existe un editor básico al que se le pueden añadir nuevas funcionalidades a través de estos plugins.

 

Arquitecturas distribuidas
 

Las arquitecturas distribuidas dividen los procesos entre varios componentes, a menudo en diferentes máquinas, lo que incrementa la tolerancia a fallos, reduce costes, mejora el rendimiento y permite la escalabilidad horizontal. Entre los tipos de arquitecturas distribuidas más comunes, destacamos:

Arquitectura basada en servicios (Service-Based Architecture)

En este enfoque, los componentes se agrupan en servicios. Podríamos considerar que dentro de este tipo de arquitecturas también se encuentran las arquitecturas orientadas a servicios (SOA) y las arquitecturas de microservicios. Ya que el planteamiento principal en todas ellas es distribuir el trabajo en diferentes componentes agrupados por funcionalidades, por dominios o servicios completos. 

Este tipo de arquitecturas, se suelen utilizar como punto de partida en el proceso de descomposición de aplicaciones monolíticas. Ya que este acercamiento nos permitiría definir un único dominio de datos para toda la solución o tener un dominio por servicio. Aunque en este caso, mejoraríamos algunos de los problemas que tienen las aplicaciones monolíticas mejorando la escalabilidad del sistema y la tolerancia a fallos, aún consideraríamos estas soluciones como temporales en el proceso de descomposición de una solución monolítica. Un ejemplo de ello llevándolo al extremo pueden ser las soluciones compuestas por Frontend, Backend y capa de persistencia.

Arquitectura orientada a eventos (Event-Driven Architecture)

Este tipo de arquitecturas son muy populares dentro de las arquitecturas distribuidas ya que son utilizadas para implementar aplicaciones completamente escalables. Esta escalabilidad no impide aplicar este patrón en aplicaciones sencillas, ya que el patrón permite ser aplicado tanto en aplicaciones simples como en las más complejas. Esta arquitectura permite tener un sistema altamente desacoplado, mediante el procesamiento de eventos que son recibidos y procesados de forma asíncrona.

Este tipo de arquitecturas se pueden aplicar tanto en flujos de datos como en el proceso de eventos de negocio. Para ello, se plantean dos topologías principales usando un mediador (mediator) o un broker. Usaríamos la topología con mediador cuando necesitemos orquestar múltiples pasos dentro de un mismo evento a través de un mediador centralizado. Por el contrario, se usaría un broker en el caso de querer encadenar eventos sin el uso de un mediador centralizado. De todas formas, en ambas topologías, existen los mismos tipos de componentes como son productores de eventos, brokers y consumidores de eventos tal y como se muestra en el siguiente diagrama.

Arquitectura basada en espacio (Space-Based Architecture)

Las arquitecturas Space-based, tienen como objetivo minimizar los factores que limitan la escalabilidad de las aplicaciones. El patrón se basa en el concepto de espacio de tupla o en el hecho de disponer de un espacio en memoria distribuido y compartido con todos los componentes de la aplicación. La alta escalabilidad se consigue eliminando la base de datos centralizada y replicando los datos en memoria. Por lo que losndatos son mantenidos en memoria y replicados a través de todos los procesos activos. Lo que permite a los procesos levantarse y detenerse según la carga de trabajo de la aplicación. Con esta aproximación se consigue eliminar casi al completo el cuello de botella que puede darse al tener bases de datos centralizadas. 

Los componentes principales dentro de este patrón son una unidad de procesamiento y un middleware virtualizado.

Dentro de las unidades de procesamiento, puede haber un frontend, un backend, una Base de datos (BBDD) en memoria e incluso un BBDD que permita persistir los datos y un motor de replicación. Este motor de replicación será el encargado de interaccionar con las otras unidades de procesamiento y con el middleware virtualizado.

Este tipo de arquitecturas son complejas y caras de implementar. Es una solución interesante para pequeñas aplicaciones web con una carga variables como pueden ser páginas de redes sociales, subastas y ofertas. Pero no es una buena solución para aplicaciones a gran escala con grandes cantidades de operaciones de datos.

Arquitectura de microservicios

En el caso de las arquitecturas basadas en microservicios, podríamos decir que es una evolución de las arquitecturas orientadas a servicios y las basadas en eventos. Ya que la idea principal es construir una aplicación utilizando piezas lo más
pequeñas posibles que sean totalmente independientes entre ellas. Hasta el punto de que una simple petición de un cliente internamente puede llamar a N microservicios para componer la respuesta.

Las aplicaciones que conforman todos estos microservicios suelen exponer una API para que sea consumida por aplicaciones de terceros y las comunicaciones entre los microservicios pueden realizarse a través de webservices (SOAP, REST, gRPC, etc.…) o utilizando un gestor de mensajes siguiendo el patrón Event-driven. Un ejemplo de una pequeña arquitectura de este tipo lo podemos ver el siguiente esquema.

Conclusiones
 

Al elegir un patrón de arquitectura, siempre deben considerarse factores como el coste de mantenimiento e implementación, las necesidades específicas del cliente, la escalabilidad, y el tipo de aplicación. No existe un patrón que lo resuelva todo, sino varios que ayudarán al arquitecto a encontrar la mejor solución para cada problema. Por eso, es crucial tener una visión amplia de los patrones disponibles y no quedarse siempre con el más popular, como es el caso de las arquitecturas de microservicios.

Autor
 

Omar Martinez Abella

Manager en Deloitte Technology & Transformation

(omartinezabella@deloitte.es)