Home Comunidade Eventos YouTube Networks Desafios // produtos Academy News CTI | CVE Contato

02 - Customer-Supplier

#contratos#customer-supplier#ddd#roadmap#upstream
video explicativo
Video explicativoEspaco reservado para o video desta anotação — adicione video: https://youtu.be/... no frontmatter da nota.

Customer-Supplier

Customer-Supplier é o padrão de integração entre contextos que organiza a relação em torno de dois papéis explícitos: o upstream, que fornece o serviço ou dado, e o downstream, que consome e depende do que é fornecido. O diferencial do padrão não está na troca técnica, e sim no acordo social que a acompanha: o fornecedor trata as expectativas do consumidor como requisito de teste automatizado, e o consumidor tem canal formal para negociar prioridades. Em produção, essa estrutura resolve o problema mais comum de integração interna, que é o time consumidor depender de um time fornecedor sem qualquer mecanismo de accountability. A relação informal funciona bem até o primeiro conflito de prioridade, quando a necessidade do consumidor compete com o roadmap do fornecedor e perde silenciosamente. Com o padrão aplicado, a expectativa vira contrato testado e a prioridade vira negociação registrada. O resultado é uma integração que sobrevive a trocas de pessoas, mudanças de escopo e picos de carga.

Papéis de upstream e downstream

O upstream fornece a capacidade, e o downstream consome. O nome técnico do padrão descreve a direção da dependência: o downstream depende do upstream, nunca o contrário, e essa assimetria é a base de todo o resto.

Os elementos do acordo, em um desenho maduro, são:

  • Contrato formal, em OpenAPI, gRPC ou schema de evento, publicado e versionado pelo upstream como artefato de primeira classe.
  • Testes automatizados de expectativa, em que o conjunto de necessidades do downstream roda contra o pipeline do upstream, bloqueando mudanças que quebrem o consumidor.
  • Canal de negociação, normalmente revisão periódica registrada, em que o downstream exerce influência real sobre o roadmap do upstream.
  • SLA de disponibilidade e de resposta a incidentes, porque a falha do upstream se torna diretamente a falha do downstream.
  • Política de compatibilidade, que define o que o upstream pode mudar sem avisar e o que exige janela de transição.

A configuração de poder entre os dois lados varia e o padrão a tolera. Quando o downstream é produto de receita e o upstream é serviço de apoio, o consumidor tem peso de prioridade maior. Quando o upstream é plataforma corporativa que atende dezenas de consumidores, o poder se inverte, e o downstream passa a se adaptar dentro das extensões que a plataforma oferece. O padrão funciona nos dois casos, desde que os papéis e as expectativas sejam declarados.

Configuração de poder Exemplo típico Efeito prático no acordo
Downstream dominante Checkout sobre serviço de apoio interno Demandas do consumidor entram no topo do backlog upstream
Upstream dominante Plataforma corporativa com dezenas de consumidores Influência via extensões e via comitê de consumidores
Poder equilibrado Dois produtos da mesma diretoria Negociação por troca de valor em ambas as direções
Upstream externo Provedor SaaS contratado Padrão degrada para Conformist ou ACL, com contratos de nível de serviço
Dependência de legado Sistema antigo sem dono ativo Expectativas automatizadas impossíveis, ACL protege o downstream

O problema que resolve

A integração sem padrão definido produz três falhas recorrentes em produção. A primeira é a expectativa implícita: o time consumidor monta sua lógica sobre o comportamento observado da API do fornecedor, sem que o fornecedor saiba quais partes são críticas, e uma mudança considerada trivial derruba o consumidor. A segunda é a quebra de prioridade: quando o fornecedor reorganiza o roadmap, as demandas do consumidor não têm representação formal e ficam sempre para depois. A terceira é o diagnóstico cruzado: em incidente, o consumidor descobre a quebra junto com o usuário, porque não existe mecanismo que teste o contrato antes do deploy.

O Customer-Supplier ataca as três falhas com o mesmo mecanismo. A expectativa explícita e automatizada transforma comportamento crítico em teste que roda no CI do fornecedor. O canal de negociação dá ao consumidor assento no planejamento do fornecedor. O contrato versionado dá ao diagnóstico um ponto de comparação, porque a pergunta muda de o que aconteceu para qual diferença entre versões explica o comportamento.

Automação das expectativas

O coração operacional do padrão é colocar os testes de expectativa do downstream dentro do pipeline do upstream. Contratos guiados por consumidor, implementados em ferramentas como Pact, materializam essa ideia: o consumidor publica o pacto com as interações de que precisa, e o fornecedor verifica o pacto contra a implementação atual antes de qualquer merge.

# Fluxo de contrato guiado por consumidor entre checkout e precificação
fluxo_pact:
  atores:
    upstream: "servico-precificacao"
    downstream: "servico-checkout"
  etapas:
    - passo: "checkout executa testes contra mock e publica o pacto"
      conteudo: "GET /precos com sku e quantidade, espera 200 e total"
    - passo: "broker de pactos registra a versão do pacto e do consumidor"
    - passo: "pipeline da precificação busca pactos pendentes e verifica"
    - passo: "verificação vermelha bloqueia o merge no upstream"
    - passo: "checkout consulta can-i-deploy antes do próprio deploy"
  regra:
    compatibilidade: "nenhuma mudança de schema que viole pacto entra em produção"

O mecanismo muda o regime de falha. Sem verificação, a quebra aparece em produção e vira incidente com dois times mobilizados. Com verificação, a quebra aparece no CI do fornecedor, minutos depois do push, com o pacto violado apontando exatamente qual interação deixou de ser atendida. O custo da falha despenca de incidente para ajuste de código.

{
  "consumer": { "name": "checkout", "version": "2.4.1" },
  "provider": { "name": "precificacao" },
  "interactions": [
    {
      "description": "consulta preço total com desconto por volume",
      "request": {
        "method": "GET",
        "path": "/precos",
        "query": { "sku": "ABC-10", "quantidade": "150" }
      },
      "response": {
        "status": 200,
        "body": {
          "sku": "ABC-10",
          "preco_unitario": "39.90",
          "desconto_aplicado": "0.05",
          "total": "5686.50"
        },
        "matchingRules": {
          "$.body.total": { "match": "type" },
          "$.body.desconto_aplicado": { "match": "regex": "^0\\.[0-9]{2}$" }
        }
      }
    }
  ]
}

O detalhe técnico que evita contratos frágeis está nas regras de correspondência. Um pacto que fixa valores literais quebra em qualquer mudança de preço, e a equipe passa a ignorar falhas de contrato, o que anula o mecanismo. As regras de tipo e de formato, como qualquer número para total e regex para o formato do desconto, mantêm o pacto focado no que importa: a existência dos campos, os tipos e o formato, e não o dado de exemplo.

Em ecossistemas sem ferramenta dedicada, a mesma ideia funciona com testes de contrato escritos à mão: o upstream mantém uma suíte chamada expectativas-checkout, acordada com o consumidor, e a suíte roda em todo pipeline. O formato importa menos do que o princípio, que é o comportamento do upstream ser verificado contra a necessidade declarada do downstream, e não contra a opinião de quem escreveu a mudança.

Contrato e compatibilidade

O contrato é a materialização escrita do acordo, e a política de compatibilidade é a parte que evita incidentes. A política define quais mudanças são seguras, quais exigem transição e quais são proibidas sem nova versão.

Mudança no contrato upstream Classificação Procedimento exigido
Adicionar campo opcional na resposta Compatível Nenhum, consumidor ignora o que não conhece
Adicionar campo obrigatório na requisição Incompatível Versão nova ou aceitar default no servidor
Renomear campo Incompatível Período com os dois nomes e deprecação do antigo
Remover campo da resposta Incompatível Janela acordada com confirmação dos consumidores
Tornar campo opcional em obrigatório no retorno Compatível com cautela Avisar consumidores que já tratam ausência
Alterar códigos de erro existentes Incompatível Nova versão, código antigo mantido na transição
Adicionar endpoint novo Compatível Publicação na documentação e changelog

A compatibilidade retroativa é a regra padrão, e as exceções precisam de processo. Mudança incompatível exige versão nova do endpoint ou do schema, janela de sobreposição em que as duas versões respondem, comunicação formal aos consumidores e métrica de consumo da versão antiga até chegar a zero. O erro clássico é manter a política apenas no boca a boca; a política precisa estar no README do contrato, com exemplos de cada classificação, para sobreviver à rotatividade das equipes.

No canal assíncrono, o mesmo acordo assume forma de schema de evento com registro de schemas centralizado. O upstream publica a versão do schema, o consumidor valida compatibilidade antes de migrar o consumidor do tópico, e o teste de expectativa verifica que o evento contém os campos de que o downstream depende. O erro específico desse canal é o consumidor ler o evento cru sem camada de desserialização versionada, o que espalha suposições de formato pelo código e impede a migração controlada de versões.

Coordenação de roadmap entre times

O componente social do padrão é tão determinante quanto o técnico, e a coordenação de roadmap é o ponto em que ele aparece. O downstream não é apenas consumidor de API; é cliente do upstream, e clientes negociam prazo, escopo e prioridade. A prática que sustenta a negociação é a revisão periódica registrada, na qual o downstream apresenta demandas com impacto de negócio e o upstream as avalia contra a capacidade e os outros consumidores.

Uma agenda típica de revisão cobre os itens a seguir:

  • Demandas novas do downstream, com caso de negócio e prazo desejado, avaliadas contra o backlog do upstream.
  • Pendências em andamento, com status real, bloqueios e responsável, evitando o relatório de otimismo que esconde atraso.
  • Mudanças planejadas pelo upstream que afetam consumidores, comunicadas com antecedência suficiente para adaptação.
  • Métricas do contrato, como volume de chamadas, latência nos percentis altos e taxa de erro vista pelo consumidor.
  • Revisão dos pactos de expectativa, removendo interações que deixaram de existir e adicionando as que surgiram.

Quando o upstream serve muitos consumidores, a negociação vira arbitragem, e a solução usual é a extensão controlada: a plataforma oferece pontos de extensão, como campos customizáveis e webhooks, e cada consumidor adapta dentro do que a plataforma fornece. O Customer-Supplier continua válido, com a diferença de que a influência do downstream se exerce sobre a evolução das extensões e não sobre o núcleo do serviço.

Relação com sistemas externos e legados

O padrão pressupõe os dois lados sob coordenação dentro da mesma organização, e é nisso que ele difere de alternativas voltadas a fronteiras externas. Provedor de pagamento, plataforma de mensageria e qualquer SaaS contratado não participam do seu processo de priorização, não rodam seus pactos e não negociam roadmap com você. Nesses casos, a relação real é de dependência unilateral, e a estratégia correta migra para Conformist, quando o modelo externo é aceito diretamente, ou para ACL, quando o modelo externo precisa ser traduzido.

Legado interno cria uma variante interessante: o sistema antigo é upstream de fato, mas não tem equipe capaz de rodar testes de expectativa nem de assumir prioridades. A saída usual é o downstream assumir sozinho o papel de protetor, com ACL no lado consumidor e instrumentação intensa de compatibilidade, enquanto se planeja a substituição do legado. Reconhecer essa limitação com honestidade é melhor do que fingir um acordo que não existe, porque o falso acordo esconde risco que ninguém gerencia.

Aplicação prática: exemplo de extremo a extremo

Um caso concreto amarra os componentes. O serviço de precificação é o upstream, e o checkout é o downstream. O checkout precisa do preço total com desconto por volume, e essa interação vira pacto publicado no broker. O pipeline da precificação verifica o pacto em todo pull request, e uma proposta de mudança no formato de desconto é bloqueada porque viola a expectativa registrada. O time do checkout abre a demanda na revisão mensal, argumentando com o impacto na conversão, e os times acordam um novo campo de desconto detalhado em versão dois do endpoint. Durante seis semanas as duas versões respondem, com métrica de consumo da versão um acompanhada semanalmente. Quando o consumo da versão antiga chega a zero, ela entra em deprecação formal e é removida no ciclo seguinte. Nenhuma etapa desse fluxo depende de sorte ou boa vontade; cada uma tem artefato, dono e mecanismo de verificação.

Erros comuns e boas práticas

Sintoma em produção Causa raiz Mitigação
Consumidor quebrado por mudança trivial do upstream Expectativa implícita, sem pacto automatizado Contratos guiados por consumidor no pipeline
Demandas do consumidor sempre adiadas Sem canal formal de negociação Revisão periódica registrada com priorização
Incidente descoberto pelo usuário final Nenhum teste de contrato antes do deploy Verificação de pacto bloqueando merge
Versões antigas vivendo indefinidamente Deprecação sem prazo e sem métrica de consumo Janela acordada e dashboard de consumo por versão
Acordo perdido com a troca de pessoas Relação baseada em contato informal Documentação do acordo e do canal de decisão

A boa prática que separa implementações maduras de implementações nominais é a exigência de can-i-deploy no deploy do consumidor. Sem essa verificação, o consumidor pode publicar dependência de recurso que ainda não existe no upstream, e a integração quebra no ambiente de staging com dois times procurando culpa. Com a verificação, o deploy do consumidor é bloqueado até que a versão do upstream com o recurso verificado esteja em produção. A segunda prática decisiva é tratar o pacto como código revisado: mudança de expectativa passa por pull request no repositório do consumidor, com revisão do time do upstream quando a mudança é estrutural. Pacto que muda sem revisão é contrato sem validade, e a confiança acumulada entre os times evapora na primeira quebra não detectada.