Pular para o conteudo principal

Contrato interno entre módulos sem inventar RPC dentro do mesmo app

Separar módulos não deveria obrigar o time a fingir rede, versão e protocolo distribuído dentro de um monólito que ainda é um único deploy.

Andrews Ribeiro

Andrews Ribeiro

Founder & Engineer

O problema

Quando o time começa a modularizar um backend, aparecem dois extremos ruins.

Primeiro extremo:

  • qualquer módulo importa qualquer coisa
  • query atravessa contexto
  • regra interna vaza sem cerimônia

Segundo extremo:

  • cada chamada local vira pseudo-API
  • cada módulo ganha client, DTO, facade e versão
  • o monólito passa a fingir que é uma malha de microservices

Os dois extremos cansam a base.

O primeiro por frouxidão.

O segundo por teatro.

Modelo mental

Contrato interno não é igual a protocolo distribuído.

Contrato interno serve para responder:

  • por onde esse módulo deve ser usado?
  • o que ele promete?
  • o que ele espera?
  • o que pode mudar por dentro sem quebrar outros?

Dentro do mesmo app, isso normalmente pode ser resolvido com:

  • interface pequena
  • porta de entrada clara
  • tipos internos coerentes
  • semântica explícita de erro e resultado

Sem fingir latência, versionamento e serialização onde ainda não existe rede.

O que costuma ser suficiente

Num monólito modular, muitas vezes basta que outro módulo fale com você por:

  • um use case público
  • uma facade interna pequena
  • um serviço de aplicação bem nomeado
  • eventos internos quando fizer sentido desacoplar

O importante é existir um ponto de entrada reconhecível.

Não é obrigar cada chamada local a parecer HTTP.

Exemplo simples

Imagine orders precisando perguntar algo a billing.

Uma solução ruim de frouxidão:

  • orders importa repository de billing
  • consulta tabela de cobrança direto

Uma solução ruim de teatro:

  • billing expõe pseudo-client interno
  • payload serializado
  • response envelope
  • mapeamento como se fosse chamada remota

Uma solução mais saudável:

  • billing expõe uma porta interna clara, como checkChargeability ou getAccountStanding
  • orders depende dessa semântica, não dos detalhes internos

O contrato existe.

Mas o time não precisou encenar rede.

Quando evento interno ajuda

Às vezes o melhor contrato nem é chamada direta.

Se o módulo só precisa reagir a um fato, evento interno pode ser mais adequado.

Exemplos:

  • pedido confirmado
  • usuário bloqueado
  • assinatura cancelada

Mas o mesmo critério vale:

evento interno útil não é substituto genérico para qualquer chamada.

Se um módulo precisa de resposta imediata para decidir agora, talvez evento não seja a forma certa.

O erro comum

O erro comum é importar a discussão de microservices sem olhar o runtime real.

Se ainda é:

  • mesmo deploy
  • mesmo processo
  • mesma base

talvez o melhor contrato interno seja mais leve.

Do contrário, você duplica custo mental sem ganhar isolamento proporcional.

Como um senior pensa

Quem decide melhor costuma perguntar:

  • esse módulo precisa de fronteira explícita ou de protocolo teatral?
  • quem pode chamar isso e por onde?
  • qual dependência estou tentando proteger?
  • estou preparando extração futura com bom senso ou só carregando custo agora?

Essa leitura costuma produzir limites melhores e menos teatrais.

Ângulo de entrevista

Esse tema aparece em perguntas sobre modular monolith, service boundaries e evolução de arquitetura.

O entrevistador quer ver se você:

  • sabe criar limite interno real
  • evita tanto acoplamento livre quanto abstração cênica
  • entende que contrato interno não é cópia de API pública

Resposta forte costuma soar assim:

“Eu criaria um ponto de entrada explícito por módulo, com semântica interna clara, mas evitaria simular RPC dentro do mesmo app. O objetivo é proteger fronteira e reduzir acoplamento, não fingir distribuição antes da hora.”

Takeaway direto

Contrato interno bom faz o módulo ficar mais previsível.

Não faz o monólito atuar como se estivesse num congresso de microservices.

Resumo rápido

O que vale manter na cabeça

Checklist de pratica

Use isto ao responder

Você concluiu este artigo

Próximo artigo Contratos internos de comando e consulta sem payload genérico demais Artigo anterior Consistência de cache interno sem invalidar no desespero

Continue explorando

Artigos relacionados