02Critério5 min

Documentar antes de programar: minha regra para integrações que não controlo

Numa integração com uma API alheia, os quatro primeiros commits não tocam em código. Escrever o documento antes obriga a medir os limites que depois explodem em produção.

Por Salva Castells

Imagem de capa: Tobin, CC BY-SA 2.0.
Neste post

Um visualizador de repositórios que fiz no verão passado tem oito commits na primeira semana. Os quatro primeiros não tocam uma única linha de aplicação: são o init a partir do meu template e três commits de documentação. O quinto já é o app inteiro.

Não foi disciplina. Foi que, ao escrever o documento, descobri que meu modelo mental da integração estava errado, e consertar isso num .md custava vinte minutos em vez de dois dias.

O erro de começar pelo código numa integração alheia

Quando a lógica é sua, ler o código é a melhor documentação que existe. Quando depende de uma API alheia, não: o que você precisa saber não está no seu código nem no deles. Está nos limites, nas cotas e nos parâmetros descontinuados.

Nesse visualizador confundi por um tempo duas conexões com o mesmo provedor. O OAuth de login e o token de servidor para ler a API parecem a mesma coisa e não são. Um serve para um humano entrar, o outro para o servidor ler. Falham de formas diferentes. Escrever isso num documento separado em duas seções foi o que me fez ver que um visualizador de repositórios públicos só precisava do segundo.

Se eu tivesse começado pelo código, teria descoberto isso no terceiro 401.

O que exatamente eu documento antes da primeira linha

Não documento o design do meu app. Documento o que não controlo. Em concreto:

  • Os limites reais, medidos, não citados. Não basta copiar "5.000 requisições por hora" do site. Pedi ao endpoint de cota: 60/h sem autenticar, 5.000/h autenticado, 30/min na busca. E medi que um 304 Not Modified não gasta cota — 4972, 4972, 4972 com condicionais, e 4971 na mesma chamada sem If-None-Match. Esse número se repetindo é o argumento central do documento, e sem executar você não o tem.
  • O que não dá para automatizar. O OAuth App não se cria por CLI: não há endpoint para criá-lo nem para ler o client secret, que é mostrado uma única vez no navegador. É um passo manual, e no dia em que você montar o ambiente de novo terá esquecido.
  • Os tetos que surpreendem em produção. 2.000 criações de token por hora, que é teto de logins, não de requisições. E reautorização forçada se um usuário entra dez vezes numa hora. Nenhum dos dois aparece quando você lê o happy path.
  • O que a decisão NÃO resolve. Anotei que obrigar login não elimina a necessidade de cache condicional, porque o bucket do usuário é compartilhado com o PAT dele e com outros apps que atuem em seu nome. Se você não escreve isso, a decisão te dá uma falsa segurança.

Nada disso é opinável. São fatos que ou você comprova ou inventa.

Os cookbooks: testar cada peça isolada antes de integrá-la

Num serviço de IA para análise documental fiz o mesmo de outra forma. Antes que qualquer peça entrasse no serviço, cada uma tinha um cookbook: um script que a executa sozinha, escreve sua saída numa pasta e se registra num run_all_cookbooks. Parser de PDF, chunker, embeddings, detector de números, extração verificável. Um por peça.

O valor não é o teste. É que, quando a saída do chunker muda de forma, isso aparece num arquivo de texto em vez de numa falha três camadas acima. Ao passar o pipeline para assíncrono, os cookbooks viraram runners com asyncio.run e a migração foi feita peça a peça, não de uma vez.

O custo é que é preciso apagá-los quando deixam de valer. Meses depois há um commit que remove os cookbooks descontinuados. Um cookbook que já não corresponde à peça é pior que nenhum.

A documentação como fonte de verdade para auditar depois

Numa galeria de conceitos de UI escrevi primeiro um guia de design da peça — tamanhos, escada de espaçamento, escala de cinzas, qual primitivo se usa para quê — e depois auditei o código contra ele.

O interessante é que a auditoria corrigiu o guia, não só o código. Três coisas que o .md dizia a menos: que o cinza acompanhante se gradua em cinco degraus e não em dois; que a escada de espaçamento tem quatro degraus e não três, porque chamá-la de três transformava seis usos legítimos em desvio; e que os três diálogos são na verdade o mesmo diálogo, com a mesma caixa e o mesmo cabeçalho, e por não dizer isso a correção tinha sido aplicada a apenas um.

Sem documento prévio esses três achados não existem. Você não tem contra o que comparar e tudo o que encontra é "eu acho que".

Quando isso é perda de tempo

O critério que uso:

  • Se a integração é sua de ponta a ponta, não documente antes. O código é a verdade e o documento envelhece.
  • Se é um protótipo que você vai jogar fora, também não. Um jogo que escrevi em um dia não tem nada escrito e está bem assim.
  • Se o documento vai repetir o que a referência oficial diz, não o escreva. Só agrega se tiver suas medições, suas versões e as armadilhas que couberam a você.

E há uma falha que me custou caro: o documento escrito antes carrega dentro as suas suposições. No visualizador, a seção de hospedagem descrevia uma plataforma serverless porque eu dei isso como certo ao redigir o escopo, não porque alguém tivesse decidido. Ao corrigir para um contêiner de vida longa, a conclusão inteira mudou: em serverless o SDK de agentes não cabia; num worker com quinze minutos de limite de requisição, cabia.

Por isso o passo seguinte não é opcional. Há um commit cujo único trabalho é verificar o documento contra fontes vivas: executar a consulta que aparece no guia, mandar uma versão de API inválida para que a própria API enumere as válidas, comprovar que per_page=500 é cortado para 100 em silêncio, tipar o snippet que não compilava em modo estrito. Esse commit descobriu que 18 de 20 "issues" devolvidas eram na verdade pull requests.

Um documento sem verificar é uma suposição com formatação bonita. Um documento verificado é a única parte da integração que não vai mentir para você daqui a seis meses.