Para comprender qué son los microservicios, primero debemos discutir los sistemas monolíticos y sus desventajas.
Imagina Amazon como un proyecto de Spring Framework. Consiste en un enorme repositorio de Git, compuesto por clases y componentes como estos:
- Producto
- Inventario
- Catálogo
- Calificación
- Envío
- Pedido
- Pago
- Descuento
- Recomendación
- Lista de deseos
- CompraConUnClic
Pregúntate: ¿qué tiene que ver la funcionalidad de compra con un clic con el envío? La compra con un clic se enfoca en números de tarjeta de crédito e información del usuario, mientras que el envío se ocupa de atributos del producto, como peso, altura y direcciones. De manera similar, la lógica de reembolso no tiene nada que ver con una lista de deseos.
A pesar de que estos componentes son muy distintos entre sí, coexisten en el mismo repositorio, se pueden acceder a través de la misma API, pueden llamarse entre sí y compartir algunas funciones o clases generales.
Están estrechamente acoplados y tienen baja cohesión. Sin embargo, en una arquitectura ideal, preferiríamos un acoplamiento débil y una alta cohesión.
Acoplamiento Débil
Si un proyecto tiene un acoplamiento débil, un cambio en una parte no debería requerir un cambio en otra. Imagina que tienes Producto, Pedido, Descuento y Pago en el mismo proyecto. Al inicio, manejas algunas clases pequeñas y elegantes. El usuario crea un pedido con algunos identificadores de productos, realizas una consulta desde Producto, calculas los precios totales y demás, todo de manera simple. Luego, el negocio desea agregar descuentos. Entonces llamas al componente Descuento desde Pedido, pasando los productos. Todo sigue simple. Un día, el negocio desea un descuento basado en el monto total de los pedidos. Sin problemas, simplemente pasas el objeto Pedido a Descuento. Después, necesitas otorgar un descuento basado en el historial de pedidos y pagos del usuario, por lo que pasas más pedidos y el objeto Usuario a Descuento. Quizás también quieras obtener algo del módulo de Pago.
Este enfoque reduce la probabilidad de efectos secundarios no deseados cuando se realizan cambios o se añaden nuevas funcionalidades, promoviendo una arquitectura más sostenible y fácil de mantener. Con un acoplamiento débil, cada módulo funciona de manera independiente, pero puede interactuar con otros cuando es necesario sin causar interrupciones o errores en otras áreas del sistema.
El Problema de los Sistemas Estrechamente Acoplados
Aunque hemos discutido las ventajas del acoplamiento débil, la realidad en muchos sistemas es que están estrechamente acoplados. Imagina ahora que en tu sistema, tienes una interacción compleja entre Pedido, Descuento, Producto, Pago, Historial de Pedidos y Usuario. En este escenario, un cambio aparentemente inocuo puede tener consecuencias inesperadas:
- Modificas la función getNetPrice() en la clase Producto, y repentinamente la llamada a la API de Descuento devuelve un código de estado 500.
- Cambias algo en la clase Usuario y Pedido comienza a comportarse de manera diferente.
- Ajustas algo en Historial de Pedidos y obtienes los descuentos incorrectos.
Así llegamos al monolito estrechamente acoplado, donde un cambio en algún lugar a menudo rompe la aplicación en otro lugar, frecuentemente en un lugar completamente no relacionado. Este es el problema de los monolitos.
Alta Cohesión
Alta cohesión significa que el comportamiento relacionado se encuentra en un solo lugar, y el comportamiento no relacionado en otro diferente. Por ejemplo, en la clase Pedido, no querrías un método llamado getProductPrice(); eso pertenecería a la clase Producto. Mantener una alta cohesión ayuda a asegurar que, si deseas cambiar algún comportamiento, no afectes accidentalmente otras áreas del sistema. Esto facilita realizar cambios más seguros y robustos.
En el mundo de los monolitos, es muy fácil crear un alto acoplamiento y baja cohesión debido a la tendencia de agrupar muchas funciones diferentes en el mismo lugar. A medida que aumenta el número de características, clases, métodos y desarrolladores, se vuelve demasiado fácil cometer errores.
Aun cuando es posible escribir buenos monolitos de alta calidad, cada sistema, sin importar cuán bien esté hecho, tiende a enfrentar algunos problemas de acoplamiento y cohesión.
¿Qué son los microservicios?
Imagina un restaurante donde el camarero utiliza una aplicación móvil para tomar tu pedido. Él toma tu pedido, y el chef recibe la información sobre lo que debe cocinar. Cuando el chef termina, el camarero entrega tu comida, luego tú la consumes. Después, el camarero imprime tu recibo a través de la aplicación móvil. Al final del día, el gerente abre el mismo sistema en su portátil y revisa los ingresos, el ingreso neto, el costo de ingresos y finaliza el día. Cada viernes va a su supermercado favorito y compra algunos elementos del menú. Luego los registra en el sistema. Al final de cada mes, descarga un archivo de Excel sobre las finanzas y lo envía por correo electrónico al contable.
Componentes en este ejemplo de microservicios
En este dominio, tenemos componentes como:
- Producto
- Grupo de Productos
- Elemento del Menú
- Pedido
- Ítem de Pedido
- Recibo
- Descuento
- Finanzas
- Almacenamiento
- Compra
Primero, intentemos crear algunos grupos con estos componentes. En cada grupo, colocamos componentes similares, que están relacionados entre sí:
Grupos:
- Gestión de Productos
- Gestión de Pedidos
- Gestión de Inventario
- Gestión de Descuentos
- Finanzas
Así agrupamos los componentes según su funcionalidad. En nuestra aplicación, tenemos responsabilidades como:
Gestión de Productos
- Hace un seguimiento de nuestros productos y sus grupos
- Almacenamiento
Gestión de Pedidos
- Almacena los pedidos de los clientes
Gestión de Inventario
- Gestiona elementos del menú y otros productos
- Compras
Gestión de Descuentos
- Maneja tarjetas de descuento y demás
Finanzas
- Crea informes sobre el negocio
Ahora, coloquemos cada componente en un grupo:
Gestión de Productos
- Grupo de Productos
- Producto
Gestión de Pedidos
- Pedido
- Ítem de Pedido
- Recibo
Gestión de Inventario
- Elemento del Menú
- Almacenamiento
- Compra
Gestión de Descuentos
- Tarjeta de Descuento
Finanzas
- Informe de Ingresos
- Informe de Costo de Ingresos
En una aplicación monolítica clásica, creas un repositorio y pones todos los componentes en él. Pero en el mundo de los microservicios, creamos un proyecto separado para cada espacio de nombres.

¿Qué es exactamente un servicio?
Un servicio es básicamente una pequeña aplicación que funciona por sí misma y tiene su propia forma de comunicarse con otras aplicaciones o servicios. Imagina que divides una gran aplicación, como un programa de gestión de un restaurante, en partes más pequeñas y manejables, donde cada parte maneja una tarea específica. Por ejemplo, una parte maneja sólo los pedidos, otra sólo las reservaciones, etc. Cada una de estas partes es un servicio.
Estos servicios no son simplemente partes de un programa más grande, son aplicaciones completas. Puedes empezar a usarlas, actualizarlas o detenerlas sin afectar a las demás. Además, cada una tiene su propia conexión al mundo exterior a través de lo que llamamos una “API”, que es como un lenguaje común que permite que diferentes programas hablen entre sí.
¿Qué hace “micro” a un microservicio?
En el desarrollo de programas, generalmente preferimos que las cosas sean lo más simples y pequeñas posible porque son más fáciles de manejar y mantener. Esto también se aplica a los servicios. Un “microservicio” es tan pequeño que un equipo pequeño puede rehacerlo completamente en unas pocas semanas si es necesario, lo cual es útil si queremos mejorar algo rápidamente sin interferir con el resto de la aplicación.
La idea es que cada microservicio sea independiente, así que si necesitas hacer cambios en uno, no tienes que preocuparte por romper otro. Esta forma de organizar las cosas viene recomendada en un libro famoso sobre el tema llamado “Building Microservices”, escrito por Sam Newman.
Ahora, supongamos que creamos cuatro microservicios diferentes para manejar diferentes partes de nuestra aplicación de restaurante. La siguiente pregunta natural es: ¿cómo interactúan entre sí? Por ejemplo, ¿cómo sabe el servicio de Finanzas cuánto dinero ha hecho el restaurante si es el servicio de Pedidos el que tiene esa información? En el siguiente posts, explicaré cómo se comunican estos servicios y cómo se aseguran de trabajar juntos de manera efectiva, pero primero, vamos a entender un poco más sobre cómo se organizan.
Encontrando el contexto delimitado
En las secciones anteriores, hablamos sobre cómo agrupar clases. Pero en el mundo real, a estos grupos los llamamos “contextos delimitados”. Esta expresión proviene del libro de Eric Evans, “Diseño Guiado por el Dominio”. Cada producto tiene su propio dominio y lenguaje, similar al que utilizamos en el ejemplo del restaurante. Cada dominio contiene varios modelos, y siempre es posible identificar un conjunto de modelos que pueden agruparse y alrededor de los cuales podemos trazar un límite. Este límite indica que estos modelos pueden funcionar juntos sin necesidad de depender de elementos externos.
En cada contexto delimitado, existen detalles de implementación internos y modelos internos que no deseamos exponer al mundo exterior. Sin embargo, también hay modelos compartidos que sí pueden ser expuestos externamente. Este es un concepto crucial. Significa que, por ejemplo, no querrías exponer todos tus componentes de Java del servicio de Productos. Prefieres mantener estos componentes dentro del servicio de productos porque contienen muchos detalles específicos de cómo funciona el servicio y deseas crear una versión más simplificada y transformada para uso externo. Profundizaremos más en este tema más adelante en este libro. Por ahora, puedes imaginar algo así:

Microservicios con Spring Boot
En la arquitectura de microservicios que estamos utilizando, el Servicio de Catálogo administra componentes internos, como ProductGroup y Product, encapsulados en un contorno rojo para indicar su uso exclusivo dentro de este servicio.
El modelo compartido, llamado Shared Product Model, es un componente externo, representado en color verde. Este modelo es utilizado para compartir información esencial de los productos con otros servicios, facilitando así la integración entre diferentes partes de la aplicación sin exponer los detalles internos del servicio de catálogo. Como puede observarse, este modelo se comparte con el Servicio de Pedidos, permitiendo una interacción eficiente entre los servicios.
El Servicio de Pedidos, también en color rojo, utiliza el Shared Product Model para acceder a los datos necesarios del producto que necesita para procesar pedidos, gestionar los ítems de los pedidos y generar los recibos. Este servicio gestiona entidades como Order, OrderItem y Receipt, que son específicas de su dominio y no están expuestas más allá de sus límites.
Identificar correctamente el contexto delimitado es esencial en el diseño de microservicios, y es una habilidad crucial en su implementación efectiva. Esta delimitación adecuada facilita la mantenibilidad, escalabilidad y seguridad de las aplicaciones, permitiendo que cada servicio se mantenga enfocado en su funcionalidad principal sin incurrir en dependencias complicadas con otros servicios.
La ventaja significativa de los microservicios es la modularidad y el aislamiento que permiten a los equipos trabajar de manera más independiente y eficiente, optimizando la gestión de cada parte de la aplicación como un módulo separado.
Conclusión
Adoptar microservicios con Spring Framework permite superar los problemas inherentes a los sistemas monolíticos, como la dificultad en mantenimiento y escalabilidad. Utilizando Spring, las aplicaciones se dividen en servicios más pequeños y manejables, cada uno operando dentro de su propio contexto delimitado. Esto promueve un desarrollo, despliegue y escalado más ágil y específico para cada servicio. Además, el uso de modelos compartidos facilita la integración entre servicios sin exponer detalles internos. En resumen, los microservicios con Spring Framework ofrecen una solución robusta y flexible para desarrollar aplicaciones modernas, superando los desafíos de los sistemas monolíticos y preparando a las empresas para un futuro escalable y eficiente.
Referencia
- Newman, S. (2021). Building Microservices, 2nd Edition. O’Reilly Media, Inc.
- Carnell, J. (2021). Spring Microservices in Action. Manning.
- Evans, Eric (2004). Domain-Driven Design: Tackling Complexity in the Heart of Software. Addison-Wesley



