2. Principios fundamentales de los microservicios

Los microservicios se apoyan en principios que favorecen la evolución continua, la resiliencia y la flexibilidad tecnológica. Comprenderlos con profundidad evita que una arquitectura distribuida se transforme en un monolito fragmentado o imposible de operar. En este capítulo exploramos los pilares que dan sustento a la autonomía, al despliegue descentralizado, a la comunicación desacoplada y a la gestión federada de la información.

2.1 Independencia y autonomía de cada servicio

Un microservicio debe poder tomar decisiones de implementación, almacenamiento y despliegue sin esperar a que el resto del sistema se actualice. Esta autonomía se logra definiendo límites de contexto nítidos, alineando equipos pequeños y manteniendo contratos livianos con sus consumidores.

Las propiedades clave de la autonomía son:

  • Propiedad de dominio: cada equipo controla un subconjunto claro de reglas de negocio y toma decisiones alineadas con las metas del dominio, evitando disputas sobre tablas o componentes compartidos.
  • Stack tecnológico independiente: el servicio puede usar los frameworks, bases de datos o bibliotecas que mejor resuelvan su problema. Esta libertad incrementa la capacidad de innovación, siempre que se respete la compatibilidad con los acuerdos de seguridad y observabilidad institucionales.
  • Ciclo de vida controlado: las versiones se incrementan según el ritmo del equipo. Esto implica que las pruebas, los pipelines de integración y el monitoreo se diseñan para validar y operar al servicio sin mezclarse con el resto del portafolio.

La autonomía también obliga a limitar el tamaño del servicio: debe ser lo suficientemente pequeño como para entenderlo y desplegarlo con rapidez, pero no tan diminuto que su mantenimiento requiera coordinar cambios entre decenas de componentes diferentes para entregar una sola función.

2.2 Despliegue individual y escalabilidad

El segundo principio busca que cada servicio pueda desplegarse sin arrastrar a los demás. El objetivo es liberar nuevas versiones de manera frecuente, incluso varias veces al día, sin programar ventanas de mantenimiento globales ni bloquear a otros equipos.

Las prácticas que habilitan este principio incluyen:

  • Automatización de pipelines: cada repositorio posee un pipeline que compila, prueba y publica imágenes listas para ejecutar o contenedores inmutables.
  • Versionado semántico: se identifica el impacto de los cambios sobre los consumidores, lo que permite mantener compatibilidad o planificar migraciones ordenadas.
  • Escalado independiente: cuando el servicio recibe mayor carga, su cálculo se replica sin afectar el resto de la plataforma. Orquestadores como Kubernetes facilitan esta elasticidad, aunque la disciplina de configuración y monitoreo sigue siendo responsabilidad del equipo propietario.

Escalar de manera localizada reduce costos y limita los riesgos de un cambio de infraestructura global. La clave está en medir el consumo de recursos de cada servicio, detectar cuellos de botella y reforzar el diseño con patrones de resiliencia como replicas activas o colas asíncronas.

2.3 Comunicación mediante interfaces bien definidas

Para que la autonomía no derive en caos, los microservicios deben comunicarse a través de interfaces precisas, documentadas y estables. El intercambio puede ser sincrónico mediante HTTP o gRPC, o bien asíncrono con eventos y colas; en ambos casos la interfaz actúa como contrato que desacopla a los participantes.

Un contrato bien diseñado suele incluir:

  • Modelo de datos claro: los DTO o mensajes contienen solo la información necesaria para la operación. Un exceso de campos filtrados desde la base de datos expone detalles internos y vuelve frágil la evolución.
  • Versionado explícito: cuando cambian los atributos o las rutas se ofrece una versión nueva que convive con la anterior durante un período de transición.
  • Documentación accesible: especificaciones como OpenAPI permiten a los consumidores generar clientes automáticos, validar contratos y realizar pruebas automatizadas.

El respeto por el contrato habilita la evolución independiente: un servicio puede reescribir su lógica interna, cambiar de lenguaje o modificar su esquema de persistencia siempre que mantenga el comportamiento acordado en la interfaz publicada.

2.4 Descentralización del control y los datos

En una arquitectura distribuida el control se reparte entre equipos y servicios. Cada microservicio administra su repositorio de datos, define sus reglas de validación y decide cuándo persistir o descartar información. Evitar bases compartidas impide dependencias ocultas y bloqueos entre equipos.

La descentralización introduce retos adicionales:

  • Consistencia eventual: las actualizaciones se propagan mediante eventos o colas. El sistema acepta que dos servicios pueden ver información desfasada durante unos segundos, priorizando la disponibilidad y el desacople.
  • Gobernanza distribuida: el rol de arquitecto o de plataforma define estándares ligeros (como formatos de logging o directrices de seguridad), pero no impone la implementación detallada de cada servicio.
  • Observabilidad federada: la recopilación de métricas, trazas y logs se centraliza para ofrecer una visión global, aun cuando la ejecución y las decisiones recaigan en cada equipo.

La clave está en encontrar el balance entre libertad y disciplina: los equipos mantienen independencia para evolucionar, pero se coordinan mediante catálogos de contratos, foros de arquitectura y revisiones técnicas transversales.

2.5 Ejemplo práctico de autonomía y contratos

El siguiente fragmento en Java muestra un enfoque de comunicación mixta. El servicio de facturación expone un endpoint REST para registrar una factura y, al mismo tiempo, publica un evento que el servicio de contabilidad consume de manera asíncrona. El contrato se mantiene estable gracias al uso de registros inmutables:

@RestController
@RequestMapping("/api/invoices")
public class InvoiceController {

    private final InvoiceService service;

    public InvoiceController(InvoiceService service) {
        this.service = service;
    }

    @PostMapping
    public ResponseEntity<InvoiceDto> create(@RequestBody CreateInvoiceCommand command) {
        InvoiceDto invoice = service.createInvoice(command);
        URI location = URI.create("/api/invoices/" + invoice.id());
        return ResponseEntity.created(location).body(invoice);
    }
}

@Service
public class InvoiceService {

    private final InvoiceRepository repository;
    private final ApplicationEventPublisher publisher;

    public InvoiceService(InvoiceRepository repository, ApplicationEventPublisher publisher) {
        this.repository = repository;
        this.publisher = publisher;
    }

    public InvoiceDto createInvoice(CreateInvoiceCommand command) {
        Invoice invoice = repository.save(Invoice.from(command));
        publisher.publishEvent(new InvoiceRegisteredEvent(invoice.id(), invoice.total(), invoice.issuedAt()));
        return InvoiceDto.from(invoice);
    }
}

public record InvoiceRegisteredEvent(UUID invoiceId, BigDecimal total, Instant issuedAt) {}

El contrato REST expone un DTO compacto mientras que el evento describe los datos indispensables para la contabilidad. Cada servicio mantiene su propia base y proceso; el acoplamiento se reduce a los contratos publicados, lo que permite evolucionar la lógica interna sin afectar a los consumidores.

2.6 Checklist para evaluar principios fundamentales

Antes de continuar con el siguiente tema conviene validar si cada servicio respeta los principios descritos. A modo de guía, responde estas preguntas:

  • ¿El servicio puede desplegarse, monitorearse y revertirse sin coordinar con otros equipos?
  • ¿Sus contratos están documentados, versionados y cubiertos por pruebas automatizadas?
  • ¿Cuenta con mecanismos para propagar cambios de datos de forma segura y detectar inconsistencias?
  • ¿Dispone de métricas, logs y trazas que permitan diagnosticar fallas sin depender de otros componentes?

Si las respuestas son afirmativas, la arquitectura está construyendo una base sólida para escalar y evolucionar con confianza. De lo contrario, es momento de reforzar los principios antes de incorporar nuevos servicios o patrones más avanzados.