Pular para conteúdo

Microsserviços

Histórico: de monólitos a SOA, e de SOA a microsserviços

Definição: SOA (Service Oriented Architecture)

Estilo arquitetural que, em meados da década de 1990, propôs quebrar uma aplicação monolítica em serviços desacoplados, integrados por interfaces bem definidas e reutilizáveis — evitando integrações ponto a ponto difíceis de manter. O padrão técnico mais comum da época era SOAP em conjunto com WSDL (Web Service Definition Language), rodando sobre HTTP — o equivalente ao Nível 0 (The Swamp of POX) do modelo de maturidade REST.

flowchart LR
    subgraph Monolito["Monólito"]
        M["Uma única aplicação"]
    end
    subgraph SOA
        S1["Aplicação<br/>de Catálogo"]
        S2["Aplicação<br/>de Pedidos"]
        S3["..."]
    end
    subgraph Microsservicos["Microsserviços"]
        MS1["Produtos"]
        MS2["Estoque"]
        MS3["Mídia"]
        MS4["..."]
    end
    Monolito -->|Desacopla módulos<br/>em aplicações| SOA
    SOA -->|Especializa cada aplicação<br/>em serviços mais finos| Microsservicos

Definição: Microsserviços como evolução da SOA

A arquitetura de microsserviços manteve os conceitos fundamentais da SOA, mas foi além ao definir o tamanho ideal da unidade de software: em vez de uma aplicação por módulo de negócio, cada microsserviço deveria representar um único contexto de negócio, coeso e de baixo acoplamento — a mesma especialização que o SRP do SOLID já defendia na escala de classes, agora aplicada na escala de serviços inteiros.

Um exemplo prático dessa evolução: um módulo de "Catálogo" (que, dentro de um monólito de e-commerce, cuida de nome, descrição, preço, estoque e mídia de produtos ao mesmo tempo) fere o SRP ao concentrar vários domínios de negócio distintos no mesmo serviço. A especialização em microsserviços separaria essas responsabilidades em serviços próprios — Produtos (ciclo de vida do produto), Estoque (disponibilidade e movimentações) e Mídia (imagens e vídeos vinculados) — cada um coeso, autônomo e com baixo acoplamento entre si.

Integração de sistemas na Web: SOAP, SOA e REST

Sistemas isolados envelhecem mal: o mercado caminha para muitos sistemas pequenos que se integram. A integração pela Web usa HTTP (porta 80/443 aceita por firewalls e suportada por infinitas ferramentas) e passou por três grandes gerações:

Geração Ideia Característica
POX / XML-RPC XML "puro" sobre HTTP, com chamadas de método Simples; cada sistema inventa seu formato
SOAP + WSDL Contrato formal (WSDL descreve operações, tipos e endpoints), mensagens em envelopes XML Padronizado e rígido; gera dezenas de classes por stubs; HTTP usado só como "túnel"
REST / JSON Recursos com URIs, verbos HTTP e representações (JSON/XML) Leve, aproveita o HTTP, melhor para evoluir

Contratos rígidos x acoplamento

O WSDL dá segurança (tudo é descrito e validável), mas acopla cliente e servidor a uma estrutura completa: um campo novo ou uma operação alterada exige reanalisar o WSDL e regenerar classes. A versão 1.2 do SOAP se aproximou do HTTP (por exemplo, aceitando o GET), mas o modelo de "tudo é um método remoto" permaneceu. A lição vale para qualquer integração: quanto mais genérico o cliente, menos manutenção.

  • Validar só o que se usa: o consumidor valida apenas os campos de que precisa e ignora o resto, em vez de rejeitar o documento inteiro por um campo novo (padrão Must Ignore / tolerant reader).
  • Produzir conforme o contrato: quem envia segue o esquema à risca.
  • Valores padrão para campos novos ausentes em versões antigas.
  • Janela de compatibilidade: o servidor se compromete a manter a versão antiga por um prazo (ex.: dois anos), avisa a depreciação e depois remove (Compatibilidade e evolução de contratos).

Princípios do SOA

Definição: SOA (princípios)

O SOA Manifesto define SOA como um estilo arquitetural independente de tecnologia: dá para implementá-lo com SOAP, REST, mensageria ou até CORBA. O que importa são os princípios, não o protocolo.

Princípio Significa
Granularidade adequada e reúso Serviços com tamanho que permita vários clientes e a composição de novos serviços a partir dos existentes
Contrato formal e descoberta O serviço é descrito (WSDL, OpenAPI) e localizável
Abstração da implementação O cliente não conhece linguagem, banco nem detalhes internos
Baixo acoplamento Cliente e serviço evoluem de forma independente
Composição e orquestração Processos de negócio combinam serviços (BPEL; hoje Sagas e workflows)
Autonomia e governança Cada serviço controla seus dados; regras comuns de segurança, versionamento e monitoramento

Os microsserviços herdam esses princípios e restringem o tamanho ao contexto de negócio (acima).

REST e hipermídia (ROA)

REST organiza a integração em recursos identificados por URIs e manipulados por representações (HTML, XML, JSON). A arquitetura orientada a recursos (ROA) destaca:

  • Hipermídia como controle: a resposta traz links (rel="pagamentos") que dizem ao cliente o que ele pode fazer em seguida, em vez de o cliente conhecer todas as URIs de antemão (early binding). O servidor pode mudar URIs sem quebrar quem segue os links, e o fluxo do processo pode ser distribuído entre vários serviços (HATEOAS).
  • Relações (rel) com nome único (URI própria ou valor registrado no IANA) evitam ambiguidade.
  • Media types declaram formato e semântica no cabeçalho (Content-Type, Accept); o servidor responde 406 ou 415 quando não consegue atender.
  • Códigos HTTP descrevem o resultado (200, 201, 400, 404, 409...) em vez de códigos próprios no corpo.
  • URI templates (/clientes/{id}) documentam padrões de URI; no Java, a especificação JAX-RS (e o Spring MVC) mapeia métodos a esses recursos.

Comparado ao SOAP, REST reduz o acoplamento, mas exige disciplina de contrato (OpenAPI) e de versionamento.

Por que os microsserviços surgiram

Microsserviços não nasceram de uma preferência técnica abstrata — surgiram como resposta a um problema concreto de escala organizacional. Com a abundância de capital de investimento disponível para empresas de tecnologia (impulsionada pelo crescimento do mercado de Venture Capital), grandes empresas passaram a construir serviços cada vez maiores, e isso demandava times cada vez maiores para mantê-los.

Definição: Regra das duas pizzas

Heurística (popularizada pela Amazon) de que um time de desenvolvimento não deveria ser maior do que o número de pessoas que duas pizzas conseguem alimentar — em geral, algo entre 6 e 10 pessoas. Times maiores que isso tendem a gastar mais energia em coordenação (reuniões, alinhamento) do que em entrega — a comunicação cresce mais rápido que a produtividade.

Ao limitar o tamanho de cada time, uma aplicação monolítica grande demais para um time pequeno cuidar sozinho passou a precisar ser dividida — cada serviço menor sob responsabilidade de um time dentro do limite das duas pizzas. Essa divisão é a origem prática dos microsserviços: não uma escolha arquitetural isolada, mas uma consequência de como organizar o trabalho de várias equipes pequenas numa aplicação grande.

Definição: O custo dos microsserviços

Dividir um sistema em serviços menores resolve o problema de escala de time, mas introduz um custo novo: cada serviço agora precisa se comunicar com outros serviços através da rede (ver HTTP), em vez de uma simples chamada de método dentro do mesmo processo. Isso multiplica o número de interações do sistema, cada uma sujeita a latência de rede e falha parcial — foi dessa complexidade nova que nasceu toda uma área de padrões próprios de sistemas distribuídos (circuit breaker, service discovery, API Gateway, entre outros), necessários justamente para lidar com o que a divisão em microsserviços passou a exigir.

Benefícios e desafios

Nem sempre microsserviços são a melhor opção para um projeto — não são "balas de prata". Uma pesquisa da IBM com mais de 1.200 desenvolvedores e executivos apontou que 87% dos usuários sentiram que a implementação da arquitetura foi benéfica economicamente, mas os desafios também são reais e precisam ser avaliados.

Categoria Aspecto Descrição resumida
Benefício Independência Isolamento entre microsserviços evita impactos e facilita manutenção
Benefício Autonomia de equipes Equipes pequenas podem cuidar de um microsserviço específico com mais domínio e agilidade
Benefício Curva de aprendizado Escopos menores são mais fáceis de entender para novos desenvolvedores
Benefício Eficiência tecnológica Uso de linguagens, bancos e ferramentas mais adequadas a cada microsserviço
Benefício Escalabilidade pontual Permite escalar apenas os microsserviços com maior demanda
Benefício Manutenção facilitada Alta coesão e baixo acoplamento tornam mudanças mais simples
Desafio Migração do monólito Transição direta é arriscada; o ideal é migrar gradualmente
Desafio Complexidade de integração Múltiplas dependências e risco de quebra entre microsserviços
Desafio Testes e validação Alta necessidade de automação para garantir estabilidade
Desafio Monitoramento e logs Exige centralização e rastreamento com identificadores únicos
Desafio Depuração Depuração local limitada; demanda uso de mocks e automações

Definição: Depuração (debugging) distribuída

Depurar remotamente um ambiente de IDE local não é viável (e não funciona) com dezenas ou centenas de microsserviços — não existe, até hoje, uma resposta única sobre como fazer isso bem. A mitigação prática é investir em automação e mapeamento claro das entradas e saídas de cada microsserviço, usando mocks para as saídas — permitindo depurar em ambiente de desenvolvimento e identificar problemas na implementação de um microsserviço isoladamente.

Definição: Migração gradual, nunca direta

Caso a empresa já possua um monólito em produção, migrar a aplicação inteira de uma vez para microsserviços é arriscado e trabalhoso. A recomendação é uma estratégia gradual: iniciar a adoção da nova arquitetura em funcionalidades novas, migrando o restante do sistema aos poucos — dando tempo para o time (e o próprio software) amadurecerem tanto na arquitetura quanto no domínio.

Derivando microsserviços a partir de Agregados do DDD

O DDD já orienta a separação de Agregados como módulos dentro de uma aplicação monolítica — o passo seguinte é aplicar esse mesmo raciocínio para definir cada Agregado como um ou mais microsserviços, com ciclo de vida independente, baixo acoplamento e alta coesão.

Agregado Microsserviço
Pagamentos payment-service
Clientes customer-service
Salas room-service
Eventos event-service
Ingressos ticket-service
Administrador admin-service

Definição: Um Agregado pode virar mais de um microsserviço

O relacionamento entre Agregados também pode se desdobrar em microsserviços novos — por exemplo, o relacionamento do Agregado Pagamentos com o Agregado Cliente ("possui ingressos de sessões") revela, na prática, um pedido de compra: daí surge um microsserviço adicional, order-service, responsável só por criar e gerenciar pedidos, sem realizar pagamento nem a gestão de ingressos em si — essas responsabilidades continuam com payment-service e ticket-service, respectivamente.

Definição: BFF (Backend For Frontend)

Padrão em que uma camada intermediária (aqui, bff-frontend) orquestra as chamadas a vários microsserviços em sequência, manipula as respostas, e conhece o domínio interno da aplicação — o objetivo é que o frontend nunca precise conhecer nem lidar diretamente com toda essa complexidade de orquestração, falando só com o BFF. Nem sempre é necessário um serviço dedicado a esse papel: em contextos mais simples, o próprio customer-service/admin-service pode assumi-lo diretamente, já que ambos naturalmente funcionam como porta de entrada para as jornadas do usuário.

Definição: BFF por canal x BFF por domínio

Duas formas comuns de modelar um BFF. Por canal: um BFF por tipo de frontend (bff-web, bff-mobile), cada um otimizado para as necessidades específicas daquele canal (formato de dados, latência) — se assemelha à arquitetura monolítica, pois tende a acumular mais responsabilidades por ser a porta de entrada de todo um canal. Por domínio: BFFs especializados por domínio de negócio (bff-customer, bff-order), usados quando o mesmo frontend atende a diversos clientes/jornadas — se assemelha mais à própria arquitetura de microsserviços, pois cada BFF atende um grupo reduzido de jornadas. Nenhuma das duas abordagens é sempre certa: a escolha depende da complexidade e dos objetivos do projeto, e é comum uma abordagem mista (ex.: bff-home-header, bff-home-content) quando uma única jornada já é grande o bastante para justificar sua própria divisão.

Definição: Vantagens, desafios e segurança do BFF

Vantagens: melhoria na experiência do usuário (dados já formatados para o frontend, menos lógica no cliente); menos chamadas de rede (consolida requisições, reduz latência); desacoplamento entre frontend e backend; facilidade de manutenção (mudar o backend sem afetar o frontend); flexibilidade para adaptar-se a novas tecnologias e dispositivos; escalonamento independente de cada BFF conforme a demanda.

Desafios: sobrecarga de múltiplos BFFs para manter; duplicação de lógica entre BFFs mitigável com libs compartilhadas; complexidade de integração com sistemas legados; necessidade de testes e CI/CD reforçados para evitar quebras; ponto único de falha por trás de cada BFF, exigindo gerenciamento de mudanças cuidadoso.

Segurança: como todo tráfego de um canal passa pelo BFF, ele se torna um ponto natural para concentrar preocupações de segurança — autenticação/autorização via OAuth2/JWT, proteção contra ataques comuns (Web Application Firewall, prevenção a SQL Injection e XSS), monitoramento em tempo real, e controle de dados sensíveis com políticas de acesso e auditoria.

Identificando os fluxos sistêmicos

Com os microsserviços mapeados, o próximo passo é identificar os fluxos sistêmicos — sequências de chamadas entre microsserviços necessárias para completar uma jornada de negócio. No sistema de gestão de eventos e venda de ingressos, três fluxos principais:

flowchart TD
    BFF["bff-frontend"] -->|"Criação e gestão<br/>de eventos"| Admin["admin-service"]
    Admin --> Event["event-service"]
    Event -->|"Obtém salas/cadeiras<br/>disponíveis"| Room["room-service"]
    Event -->|"Obtém ingressos<br/>disponíveis"| Ticket["ticket-service"]
flowchart TD
    BFF["bff-frontend"] -->|"Cria o pedido de<br/>compra dos ingressos"| Customer["customer-service"]
    Customer --> Order["order-service"]
    Customer --> Event["event-service"]
    Event --> Ticket["ticket-service"]
    Order --> Room["room-service"]
flowchart TD
    BFF["bff-frontend"] -->|"Paga o pedido de<br/>compra dos ingressos"| Customer["customer-service"]
    Customer --> Payment["payment-service"]
    Payment --> Order["order-service"]

Cada fluxo mostra como o bff-frontend delega a operação de entrada para o microsserviço responsável, que então coordena os demais microsserviços necessários para completar a jornada — gestão e listagem de eventos, criação de pedidos de compra, e pagamento de pedidos, respectivamente. Mapear esses fluxos antes de implementar qualquer código deixa explícitas as dependências entre microsserviços, o que ajuda a antecipar onde a comunicação síncrona (REST) pode se beneficiar de comunicação assíncrona (ver Event-Driven Architecture) para reduzir acoplamento entre os fluxos.