Conectivos para o desenvolvimento: o que funciona e o que quebra no dia a dia
Muita gente começa um projeto novo achando que conectar sistemas é só escolher uma biblioteca e chamar uma função. Na prática, você passa mais tempo lidando com timeouts, retry policy e formatos de payload diferentes do que escrevendo código novo. Isso é normal. O problema é que a maioria dos tutoriais mostra apenas o fluxo feliz.
O básico dos conectivos para o desenvolvimento
Conectivo, nesse contexto, é qualquer abstração que permite que dois serviços ou módulos se comuniquem de forma padronizada. Pode ser um client HTTP, uma fila de mensagens, um adaptador de banco de dados, ou até um wrapper em torno de uma API de terceiros. O objetivo é isolado: você não quer que uma mudança na API do parceiro quebre três arquivos diferentes no seu projeto. A estrutura mínima que eu uso em quase tudo hoje é essa. Crie uma interface pura, sem dependências de infraestrutura. Depois, implemente ela com o client real. Quando precisar trocar de provedor ou simular em teste, você injeta a interface. Simples, mas muita gente pula essa parte e vive sofrendo depois.
O que diferencia um conectivo bem feito de um ruim é como ele lida com o que dá errado. A maior parte do código que vejo em repositórios públicos trata apenas o sucesso. Quando a requisição falha, o sistema simplesmente cai. Em produção, isso não funciona.
Como estruturar um conectivo que não te causa dor de cabeça
Vou pegar um exemplo real. No último projeto que fiz, precisávamos consumir uma API de pagamentos de um gateway que tinha SLA instável. A documentação dizia "99,9% de disponibilidade". A prática foi bem diferente em horários de pico. Chamar a API e tratar erro como exceção genérica funcionava em homologação e travava tudo em produção. A solução que adotamos foi implementar um padrão de retry exponencial com jitter, mas só para operações idempotentes. Requisições de criação de transação iam direto para um dead letter queue quando falhavam após três tentativas, em vez de retry infinito. Isso reduziu o número de tickets de incidentes noturnos de cerca de vinte por semana para dois ou três.
Retry policy: onde a maioria erra
Retry não é bala de prata. Se você colocar retry em tudo, pode piorar o problema de load em cascata. A regra prática que eu sigo: retry apenas em operações idempotentes (GET, DELETE, PUT com chave única) e com limite rígido de tentativas. Nunca em POST de criação, a menos que o serviço de destino garanta idempotência via token único no header. Outro erro comum é usar o mesmo timeout para tudo. Conexão com um serviço interno pode ter timeout de 500ms. Uma API de terceiro pode precisar de 5 segundos. Configurar tudo igual é pedir para um serviço lento travar o rápido.
Timeout, deadline e cancellation
Todo conectivo que se preza precisa suportar context cancellation. Em Go uso context com deadline, em Python com asyncio.wait_for. O ponto importante é passar esse contexto para todas as camadas, inclusive para conexões de banco. Já vi conectivo que fazia o request correto com timeout definido, mas a query no banco rodava sem deadline e prendia conexão por minutos. Na prática, isso significa que seu conectivo deve receber um contexto/timeout como parâmetro obrigatório, nunca usar valores hard-coded. E se o upstream não expor timeout configurável, você coloca um wrapper que cancela a operação após o limite que você definiu.
Serialização: o campo minado que ninguém comenta
Aqui vai algo que aprendi na marra. Converter dados entre formatos parece trivial até você encontrar um caso onde um campo numérico vem como string com vírgula decimal em vez de ponto, ou um timestamp sem fuso horário. Quando seu conectivo consome dados de múltiplas fontes, a validação na entrada é obrigatória, não opcional. Eu uso validação estrutural com schemas no.entry point de cada conectivo. Em Python, Pydantic. Em Go, struct tags com validadores ou uma biblioteca como datalogic. Se o payload não passa na validação, você rejeita com um erro claro antes de qualquer lógica de negócio. Isso elimina meia dúzia de bugs que aparecem semanas depois, quando alguém descobre que o dado chegou corrompido.
👉 Clique no botão abaixo para saber mais sobre o assunto!
O downside é que isso adiciona código boilerplate. Sim, adiciona. Mas o custo de manutenção de debuggar dados malformados em produção é muito maior do que escrever o schema uma vez.
Logging e observabilidade: o que você precisa rastrear
Um conectivo bem implementado gera logs estruturados com pelo menos: timestamp, ID da requisição, endpoint chamado, status code, latência e mensagem de erro se houver. Sem isso, quando algo quebra às três da manhã, você está adivinhando. Um detalhe prático: nunca logue dados sensíveis. Token de API, CPF, número de cartão. Isso parece óbvio até ver um dump de log vaziar no Slack porque alguém esqueceu de remover um print do response completo.
Métricas também são importantes. Contagem de requisições, taxa de erro por endpoint, percentis de latência. Se você não tem isso, está voando cego. Prometheus com expor um endpoint de metrics ou enviar para um service like Datadog resolve. Leva cerca de uma hora para configurar e depois você tem visibilidade real do comportamento dos seus conectivos.
Caching: quando vale a pena e quando não vale
Caching em conectivos é útil para dados que não mudam com frequência e cujo custo de busca é alto. Uma lista de categorias, por exemplo. Mas caching de dados transacionais é armadilha. Você começa com TTL de cinco minutos, depois percebe que o dado está desatualizado e o problema vira um bug intermitente difícil de reproduzir. Regra simples: cache apenas para dados read-only ou com invalidate explícito. E sempre tenha um mecanismo de fallback que permita furar o cache quando necessário. No meu projeto de pagamentos, tínhamos um cache de taxas de câmbio que às vezes vinha desatualizado. Criamos um header X-Cache-Bypass que, quando enviado, pulava o cache e ia direto para a fonte. Resolveu sem complicação.
Testando conectivos sem depender do serviço externo
Teste de integração com serviço de terceiro é lento e frágil. O jeito certo é usar um mock ou wiremock. Você grava os responses esperados e roda contra eles. Assim seu teste é rápido, determinístico e não quebra quando o fornecedor atualiza a API. Para testes unitários do conectivo em si, use a interface definida lá no início. Injeta um mock que retorna o que você quiser. Teste os caminhos de erro, timeout, retry exaurido. Se você só testa o fluxo feliz, o conectivo não está testado.
O tempo gasto com testes bem feitos compensa. Em média, um conectivo testado leva o dobro do tempo para ser escrito, mas reduz em cerca de 70% os bugs que chegam em produção. Se você pular testes, vai passar mais tempo consertando do que desenvolvendo.
Quando não usar um conectivo customizado
Nem tudo merece um conectivo do zero. Se existe uma biblioteca madura que resolve seu problema com boa manutenção e testes, use ela. SDKs oficiais de AWS, Google Cloud, Stripe, OpenAI são exemplos. Recriar o que já existe é perda de tempo e introduz bugs conhecidos que outros já resolveram. O conectivo customizado faz sentido quando: a biblioteca existente não expõe funcionalidade que você precisa, você precisa de um comportamento específico de retry ou cache, ou você está consumindo múltiplos provedores similares e quer uma interface unificada. Fora esses casos, evite reinventar.
Manutenção a longo prazo
O maior custo de um conectivo não é escrevê-lo. É mantê-lo quando a API do parceiro muda. Sempre versionoe sua interface. Se a API de terceiro quebra breaking change, você cria uma nova versão do conectivo e mantém ambas rodando até migrar todos os consumers. Não atualize em produção sem testes de regressão cobrindo os casos de uso existentes. Documentação interna também conta. Um README com exemplos de uso, comportamentos esperados, limites de rate e pontos de dor conhecidos economiza horas de onboarding para quem chega depois. Escrever documentação dá preguiça no início, mas na terceira vez que alguém pergunta como aquele conectivo lida com retry, você agradece a versão anterior de si mesmo por ter documentado.