Table of Contents
El año pasado, Apiumhub organizó el Global Software Architecture Summit, un evento de 2 días que se centró en las métricas de arquitectura de software. Durante este evento, tuve la oportunidad de asistir a la charla «Understanding the Differences Between Modularity and Granularity» de Mark Richards, un experimentado arquitecto de software práctico y coautor de los libros «Fundamentals of Software Architecture» y «Software Architecture: The Hard Parts». En esta presentación, Mark explicó cómo la modularidad y la granularidad pueden ser útiles para decidir cómo puede evolucionar una aplicación, dividiéndola en diferentes servicios o agrupándolos de nuevo.
Para entender mejor de qué estamos hablando, entendamos primero la definición de los términos modularidad y granularidad (del libro Software Architecture: The Hard Parts de los mismos Richards, Neal Ford, Pramod Sadalage y Zhamak Dehghani):
La modularidad consiste en dividir los sistemas en partes separadas.
La granularidad tiene que ver con el tamaño de esas partes separadas.
Curiosamente, la mayoría de los problemas y retos de los sistemas distribuidos no suelen estar relacionados con la modularidad, sino con la granularidad.
Repaso de la charla sobre las diferencias entre modularidad y granularidad
Modularidad de la arquitectura
¿Por qué debería considerar la posibilidad de dividir mi aplicación en componentes distribuidos más pequeños?
En el desarrollo de software, algunas decisiones se toman basándose en opiniones y no en criterios objetivos. No debe tomarse en función del tema de moda, sino en función de las necesidades reales.
Puede ser una buena justificación para dividir la aplicación monolítica cuando su sistema debe seguir algunos ‘ilities’ como:
- Mantenibilidad
- Testabilidad
- Capacidad de despliegue
- Escalabilidad
- Tolerancia a fallos
¿Cómo debo dividir mi aplicación monolítica en partes más pequeñas?
Una vez que el equipo ha decidido que la descomposición está justificada y es factible, tiene que comprobar cuál es la mejor manera de llevarla a cabo. Dependiendo de si el proyecto se encuentra en un estado maduro, en el que los distintos componentes del sistema son definibles, podríamos optar por una descomposición basada en componentes. Por el contrario, si se encuentra en un estado más caótico, la bifurcación táctica puede ser un mejor enfoque.
a) Descomposición por componentes
- Aplicación monolítica
- Identificar y dimensionar los componentes
- Reunir componentes comunes
- Aplanar componentes
- Analizar las dependencias de los componentes
- Crear dominios de componentes
- Crear servicios de dominio
- Separarse aún más
Una vez identificados, clasificados, agrupados o separados los componentes en diferentes preocupaciones, surgirán diferentes servicios de dominio y podrán surgir diferentes microservicios.
Encontrarás una descripción detallada en el libro mencionado al comienzo de este artículo
b) Bifurcación táctica
Cuando el proyecto no tenga los módulos tan claros, no intentes ampliar el nuevo servicio. Probablemente será doloroso y lleno de errores. En su lugar, hay que replicar todo el proyecto y desplegarlo dos veces. A partir de aquí, cada aplicación seguirá su propio camino y evolucionará como un proyecto diferente. Cualquier código de la otra aplicación puede eliminarse sin ningún problema. A la larga, aparecerán aplicaciones diferentes.
Granularidad del servicio
¿Cuál es el nivel de granularidad adecuado para un servicio?
Mark Richards preguntó al público cómo dividiríamos un servicio con diferentes responsabilidades. Algunas manos se alzaron para elegir una opción, otras para la segunda. Y la mejor respuesta fue «depende». Depende de cada aplicación y de su uso. Una vez más, tenemos que tomar decisiones basadas en algunos datos, no en lo que podamos pensar.
Desintegradores de granularidad
¿Cuándo debo considerar la posibilidad de separar un servicio?
Consideremos un servicio de notificación típico, que incluye diferentes formas de enviar una notificación. Mediante texto SMS, correo electrónico y carta postal.
1.- Funcionalidad del servicio
Podemos dividir el servicio único en tres servicios, siguiendo el principio de responsabilidad única: servicio de SMS, servicio de correo electrónico y servicio de cartas.
2.- Volatilidad del código
Pudimos comprobar que algunas partes del código cambiaban más rápido que otras. Por ejemplo, el texto SMS y la carta postal tienen unos protocolos bien estandarizados, y el código rara vez se modifica. Pero el servicio de correo electrónico ha cambiado mucho recientemente debido a algunos cambios en los proveedores,… En este caso, puede ser correcto dividir en dos los servicios: El texto SMS y la carta postal, que se mantienen en el TraditionalService, y el correo electrónico en el Servicio de Notificación Electrónica.
3.- Escalabilidad y rendimiento
¿Todas las partes del código tienen la misma escala? ¿Tienen la misma solicitud de salida? En nuestro servicio, vemos que se envía una carta postal cada minuto, 500 correos electrónicos cada minuto y miles de SMS. Basándonos en esos datos, puede que necesitemos dividir los servicios para que cada uno pueda escalarse de formas distintas. Puede que no necesitemos escalar el servicio postal en absoluto, pero el servicio de SMS debe escalarse para hacer frente a todo el tráfico.
4.- Tolerancia a fallos
Algunas áreas son más propensas a errores que otras y pueden afectar a otros servicios. Por ejemplo, en nuestro caso, el servicio de correo electrónico trabaja con un proveedor que falla de vez en cuando. Si ese proveedor falla, todas las notificaciones podrían verse afectadas también. Parece una buena idea dividir el servicio de correo electrónico en su propio servicio para que el resto de la aplicación funcione sin problemas.
5.- Restricción de acceso
No todo el código necesita las mismas restricciones en materia de seguridad. Algunas partes deben tratarse con mucho cuidado. Por ejemplo, si tenemos un servicio Perfil en el que gestionamos los datos del perfil y los de la tarjeta de crédito, puede ser un buen principio dividirlo en servicios Perfil y Cartera, donde el servicio Cartera tenga algunas restricciones a la hora de acceder a sus datos.
Integradores de granularidad
¿Cuándo debería plantearme volver a montar los servicios?
1.- Transacciones en la base de datos
Una de las grandes dificultades es la gestión de transacciones de base de datos entre diferentes microservicios. Por ejemplo, al crear un nuevo usuario, si mantenemos el servicio de perfil en un microservicio, y la información de seguridad en otro, no hay transacción ácida (db) posible. Ese puede ser un buen momento para unir estos dos servicios.
2.- Dependencia de los datos
Cuando el servicio A necesita datos del servicio C, el servicio B de A, y el servicio C de A y B, algo nos está diciendo que esos tres servicios podrían pegarse.
3-. Flujo de trabajo y coreografía
A partir de un servicio monolítico, creamos varios microservicios.
Antes, el tiempo de respuesta era aceptable. Ahora la capacidad de respuesta y el rendimiento son mucho peores porque tenemos que sumar el tiempo de todas las llamadas entre microservicios.
Además, la fiabilidad y la coherencia de los datos son mucho más complicadas. Si un microservicio falla, el cliente recibe un error. Si ese es el caso, tienes que plantearte volver a los monolitos.
Conclusión
Esta charla de Mark Richards que invitó a la reflexión sobre un tema que a veces no se tiene bien en cuenta. En arquitectura de software, como se suele decir, no hay una bala de plata y para cada caso hay que recoger y analizar puntos y datos objetivos. La respuesta favorita del señor Richards a la mayoría de las preguntas es «Depende», porque es una realidad. Cada situación tiene una solución conveniente. En esta charla, Richards resumió algunos puntos para decidir cuándo unir o cuándo separar un servicio, basándose en conocimientos reales.
Si deseas ver otras charlas de la pasada edición de GSAS, puedes dirigirte al canal de YouTube de Apiumhub.
Las entradas para la tercera edición del GSAS ya están disponibles en el sitio web del evento. El evento de este año tendrá lugar del 9 al 11 de octubre en el Auditorio AXA de Barcelona. Se centrará en las prácticas modernas en arquitectura de software: cómo ser más eficaz, eficiente y disfrutar de lo que haces. Utiliza el código apiumhub-community para disfrutar de un 30% de descuento en tus entradas por formar parte de nuestra comunidad.
Author
-
Experienced Full Stack Engineer with a demonstrated history of working in the information technology and services industry. Skilled in PHP, Spring Boot, Java, Kotlin, Domain-Driven Design (DDD), TDD and Front-end Development. Strong engineering professional with a Engineer's degree focused in Computer Engineering from Universitat Oberta de Catalunya (UOC).
Ver todas las entradas