MÓDULO 13 · CONCEITO 08 DE 15

Documentação Gerada com IA

Quando agrega valor, quando polui a base, e como documentar o que o código não diz

Tempo de leitura ~20 min Pré-requisito 07 · Refactoring assistido por IA Próximo 09 · IA em pipelines de CI/CD

Documentação gerada por LLM é um dos casos onde a capacidade de produção é inversamente proporcional ao valor produzido quando usada incorretamente. Um LLM pode gerar docstrings para cada função de um repositório em minutos — e na maioria dos casos, o resultado é documentação que descreve o que o código faz, informação que um leitor competente já extrai do código. O que está faltando — as decisões de design, as restrições não-óbvias, o porquê de uma escolha que parece estranha à primeira vista — o LLM não consegue produzir porque não existe no texto do código.

Há um princípio de documentação que precede LLMs e que fica ainda mais importante com eles: boa documentação explica o porquê, não o quê. O quê está no código — qualquer leitor vê que a função itera sobre uma lista e filtra por status. O que o leitor não vê: por que esse filtro específico, por que nesse lugar e não em outro, por que esse campo e não aquele, o que aconteceu quando foi tentado de outra forma. Essas são as informações que economizam horas de debugging e de entendimento errado — e são exatamente o que LLMs não conseguem gerar porque não estiveram presentes nas decisões.

Isso não significa que LLMs são inúteis para documentação. Significa que o valor está em lugares específicos: documentar decisões de design que o engenheiro articula explicitamente, gerar documentação de API a partir de contratos bem definidos, manter changelogs a partir de commits, e identificar onde a documentação existente está desatualizada ou inconsistente com o código. O padrão correto é usar LLM para a parte mecânica de documentação e preservar o esforço humano para a parte de valor alto — documentar as decisões que só o engenheiro conhece.

O problema fundamental: LLMs descrevem o quê, não o porquê

Considere uma função com o seguinte comentário gerado por LLM: "Calcula o preço final do pedido aplicando descontos e impostos". O comentário é correto, fluente, e completamente inútil — qualquer pessoa que lê o nome da função CalculateFinalOrderPrice já sabe isso. O comentário que seria valioso: "Imposto é calculado sobre o preço com desconto, não sobre o preço original — isso é requerimento legal (consulte issue #1423 para o contexto do regulador). A ordem de aplicação (desconto primeiro, então imposto) não pode ser invertida sem validação legal."

Esse comentário valioso não pode ser gerado por LLM porque a informação — que a ordem de cálculo é requerimento legal, não escolha de implementação — não existe no código. Ela existe na memória do engenheiro que implementou, no histórico de discussão da issue, no documento legal que o time recebeu. O LLM vê apenas o resultado: desconto aplicado, imposto calculado. A decisão que tornou esse resultado necessário é invisível.

Esse problema escala para todo o código de domínio não-trivial: invariantes de negócio, decisões arquiteturais, workarounds para bugs de dependências externas, comportamentos que parecem errados mas estão corretos por razões não-óbvias. O LLM pode identificar que o código faz algo não-óbvio — uma condição que parece estranha, um número mágico, uma sequência de operações incomum — e pode perguntar ao engenheiro o porquê. Mas a resposta precisa vir do engenheiro.

princípio orientador

Antes de gerar documentação com LLM, pergunte: "o que estou documentando é visível para um leitor competente que lê o código?" Se sim, a documentação não agrega valor — o código já é a documentação. O que vale documentar é o que o código não mostra: decisões, restrições, trade-offs, contexto histórico, invariantes de domínio. Essas informações precisam vir do engenheiro, não do LLM.

Onde LLMs agregam valor em documentação

Documentação de API a partir de schema formal. Dado um schema OpenAPI, definição de Protocol Buffer, ou interface tipada, o LLM pode gerar documentação de referência — descrições de campos, exemplos de request/response, descrições de endpoints. Essa documentação é derivável dos contratos formais e é exatamente o tipo de transformação mecânica que LLMs fazem bem. O resultado não precisa de input do engenheiro além do schema, que já existe.

README de módulo a partir da estrutura e testes. Para um módulo que o engenheiro conhece bem, o LLM pode gerar o rascunho do README: o que o módulo faz, como usá-lo, quais são as principais APIs públicas. O engenheiro fornece o contexto de domínio que o LLM não tem (por que esse módulo existe, quais os casos de uso primários, o que está fora do escopo) e o LLM gera a estrutura e os exemplos de uso a partir dos testes e do código.

Changelog a partir de commits. "Dado os commits desta semana, gere um changelog no formato convencional agrupando por tipo de mudança" é uma tarefa mecânica e bem adequada para LLM. O resultado é mais consistente do que changelog escrito manualmente por cada desenvolvedor e mais completo do que changelog só do que o time lembrou de mencionar na reunião de sprint.

Identificar onde documentação está desatualizada. "Dado o código atual e a documentação existente, identifique onde a documentação não corresponde ao código" é análise que LLMs fazem razoavelmente bem para inconsistências visíveis — um parâmetro documentado que não existe mais na assinatura, um comportamento descrito que o código implementa diferente, um exemplo que não compila com a versão atual da API. Inconsistências sutis de semântica ainda requerem o humano.

Documentar decisões de design que o engenheiro articula. Esse é o uso de mais valor: o engenheiro escreve um rascunho de ADR ou comentário de design em bullet points, e o LLM transforma em prosa fluente e bem estruturada. O conteúdo — as decisões reais, as alternativas consideradas, as restrições que levaram à escolha — vem do engenheiro. A fluência e a estrutura vêm do LLM. A combinação é mais rápida do que o engenheiro escrevendo tudo e mais substancial do que o LLM gerando sem input de decisões reais.

O risco da documentação que ninguém mantém

Documentação gerada automaticamente tem um risco específico: como é barata de gerar, há incentivo a gerar muito. Documentação que ninguém vai manter fica desatualizada rapidamente — e documentação desatualizada é ativamente prejudicial, porque um leitor que a encontra pode confiar nela e tomar decisões baseadas em informação errada.

A heurística para decidir se a documentação que vai ser gerada vale gerar: alguém vai ler isso? Quem? Quando? Se a documentação for para um módulo interno que só três pessoas do time conhecem e que ninguém de fora vai consultar, o custo de mantê-la atualizada supera o benefício de tê-la. Se for para uma API pública que consumidores externos vão usar, o valor de manter atualizada é alto e o custo de desatualização é ainda mais alto.

Para documentação de API pública, a solução que escala é documentação como código: o schema OpenAPI é a source of truth, gerado automaticamente a partir das anotações no código (ou o código gerado a partir do schema), e a documentação de referência é derivada do schema. Essa abordagem garante consistência automaticamente — o schema está errado ou o código está errado, mas não podem divergir silenciosamente. LLMs ajudam na parte narrativa (descrição de casos de uso, exemplos, guias de início rápido) que não é derivável do schema.

C# — documentação de decisão de design via LLM a partir de bullet points
// Engenheiro escreve o contexto em bullet points:
//
// Decisão: usar outbox pattern para garantir que eventos
// são sempre publicados depois de mudança de estado do pedido
//
// - Problema: se publicarmos o evento antes de salvar no banco,
//   o banco pode falhar e o evento já saiu — inconsistência
// - Se salvarmos no banco e publicarmos depois, a instância pode
//   morrer antes de publicar — evento perdido
// - Tentamos two-phase commit mas era muito complexo e tinha
//   problemas de performance com o message broker
// - Outbox: salvar evento na mesma transação do banco,
//   um worker separado lê o outbox e publica
// - Trade-off aceito: latência extra de publicação (50-200ms)
//   em troca de garantia de entrega
// - Alternativa considerada e rejeitada: saga com compensação
//   (complexidade muito alta para o nível de consistência exigido)
//
// Instrução ao LLM:
// "Transforme esses bullet points em um ADR (Architecture
//  Decision Record) bem estruturado seguindo o template
//  em docs/templates/adr-template.md. Tom técnico, objetivo.
//  Não adicione informação além do que está nos bullets.
//  Não faça suposições sobre o sistema além do que foi descrito."

// Resultado: ADR fluente com contexto, decisão, alternativas
// e consequências — o engenheiro forneceu o conteúdo,
// o LLM forneceu a estrutura e a fluência.

O engenheiro fornece as decisões reais (o que o LLM não tem como inventar); o LLM transforma em documento estruturado. Essa divisão produz documentação que tem valor real sem o custo de escrever prosa do zero.

Python — identificar código sem documentação de porquê
# Instrução ao LLM para auditoria de documentação:
"""
Leia o módulo services/pricing.py.

Para cada bloco de código ou decisão que parece não-óbvia,
liste:
1. O que o código faz (o quê — visível no código)
2. Por que faz assim (o porquê — o que está FALTANDO
   ser documentado e eu como autor deveria explicar)

Foque em:
- Números mágicos (constantes sem nome ou explicação)
- Condicionais com mais de 2 ramificações
- Ordem de operações que parece arbitrária mas pode não ser
- Tratamentos de caso especial sem comentário
- Uso de biblioteca de forma não-óbvia

Não invente o porquê — liste o que está faltando ser explicado.
Vou responder com o contexto real de cada um."
"""

# Resultado: lista de lugares onde documentação de porquê
# está faltando. O engenheiro responde com o contexto real.
# O LLM transforma as respostas em comentários/docstrings.

# Exemplo de resultado da auditoria:
# L47: FALTANDO — por que multiplica por 0.85 para pedidos
#      internacionais? É taxa? É desconto? Regulação?
# L89: FALTANDO — por que o fallback é 'standard' e não 'none'?
#      Qual o impacto de trocar esse default?
# L112: FALTANDO — a condição `and customer.tier != 'trial'`
#       parece uma exceção especial — qual é a regra de negócio?

Usar LLM para identificar o que está faltando ser documentado é mais valioso do que usar para gerar documentação. O LLM encontra os pontos de confusão; o engenheiro fornece o contexto; o LLM escreve o texto final.

Go — changelog a partir de git log com categorização
// Instrução ao LLM (com git log colado):
//
// "Dado o git log abaixo (últimas 2 semanas), gere um
//  CHANGELOG.md no formato Keep a Changelog (keepachangelog.com).
//
//  Agrupe por categoria:
//  - Added: funcionalidades novas
//  - Changed: mudanças em funcionalidades existentes
//  - Fixed: correções de bug
//  - Removed: funcionalidades removidas
//  - Security: correções de segurança
//  - Deprecated: funcionalidades marcadas para remoção
//
//  Regras:
//  - Ignore commits de merge, bump de versão, e 'fix typo'
//  - Para commits ambíguos, prefira a categoria mais conservadora
//  - Tom: frases curtas, voz ativa, do ponto de vista do usuário
//    ('Adiciona paginação cursor-based em GET /orders' não
//     'Implementa CursorPaginationMiddleware em handlers/orders.go')
//  - Se um commit não é claro o suficiente para categorizar,
//    liste separadamente para eu revisar"
//
// git log --oneline --no-merges --since="2 weeks ago":
// a1b2c3d feat: add cursor-based pagination to orders endpoint
// d4e5f6g fix: race condition in payment processing
// h7i8j9k refactor: extract discount calculator
// l0m1n2o security: upgrade jwt library to fix CVE-2024-1234
// p3q4r5s chore: bump go version to 1.24
// t6u7v8w fix: typo in error message
// ...

Changelogs gerados por LLM a partir de commits são mais consistentes do que changelogs escritos manualmente e mais completos do que "o que o time lembrou de mencionar". A qualidade dos commits de entrada determina a qualidade do changelog.

Docstrings e comentários: quando gerar e quando não gerar

A questão de quando gerar docstrings automaticamente tem uma resposta que parece contraintuitiva: para código de domínio complexo, docstrings geradas por LLM geralmente não valem o espaço que ocupam. Para APIs públicas expostas a consumidores externos, valem muito.

Para código de domínio complexo, a regra é: um comentário que descreve o quê o código faz é sempre pior do que código que se explica pelo naming. Se o código precisa de comentário para explicar o quê, o código está mal-nomeado. Se o comentário explica o porquê — uma restrição não-óbvia, um workaround para bug de dependência, uma decisão de design — então agrega valor real e não pode ser gerado automaticamente.

Para APIs públicas, a situação é diferente: os consumidores podem não ter acesso ao código, precisam de exemplos de uso, e a consistência da documentação afeta a adoção. Aqui, LLMs geram rascunhos úteis: descrição de parâmetros, valores de retorno, exceções possíveis, exemplos básicos de uso. O engenheiro adiciona os casos de uso específicos, as restrições não-óbvias, e as advertências que os consumidores precisam saber.

O critério prático: gerar docstrings para funções públicas que fazem parte de uma API consumida por outros (outros times, clientes externos, biblioteca open-source). Não gerar para funções privadas internas a um módulo onde o código bem-nomeado é suficiente. Para funções públicas complexas com invariantes não-óbvias, o engenheiro escreve os comentários de porquê; o LLM pode ajudar a estruturar o texto.

Documentação técnica de longa duração

Além de comentários e docstrings, há a documentação técnica de longa duração: arquitetura do sistema, guias de onboarding, runbooks de operação, post-mortems, RFCs. LLMs são úteis em diferentes graus para cada tipo.

Para arquitetura: LLMs podem gerar rascunhos de diagramas C4 em formato Mermaid ou PlantUML a partir de descrição verbal, ajudar a estruturar documentos de arquitetura, e identificar inconsistências entre o que está documentado e o que está no código. A substância — as decisões arquiteturais, os trade-offs, os componentes reais — precisa vir do engenheiro.

Para runbooks de operação: dado o procedimento que o engenheiro descreve, o LLM pode estruturá-lo no formato padrão, adicionar seções que o engenheiro esqueceu (verificação de pré-condições, rollback, notificação de stakeholders), e tornar as instruções mais claras. Runbooks precisam ser testados — não só escritos — e o teste precisa ser feito por humanos.

Para post-mortems blameless: LLMs podem ajudar a estruturar a narrativa do incidente a partir de um log de eventos, identificar padrões de causa raiz em múltiplos post-mortems ("essa categoria de problema apareceu 3 vezes nos últimos 6 meses"), e garantir que o documento segue o formato do time. A análise de causa raiz e os action items precisam vir de quem esteve no incidente — o LLM não estava.

Como praticar

  1. Auditoria de documentação de porquê. Escolha um módulo do projeto atual com código não-trivial. Use LLM para listar todos os lugares onde há código que parece não-óbvio mas não tem comentário de porquê. Para cada item da lista, escreva o porquê real (você sabe — é o seu código). Use LLM para transformar suas respostas em comentários ou docstrings bem estruturados. Compare o resultado com o que o LLM teria gerado sem seu input de contexto.
  2. ADR via bullet points. Para uma decisão técnica que você tomou recentemente e não documentou, escreva os bullet points: o problema, as alternativas consideradas, o porquê da escolha, os trade-offs aceitos. Passe os bullets para o LLM e peça um ADR estruturado. Revise se o ADR captura fielmente sua decisão sem inventar informação. Esse exercício calibra o protocolo de "engenheiro fornece contexto, LLM estrutura".
  3. Identificar documentação desatualizada. Pegue um módulo que passou por mudanças nos últimos três meses e ainda tem documentação escrita antes das mudanças. Use LLM para comparar o código atual com a documentação e identificar inconsistências. Quantas inconsistências o LLM encontrou? Quantas você conhecia? Quantas eram invisíveis sem comparação explícita? Esse número calibra o quanto sua documentação está se deteriorando e com que frequência auditoria de consistência deve ser feita.

Referências para aprofundar

  1. livro A Philosophy of Software Design — John Ousterhout (2018). O capítulo sobre documentação é o argumento mais claro de por que comentários devem explicar o porquê, não o quê. A fundação conceitual para avaliar quando LLMs ajudam e quando produzem ruído.
  2. livro Clean Code — Robert C. Martin (2008). Capítulo 4 sobre comentários: quando são necessários e quando são sinal de código mal-nomeado. O framework para decidir quando gerar docstring agrega valor versus polui.
  3. artigo Keep a Changelog — Olivier Lacan. keepachangelog.com — O formato padrão de changelog que o exercício de geração por LLM usa. Entender o formato é necessário para instruir o LLM a produzi-lo corretamente.
  4. artigo ADR: Architecture Decision Records — Michael Nygard (2011). cognitect.com/blog — O artigo original que propôs ADRs. O formato que LLMs ajudam a produzir quando o engenheiro fornece o conteúdo de decisão real.
  5. docs OpenAPI Specification — Description Objects — OpenAPI Initiative. spec.openapis.org — A estrutura de documentação que LLMs preenchem bem dado um schema. Entender o que pode ser expresso no schema determina o que pode ser gerado automaticamente.
  6. artigo Docs as Code — Anne Gentle. docsascode.com — A metodologia de tratar documentação como código: versionada, revisada em PR, testada. Complementa LLMs para documentação que precisa se manter sincronizada com o código.
  7. artigo The Documentation System — Divio (2017). documentation.divio.com — A taxonomia em quatro tipos: tutoriais, how-to guides, explanations, reference. LLMs são mais úteis em reference (derivável de código) e menos em explanations (requer contexto de decisão).
  8. artigo Using AI for Technical Writing — Tom Johnson (2024). idratherbewriting.com — Perspectiva de technical writer profissional sobre o que LLMs mudam (e não mudam) em escrita técnica. Foco em onde a expertise humana permanece essencial.
  9. vídeo Documentation-Driven Development — Write the Docs (2022). youtube.com — Documentação escrita antes do código como forma de spec. Conecta spec-driven (conceito 02) com documentação — o mesmo princípio de articular intenção antes de implementar.
  10. artigo AI-Generated Documentation: Risks and Best Practices — Hamel Husain (2024). hamel.dev — Análise prática dos riscos de documentação gerada automaticamente, especialmente desatualização silenciosa. Propõe estratégias de mitigação com dados de casos reais.
  11. livro The Google SRE Book — Beyer et al. (2016). Capítulos sobre runbooks e postmortems. O formato que LLMs podem ajudar a estruturar — mas cujo conteúdo (o que aconteceu, por que, o que fazer) só quem operou o sistema tem.
  12. artigo Conventional Commits — conventionalcommits.org. O formato de commits que torna changelog por LLM mais fácil e mais preciso. Adotar Conventional Commits é o investimento que torna a geração automática de changelog uma prática sustentável.