Table of Contents
Hace relativamente poco he empezado a estudiar estilos de arquitectura de software de diferentes maneras: leyendo libros de arquitectos reconocidos y tratando de ir un paso más allá en mi carrera profesional. He visto lo diferente que es ser un arquitecto a un developer, pese a que ambos roles tienen varios puntos en común, el enfoque es diferente.
En este artículo no pretendo describir lo que significa ser un arquitecto de software. Lo que haré es resumir lo que he estado leyendo y aprendiendo sobre los diferentes estilos de arquitectura de software categorizados como monolíticos o distribuidos.
Monolítica vs. distribuida: definiciones
Cuando hablamos de una arquitectura monolítica o distribuida, nos estamos refiriendo al tipo de despliegue que tiene dicha aplicación, o sea, ¿se debe desplegar la aplicación como un todo, de manera unitaria (monolítica), o desplegamos varios artefactos aislados de manera independiente (distribuida)? Como developer siempre he pensado que una arquitectura distribuida es una solución que llega tras tener una arquitectura monolítica, que con el paso del tiempo y el incremento de los usuarios de la aplicación, tienes la necesidad de aislar ciertas partes de tu código porque hacen colapsar al resto. No estaba desencaminado pero no es la única manera de llegar allí, es más, puede darse el caso en el que debas empezar con algún tipo de arquitectura distribuida por diferentes requisitos como seguridad, elasticidad, temas legales (pe PCI), aunque no es lo habitual.
Estilos de arquitectura de software
Arquitectura monolítica
Este tipo de arquitectura tiene unos beneficios muy importantes sobre todo a la hora de comenzar una aplicación, donde el dominio está en una etapa muy inicial y los “boundaries” entre contextos son muy difusos. Algo importante a tener en cuenta es que independientemente del tiempo que lleve la aplicación en producción, los cambios en el dominio se deben llevar a cabo. No es algo que puedas dejar de lado, debemos actualizar nuestra implementación tan a menudo como sea posible para representar fielmente el dominio, y no hay arquitectura que te salve de esto. El beneficio que te puede dar una arquitectura monolítica es hacer el cambio más rápido.
El beneficio que te puede dar una arquitectura monolítica es hacer el cambio más rápido. Esto no significa que con una arquitectura distribuida no se pueda hacer, aquí estamos hablando del tiempo que lleva y la seguridad a la hora de hacerlo (esto implica coste de desarrollo). A nivel de desarrollo también simplifica mucho en una etapa inicial al solo hablar de un único repositorio en un único lenguaje.
A nivel de despliegue es un poco más complejo. En una etapa temprana de la aplicación, simplificar el despliegue podría ayudarte mucho a hacer foco en dominio. Si introduces microservicios en esta etapa, vas a tener que lidiar no solo con el dominio sino también con toda la infraestructura que esto conlleva. Sin embargo, conforme tu aplicación crece, los despliegues tienden a ser más lentos y espaciados en el tiempo por temas de seguridad. Por ejemplo: en un e-commerce, querer cambiar una pequeña parte de la lista de productos implica un despliegue no solo de esa parte, sino del resto, incluyendo el sistema de checkout u otras partes más vitales, por lo que evitas que algo que da beneficio se rompa por un cambio minúsculo, agrupando varios cambios pequeños en uno mismo en horas donde hay poco tráfico.
A nivel de escalabilidad, opino lo mismo que con el despliegue; en una etapa temprana, escalar todo el proyecto por igual mientras recoges métricas para más adelante poder ver qué parte de tu proyecto necesita escalar más o menos (escalar un monolito tiene sus riesgos pero Stack Overflow ya ha demostrado que es muy viable). Conforme pasa el tiempo, ves que no hace falta escalar todo el proyecto, es probable que la lista de productos sea algo que se visita mucho más que el checkout o la página de perfil del usuario, por lo cual, podríamos valorar algún cambio a la hora de desplegar esta aplicación (o a lo mejor basta con añadir un elastic, quién sabe).
Arquitectura distribuida
Cuando hablamos de una arquitectura distribuida nos referimos a ese tipo de aplicaciones donde los módulos están desplegados de manera independiente, aislados del resto y con una comunicación entre ellos con protocolos de acceso remoto (por ejemplo: http, grpc, colas, etc.).
Son ampliamente conocidos debido a su escalabilidad y disponibilidad, entre otros factores. Performance suele ser uno de sus puntos fuertes, sobre todo dependiendo de la granularidad de los servicios. Además este tipo de arquitectura suele apoyarse mucho en la consistencia eventual, por lo que los eventos son un medio de comunicación muy usado entre servicios. Esto hace que al no esperar una respuesta del servicio al que enviamos un mensaje, procesamos más rápido las requests que recibimos.
El envío de eventos abre un abanico de posibilidades a nivel de comunicación entre servicios, pero eso no quiere decir que no necesitemos transacciones entre servicios, y aquí entra uno de los puntos flacos de las arquitecturas distribuidas: las transacciones distribuidas.
La alternativa a la transacción distribuida son las transacciones ACID, algo imposible de conseguir según como dimensionamos nuestros servicios. En una arquitectura service-based o microservicios donde está más enfocado a dominio (DDD), donde los servicios son más coarse-grained, las transacciones serán ACID (y si no lo son, es muy probable que tengas un problema de diseño). Mientras que en otras arquitecturas, como por ejemplo EDA, las transacciones serán distribuidas y ahí necesitaremos de piezas extras (por ejemplo: SAGA, 2PC), para completar, ya sea de manera satisfactoria o no, dicha transacción. En el caso de que alguna pieza falle, habrá que compensar el resto.
Cuándo usar una arquitectura monolítica o una distribuida
Pese a ser algo que se pregunta mucho, la respuesta siempre va a ser “depende”, ya que cada proyecto tendrá requisitos distintos, y según estos requisitos se tomará una decisión o otra, pero no es una decisión que deba tomarse rápido, requiere de cierto criterio, experiencia y consideración.
Es aquí donde un developer marca la diferencia, y es tener la capacidad de ver el proyecto desde otro punto de vista, una vista mucho más global. Los developers siempre vamos a tender a pensar más en nuestro día a día y no tanto a largo plazo, tomaremos decisiones en base a nuestra experiencia y conocimientos, o por mero aprendizaje, siguiendo las corrientes del hype. Los developers que tienen esa capacidad de cambiar de objetivo para mirar el proyecto tomarán dicha decisión. Definirá las características de la aplicación en base a los requisitos de negocio, sean explícitos (van a salir en un anuncio de la TV), o implícitos (es un e-commerce y sabes de las épocas de rebajas, black friday y demás), valorará las diferentes arquitecturas y sus tradeoffs y decidirá cuál conviene más.
Dicho esto, como ya hemos comentado, las arquitecturas monolíticas suelen ser buenas, entre otros factores, por la facilidad de cambio, y es por eso que es una arquitectura recomendada cuando estás empezando un desarrollo. Esto no implica no desarrollar pensando que en un futuro puedas llegar a aislar ciertos componentes de tu monolito.
Cuando se suele hablar de estilos de arquitectura, se refiere a los top-level styles, o sea, las arquitecturas que definen el primer nivel. Un claro ejemplo vendría a ser el Modular Monolith Architecture, donde en top-level vemos un componente monolítico dividido en módulos separados por dominio pero si hacemos zoom a cada dominio, vemos claramente identificada el Layered Architecture, que vendría a separar las capas por componentes técnicos (presentación, domain, o infraestructura, entre otros)
Monolito o “Big Ball Of Mud”?
Es común encontrarse con proyectos donde se crítica muy duramente a un “monolito”. Cuando profundizas un poco más en el proyecto te das cuenta que las críticas no van hacía al tipo de arquitectura sino a lo que se conoce precisamente como “falta de” arquitectura, conocido como el “Big Ball Of Mud”.
Esto lleva a demonizar una arquitectura, algo que no debería caer en la subjetividad. La decisión de si una arquitectura monolítica es buena o no para el proyecto se debe dar con unos argumentos de peso, sopesando todos los trade offs tanto de la arquitectura descartada como la que se va a introducir.
El hecho de que, subjetivamente hablando, las arquitecturas monolíticas han perdido mucho peso, lleva a reestructuraciones de proyectos completos para salir del big ball of mud a la arquitectura elegida, los microservicios, llevándonos a una nueva arquitectura conocida como la “Distributed Big Ball Of Mud”. Ni cabe decir que habrá equipos dedicados exclusivamente a esto, parando negocio (o intentándolo) mientras se hace dicha reestructuración.
Lejos de solucionar nada, hemos complicado aún más nuestro sistema, haciendo que sea no sólo difícil de modificar, sino que además hemos añadido muchos más puntos de fallo y latencia por el camino. Ah, y un equipo un poco más grande de “DevOps”.
Un enfoque mucho mejor sería atacar el “big ball of mud” de una manera más directa mientras entregamos valor a negocio siguiendo ciertos patrones que nos ayudarán a movernos a otra arquitectura de una manera más sana.
Conclusión
La falta de atención a la arquitectura lleva a muchas empresas a tomar decisiones que no son las mejores, pese a que van a funcionar, no lo harán como deberían. Mark Richards una vez dijo: “There are no wrong answers in architecture, only expensive ones”. Y tiene toda la razón: cuando las decisiones se toman en base a un único problema y no desde un punto de vista global, los resultados no son los esperados, solucionas un problema añadiendo 10 más a la lista.
El proyecto avanzará, la entrega a negocio se irá ralentizando poco a poco provocando fricción entre “equipos” hasta llegar a un punto de no retorno, donde la entrega de valor al proyecto no será asumible y se tendrá que valorar una posible reescritura, con todo lo que ello conlleva.
Estás son algunas de mis conclusiones:
- Tomar decisiones lo más objetivas posibles, en base a métricas, como por ejemplo: la latencia de las respuestas o el throughput si la performance es una característica a tener en cuenta, o el nivel de acoplamiento en base a la instability de nuestro código.
- Leer o escuchar la experiencia de los demás, ya sea mediante libros, artículos o una simple conversación con un compañero.
- Y para mi, lo más importante: ser autocrítico y dejar el ego de lado, lo más probable es que el error no se encuentre en la manera de desplegar nuestro código sino por un mal diseño.
Si quieres aprender más sobre arquitectura de software, no te pierdas el blog de Apiumhub. Podrás encontrar más contenido técnicos sobre arquitectura de software, estilos de arquitectura de software, mejores prácticas y mucho más.
Author
-
Software developer with over 16 years experience working as Fullstack Developer & Backend Developer.
Ver todas las entradas
More to Explore