La arquitectura de microservicios consiste en construir una aplicación como un conjunto de servicios pequeños, autónomos y desplegables de forma independiente, cada uno responsable de una capacidad de negocio concreta y comunicándose mediante mecanismos ligeros como APIs HTTP o mensajería. Es uno de los estilos arquitectónicos más populares de la última década, pero también uno de los más malinterpretados: aporta enormes beneficios cuando se aplica con criterio y un coste de complejidad considerable cuando se adopta por moda.
En esta lección definiremos sus características, lo compararemos con el monolito, analizaremos cuándo conviene (y cuándo no) y veremos un ejemplo concreto de descomposición de una aplicación de seguros.
Contenido
- Definición y características
- Microservicios frente a monolito
- El monolito modular como alternativa
- Cuándo SÍ usar microservicios
- Cuándo NO usar microservicios
- Ejemplo de descomposición
- Errores comunes y consejos
- Ejercicios
- Conclusión
- Definición y características
Un microservicio es un servicio que cumple, idealmente, estas características:
- Responsabilidad única de negocio: gestiona una capacidad concreta (pólizas, siniestros, facturación).
- Despliegue independiente: se puede desplegar sin coordinar con el resto.
- Base de datos propia: cada servicio es dueño de sus datos; nadie accede a su base de datos directamente.
- Autonomía de equipo: un equipo lo desarrolla, prueba y opera de principio a fin.
- Comunicación por red: vía API o mensajes, nunca compartiendo memoria.
- Tolerancia a fallos: diseñado para soportar que sus dependencias fallen.
graph TB
subgraph "Aplicación de Seguros"
P[Servicio Pólizas]
S[Servicio Siniestros]
C[Servicio Clientes]
F[Servicio Facturación]
end
P --> DBP[(BD Pólizas)]
S --> DBS[(BD Siniestros)]
C --> DBC[(BD Clientes)]
F --> DBF[(BD Facturación)]Fíjate en que cada servicio tiene su propia base de datos. Este es uno de los principios más importantes: un servicio nunca lee ni escribe en la base de datos de otro. Si necesita datos ajenos, los pide por API o reacciona a eventos.
- Microservicios frente a monolito
Un monolito es una aplicación desplegada como una única unidad. No es intrínsecamente malo; de hecho, suele ser el punto de partida correcto. La comparación honesta es:
| Aspecto | Monolito | Microservicios |
|---|---|---|
| Despliegue | Una unidad | Muchas unidades independientes |
| Escalado | Todo o nada | Por servicio, según necesidad |
| Complejidad operativa | Baja | Alta (red, observabilidad, orquestación) |
| Velocidad inicial | Alta | Baja (mucha infraestructura previa) |
| Aislamiento de fallos | Pobre (un fallo puede tumbar todo) | Bueno (fallos contenidos) |
| Transacciones | ACID locales sencillas | Distribuidas y complejas (sagas) |
| Tecnología | Una pila común | Heterogénea por servicio |
| Autonomía de equipos | Baja (todos tocan lo mismo) | Alta |
| Depuración | Sencilla (un proceso, una traza) | Compleja (trazas distribuidas) |
La conclusión clave: los microservicios cambian complejidad de desarrollo por complejidad operativa. No la eliminan.
- El monolito modular como alternativa
Antes de saltar a microservicios, existe una opción intermedia muy infravalorada: el monolito modular. Se trata de un único desplegable, pero internamente organizado en módulos con fronteras claras y comunicación explícita entre ellos.
// Módulos bien separados dentro de un único desplegable.
// El módulo de siniestros NO accede a las clases internas de pólizas;
// solo usa su API pública (una interfaz).
package com.fiatc.siniestros;
public class ServicioSiniestros {
private final PolizaApi polizaApi; // interfaz pública del módulo Pólizas
public ServicioSiniestros(PolizaApi polizaApi) {
this.polizaApi = polizaApi;
}
public void registrarSiniestro(String polizaId) {
// Consultamos a través de la API pública, no de tablas internas
if (!polizaApi.estaVigente(polizaId)) {
throw new IllegalStateException("La póliza no está vigente");
}
// ... lógica de registro
}
}Este enfoque te da fronteras limpias sin el coste de la red. Si más adelante un módulo necesita escalar o desplegarse por separado, ya está aislado y extraerlo a un microservicio es mucho más fácil. Es la estrategia recomendada para empezar.
- Cuándo SÍ usar microservicios
Los microservicios tienen sentido cuando se cumplen varias de estas condiciones:
- La organización es grande: muchos equipos que se pisan al trabajar sobre el mismo código.
- Necesidades de escalado dispares: el servicio de facturación necesita 20 instancias y el de configuración solo 1.
- Ritmos de cambio distintos: unas partes cambian a diario y otras casi nunca.
- Requisitos de disponibilidad por dominio: aislar un fallo en siniestros para que no tumbe la contratación.
- Madurez en DevOps: existe automatización de CI/CD, contenedores, observabilidad y orquestación.
La famosa "ley de Conway" lo resume: la arquitectura del sistema tiende a reflejar la estructura de comunicación de la organización. Si tienes equipos autónomos, los microservicios encajan.
- Cuándo NO usar microservicios
Evita los microservicios si:
- El equipo es pequeño: la sobrecarga operativa no compensa.
- El dominio no está claro: si aún no entiendes bien las fronteras, las dibujarás mal y pagarás un coste altísimo por corregirlas.
- No hay madurez operativa: sin observabilidad ni automatización, depurar es un infierno.
- Buscas rendimiento extremo en transacciones: las transacciones distribuidas son lentas y complejas.
Un antipatrón habitual es el monolito distribuido: microservicios tan acoplados entre sí que hay que desplegarlos juntos. Reúne lo peor de ambos mundos: la complejidad de la red y la rigidez del monolito.
| Síntoma | Diagnóstico |
|---|---|
| Para desplegar un servicio hay que desplegar otros | Monolito distribuido |
| Un cambio de esquema afecta a varios servicios | Fronteras mal definidas |
| Servicios que comparten base de datos | Acoplamiento de datos |
| Cadenas largas de llamadas síncronas | Acoplamiento temporal |
- Ejemplo de descomposición
Partamos de un monolito de seguros con todo en un solo proceso: clientes, pólizas, siniestros y facturación. Una descomposición razonable, por capacidades de negocio, sería:
# Mapa de servicios resultante
servicios:
- nombre: clientes
responsabilidad: "Datos de contacto y perfil del asegurado"
datos_propios: [cliente, direccion]
- nombre: polizas
responsabilidad: "Contratación y ciclo de vida de pólizas"
datos_propios: [poliza, cobertura]
- nombre: siniestros
responsabilidad: "Apertura y tramitación de siniestros"
datos_propios: [siniestro, peritaje]
- nombre: facturacion
responsabilidad: "Recibos, cobros y devoluciones"
datos_propios: [recibo, cobro]Cada servicio es dueño de sus tablas. ¿Cómo obtiene el servicio de siniestros el nombre del cliente? No accede a la base de datos de clientes; lo pide por API o mantiene una copia local de los pocos datos que necesita, actualizada mediante eventos:
sequenceDiagram
participant CL as Servicio Clientes
participant BUS as Bus de eventos
participant SI as Servicio Siniestros
CL->>BUS: Evento ClienteActualizado
BUS->>SI: ClienteActualizado
Note over SI: Actualiza su copia local<br/>(nombre, NIF anonimizado)Cuando un cliente cambia sus datos, el servicio de clientes publica un evento. El de siniestros mantiene una copia mínima de lo que necesita y la actualiza al recibirlo. Así se evita el acoplamiento directo a la base de datos ajena.
Errores Comunes y Consejos
- Empezar directamente con microservicios: prefiere un monolito modular hasta entender bien el dominio.
- Compartir base de datos entre servicios: rompe la autonomía y crea acoplamiento oculto. Cada servicio, su base de datos.
- Hacer microservicios demasiado pequeños (nanoservicios): generan una explosión de llamadas de red y dificultan razonar sobre el sistema.
- Olvidar la observabilidad: invierte desde el día uno en trazas distribuidas, métricas y logs correlacionados.
- Sincronizar todo: las cadenas largas de llamadas síncronas acoplan disponibilidad. Considera eventos asíncronos.
Ejercicios
- Construye una tabla con tres ventajas y tres inconvenientes de los microservicios frente al monolito, justificando cada punto.
- Una startup de 4 desarrolladores quiere lanzar un MVP en 3 meses. ¿Recomendarías microservicios? Razona tu respuesta y propón una alternativa.
- Dado un monolito de e-commerce con módulos de catálogo, carrito, pedidos y pagos, propón una descomposición en servicios indicando qué datos posee cada uno y cómo obtiene el servicio de pedidos el precio actual de un producto.
Soluciones
-
Ventajas: despliegue independiente (menos coordinación), escalado selectivo (ahorro de recursos), aislamiento de fallos (mayor disponibilidad). Inconvenientes: complejidad operativa (red, orquestación), transacciones distribuidas (sagas), depuración más difícil (trazas distribuidas).
-
No. Con 4 personas y prisa por validar el producto, la sobrecarga operativa de los microservicios retrasaría el MVP. Recomendación: un monolito modular con fronteras limpias, que permita extraer servicios más adelante si el producto crece.
-
Catálogo posee
productoyprecio; carrito poseelinea_carrito; pedidos poseepedidoylinea_pedido; pagos poseetransaccion. El servicio de pedidos obtiene el precio llamando a la API del catálogo en el momento de confirmar el pedido y, muy importante, guarda el precio aplicado en su propia tablalinea_pedido, porque el precio del catálogo puede cambiar después.
Conclusión
Los microservicios son servicios pequeños, autónomos y desplegables de forma independiente, cada uno dueño de sus datos. Cambian complejidad de desarrollo por complejidad operativa, así que solo merecen la pena cuando la organización, el escalado y la madurez técnica lo justifican. En caso de duda, el monolito modular es un excelente punto de partida.
La pregunta más difícil que queda pendiente es dónde trazar las fronteras entre servicios. A ello dedicaremos la siguiente lección, Descomposición de Servicios y Bounded Contexts, donde aplicaremos las ideas del Diseño Guiado por el Dominio para acertar con el tamaño y los límites de cada servicio.
Curso de Arquitectura de Aplicaciones
Módulo 1: Fundamentos de la Arquitectura de Aplicaciones
- ¿Qué es la Arquitectura de Aplicaciones?
- El Rol del Arquitecto de Software
- Atributos de Calidad y Requisitos No Funcionales
- Decisiones Arquitectónicas y Compromisos (Trade-offs)
- Documentación de Arquitectura: Vistas y el Modelo C4
Módulo 2: Principios y Tácticas de Diseño
- Acoplamiento, Cohesión y Separación de Responsabilidades
- Principios SOLID Aplicados a la Arquitectura
- DRY, KISS, YAGNI y Otros Principios de Diseño
- Tácticas Arquitectónicas para los Atributos de Calidad
- Gestión de la Deuda Técnica
Módulo 3: Estilos y Patrones Arquitectónicos
- Arquitectura Monolítica
- Arquitectura en Capas (N-Tier)
- Arquitectura Cliente-Servidor
- Arquitectura Hexagonal (Puertos y Adaptadores)
- Arquitectura Limpia y Cebolla (Clean & Onion)
Módulo 4: Arquitecturas Distribuidas y Microservicios
- Introducción a los Sistemas Distribuidos
- Arquitectura de Microservicios
- Descomposición de Servicios y Bounded Contexts
- API Gateway, Service Discovery y Comunicación entre Servicios
- Patrones de Resiliencia: Circuit Breaker, Retry y Bulkhead
- El Teorema CAP y la Consistencia de Datos
Módulo 5: Arquitecturas Dirigidas por Eventos y Mensajería
- Fundamentos de la Arquitectura Orientada a Eventos
- Mensajería Asíncrona: Colas y Brokers
- Patrones de Eventos: Event Sourcing y CQRS
- Gestión de Transacciones Distribuidas: Patrón Saga
- Streaming de Datos en Tiempo Real
Módulo 6: Diseño Dirigido por el Dominio (DDD)
- Conceptos Fundamentales del DDD
- Diseño Estratégico: Bounded Contexts y Lenguaje Ubicuo
- Diseño Táctico: Entidades, Agregados y Repositorios
- Mapeo de Contextos (Context Mapping)
Módulo 7: Datos y Persistencia
- Estrategias de Persistencia: SQL vs NoSQL
- Patrones de Acceso a Datos: Repository, Unit of Work y DAO
- Base de Datos por Servicio y Gestión de Datos Distribuidos
- Caché y Estrategias de Invalidación
Módulo 8: Arquitectura en la Nube y Despliegue
- Fundamentos del Cloud Computing (IaaS, PaaS, SaaS)
- Contenedores y Orquestación con Docker y Kubernetes
- Arquitectura Serverless
- Patrones de Diseño Cloud-Native
- Infraestructura como Código (IaC)
Módulo 9: Calidad, Seguridad y Observabilidad
- Escalabilidad: Horizontal vs Vertical y Balanceo de Carga
- Alta Disponibilidad y Tolerancia a Fallos
- Seguridad por Diseño y Autenticación/Autorización
- Observabilidad: Logging, Métricas y Trazabilidad
- Rendimiento y Pruebas de Carga
