Pular para o conteúdo principal

Conceitoavançado

Contratos de Integração

Visão Geral

Um contrato de integração é o que uma ponta promete à outra: quais campos existem, o que significam, o que é obrigatório, quais erros podem acontecer, e como a promessa muda ao longo do tempo.

Ele existe em toda integração. A pergunta é se está declarado ou se é implícito — descoberto por quem consome, lendo respostas reais e adivinhando.

Integrações morrem por contrato quebrado. Raramente por escolha de protocolo.

Problema

O padrão comum: um serviço expõe uma API, outro consome. Nenhum documento diz o que é garantido.

O consumidor observa o comportamento e passa a depender de coisas que ninguém prometeu: a ordem dos itens de uma lista, um campo que sempre veio preenchido, o formato de um identificador, o fato de que certo erro nunca acontece.

Do lado do provedor, ninguém sabe disso. Uma mudança que parece interna — reordenar, tornar um campo opcional, mudar o formato de um id — quebra consumidores que ele não sabe que existem.

O defeito aparece em produção, do lado errado, e a discussão vira sobre quem tinha razão.

Conceitos Centrais

O contrato é maior que o esquema

Esquema é a parte fácil e a única que costuma existir. O contrato completo tem mais:

estrutura campos, tipos, obrigatoriedade, cardinalidade
semântica o que cada campo significa, unidade, fuso, moeda
garantias unicidade, estabilidade de identificador, ordenação
erros quais códigos, o que cada um significa, o que é retentável
comportamento idempotência, efeito de repetir, limites de taxa
disponibilidade latência esperada, janela de manutenção
evolução como muda, com quanto aviso, por quanto tempo convivem versões

As linhas de semântica e de erro são as que mais faltam, e as que mais custam. Um campo valor: 1050 sem unidade declarada é uma integração esperando para dar errado.

Declarar o que não é garantido

Metade do valor de um contrato está em dizer o que a outra ponta não pode assumir.

"A ordem dos itens não é garantida." "O identificador é opaco; não interprete o formato." "Campos novos podem aparecer; ignore os desconhecidos."

Sem isso, o consumidor assume tudo que observa. E a assunção não declarada vira contrato de fato, porque quebrá-la quebra alguém.

Robustez tem um lado errado

O princípio clássico — seja liberal no que aceita, conservador no que envia — tem um efeito colateral conhecido.

Um provedor liberal aceita entrada malformada, e os consumidores passam a depender de ser aceitos assim. Corrigir depois quebra todos eles.

A prática que envelhece melhor: rigor na entrada, tolerância na saída. Rejeite entrada inválida desde o primeiro dia; ignore campos desconhecidos na resposta que você recebe.

Contrato dirigido pelo consumidor

A inversão que resolve o problema de "não sei quem depende de quê".

Em vez de o provedor publicar um contrato e torcer, cada consumidor declara o que usa — em forma executável. O provedor roda essas declarações na sua própria integração contínua.

O efeito: o provedor sabe, antes de implantar, exatamente qual consumidor quebra. E pode remover com segurança o que ninguém usa.

É a técnica de maior retorno desta seção, e a menos adotada. Ela exige que os consumidores sejam conhecidos, o que a torna adequada dentro de uma organização e inviável para uma API pública.

Teste de contrato não é teste de integração

Teste de integração sobe as duas pontas e verifica o fluxo. Lento, frágil, e não diz o que quebrou.

Teste de contrato verifica cada lado contra o contrato, isoladamente. Rápido, e aponta a violação exata.

Confundir os dois leva a suítes lentas que continuam deixando quebras passarem.

Contrato público não se remove

Uma API pública com consumidores desconhecidos não permite remoção. O que se pode fazer é adicionar, depreciar com aviso longo, e conviver.

Isso muda o desenho: campos e endpoints públicos são compromisso quase permanente. Expor menos é a decisão que preserva liberdade — e é exatamente o oposto do instinto de "expor tudo, o consumidor usa o que quiser".

Modelo Mental

O contrato não é o que você documentou — é aquilo em que alguém já depende. Declarar o contrato é o que transforma dependência acidental em compromisso conhecido.

Quando Usar

Contrato explícito se paga sempre que:

  • Duas pontas são implantadas independentemente.
  • Times diferentes controlam cada lado.
  • A integração precisa sobreviver à saída de quem a escreveu.
  • Há mais de um consumidor.
  • A API é pública.

Quando Não Usar

Formalizar contrato entre módulos de um mesmo processo, com um time só. Sobrecarga sem benefício — ali o compilador já é o contrato.

Contrato sem processo de mudança. Vira documentação desatualizada, o que é pior que nada: dá falsa confiança.

Versionar tudo desde o primeiro dia. Antes de haver consumidor externo, a liberdade de mudar vale mais.

Contrato dirigido pelo consumidor em API pública. Os consumidores não são conhecidos.

Documento estático como único contrato. Ele diverge do código na primeira semana; o contrato precisa ser verificável.

Alternativas

  • Esquema executável — definição de que servidor e cliente derivam código, eliminando divergência entre documento e implementação.
  • Registro de esquema — o contrato central, com compatibilidade validada na publicação.
  • Teste de contrato dirigido pelo consumidor — dentro da organização.
  • Versionamento explícito — quando conviver é inevitável. Ver evolução de esquema.

Trade-offs

Contrato declaradoImplícito
Mudança previsívelQuebra sem aviso
Consumidores conhecidosDesconhecidos
Processo a manterNenhum
Evolução independenteCoordenação a cada mudança
Dirigido pelo consumidorPublicado pelo provedor
Sabe quem quebra antes de implantarDescobre depois
Remove o que ninguém usaNunca remove
Exige consumidores conhecidosServe API pública
Custo em cada consumidorSó no provedor

Modos de Falha

Dependência não declarada. O consumidor depende do que ninguém prometeu.

Semântica ambígua. Valor sem unidade, data sem fuso, texto sem codificação.

Erro não documentado. O consumidor não sabe o que é retentável.

Documento divergente do código. O contrato escrito não é o implementado.

Remoção quebrando consumidor desconhecido.

Robustez virando compromisso. O provedor aceitava entrada inválida e agora não pode parar.

Erros Comuns

Tratar esquema como contrato completo. O esquema descreve a forma, não o significado: o que acontece em erro, se a operação é idempotente, qual a ordem garantida e o que é opcional de verdade ficam de fora — e são onde a integração quebra.

Não declarar o que não é garantido. Tudo que não é negado explicitamente vira suposição de alguém. Ordem, unicidade e prazo de entrega precisam estar escritos, inclusive quando a resposta é "não garantimos".

Não documentar os erros. O consumidor precisa distinguir o que adianta repetir do que não adianta. Sem isso, ele repete tudo ou não repete nada, e ambos são errados.

Contrato como documento estático. Um contrato que não é verificado por teste diverge da implementação em semanas, e passa a ser uma descrição de como o sistema funcionava.

Expor mais do que o necessário. Todo campo publicado é um campo que alguém vai usar e que não poderá mais mudar. A superfície do contrato é o que se compromete a manter.

Não saber quem consome. Sem a lista de consumidores, não há como avaliar impacto nem avisar sobre depreciação, e toda mudança vira aposta.

Exemplo Real

Uma plataforma de pagamentos expunha uma API de consulta de transações, consumida por sete sistemas internos e dois parceiros externos.

O contrato era um documento escrito uma vez, dois anos antes.

Quatro incidentes ao longo de dezoito meses, todos com a mesma raiz.

Ordem da lista. A resposta trazia as transações ordenadas por data, porque a consulta usava um índice que produzia essa ordem. O contrato não prometia nada. Uma otimização mudou o plano de execução e a ordem mudou. Um consumidor exibia a primeira transação como "a mais recente" — passou a exibir qualquer uma.

Formato do identificador. Os ids começavam com tx_. Um parceiro validava esse prefixo. A migração para identificadores aleatórios quebrou a integração dele, em produção, num sábado.

Campo tornado opcional. Um campo de descrição sempre vinha preenchido. Tornou-se opcional para um novo tipo de transação. Três consumidores quebraram — nenhum tratava ausência.

Erro novo. Passou a existir um código de erro para transação em análise. Consumidores que só tratavam os erros documentados o classificaram como falha permanente e desistiram de transações que teriam sucedido.

As correções, em ordem de retorno:

Contrato executável derivado do código, publicado a cada implantação. O documento estático deixou de existir.

Declaração explícita do que não é garantido — ordem, formato de id, presença de campos opcionais. Isso foi conversado com cada consumidor conhecido, e duas dependências indevidas foram descobertas na conversa, antes de quebrarem.

Testes de contrato dirigidos pelo consumidor para os sete sistemas internos. O provedor passou a saber, na integração contínua, quem quebrava. Nos oito meses seguintes, quatro mudanças foram barradas ali.

Catálogo de erros com a classificação de retentável ou não, por código.

Os dois parceiros externos continuaram sem teste de contrato — não há como executá-lo do lado deles. Para eles, o processo virou aviso com noventa dias e convivência de versões.

O ponto que a equipe sublinha: os quatro incidentes eram, tecnicamente, mudanças válidas. O contrato não prometia nada do que foi quebrado. E isso não ajudou ninguém — o que não está declarado como "não garantido" é assumido como garantido.

Conceitos Relacionados

Exercício Prático

Pegue uma API que seu time expõe. Liste o que ela não garante — ordem, formato de identificador, presença de campos opcionais, estabilidade de erros.

Depois pergunte a um consumidor quais dessas coisas ele assume. A diferença entre as duas listas é a sua próxima quebra.

Perguntas de Entrevista

  • O que um contrato precisa dizer além do esquema?
  • Por que declarar o que não é garantido é metade do valor?
  • Qual a diferença entre teste de contrato e teste de integração?

Para Aprofundar

  • Robinson, Ian. Consumer-Driven Contracts: A Service Evolution Pattern. martinfowler.com, 2006.
  • Newman, Sam. Building Microservices. 2ª ed. O'Reilly, 2021 — capítulo 5.
  • Hohpe, Gregor; Woolf, Bobby. Enterprise Integration Patterns. Addison-Wesley, 2003.
Terminou de ler este documento?Seu progresso fica salvo apenas neste navegador.