Programação Por Equipe DevBras

Capa do artigo: Comentário bom explica por que, não repete o que a linha já diz

Comentário bom explica por que, não repete o que a linha já diz

Aprenda a separar o comentário que envelhece mentindo do que salva a próxima pessoa: restrição externa, regra de negócio, contorno com prazo. Com exemplos em Python antes e depois.

A linha diz TIMEOUT_COTACAO_S = 2 e o comentário ao lado diz "timeout de 2 segundos". Um ano depois, alguém acha 2 segundos pouco, troca para 10 e esquece o comentário. Agora o código diz 10, o comentário diz 2, e nenhum dos dois diz o que importava: a transportadora encerra a conexão em 3 segundos, então esperar 10 só prende o checkout enquanto o cliente olha um spinner.

A resposta curta: comente o porquê, não o quê. O que a linha faz, o código já diz. O comentário que vale guarda o que o código não consegue mostrar: uma restrição externa, a regra de negócio e sua origem, o incidente que motivou a decisão, o contorno temporário e quando ele pode sair. Comentário que repete o código envelhece mentindo; apague-o ou troque por um nome melhor.

Por que o comentário que repete o código é pior do que nenhum

Código é executado e testado. Comentário não. Quando alguém muda a lógica, o teste quebra se a lógica estiver errada, mas nada quebra se o comentário ficou desatualizado. Com o tempo, todo comentário que descreve o mecanismo diverge do mecanismo.

A PEP 8, o guia de estilo do Python, diz isso de forma direta: comentário que contradiz o código é pior do que nenhum comentário, e mantê-lo atualizado deve ser prioridade quando o código muda. O problema é que comentário redundante dá trabalho de manter e não devolve nada, então ninguém mantém.

Já o porquê muda pouco. A transportadora cortar em 3 segundos é um fato do contrato, não da implementação. Você pode reescrever a função inteira, trocar de biblioteca HTTP, e o motivo continua valendo. Por isso esse tipo de comentário envelhece bem.

Antes e depois no mesmo módulo

O exemplo é o módulo de cotação de frete de uma loja. Primeiro, a versão com comentários que só narram:

import requests

# timeout de 2 segundos
TIMEOUT_COTACAO_S = 2

def cotar_frete(cep, peso_g):
    # monta a url
    url = "https://api.transportadora.exemplo/v2/cotacao"
    # faz a requisição
    resposta = requests.post(url, json={"cep": cep, "peso": peso_g}, timeout=TIMEOUT_COTACAO_S)
    # verifica o status
    resposta.raise_for_status()
    # arredonda para cima
    peso_kg = -(-peso_g // 1000)
    return resposta.json()["valor"], peso_kg

Cada comentário repete a linha seguinte. Nenhum responde às perguntas que alguém faria ao mexer aqui: por que 2 segundos? Por que arredondar o peso para cima? Agora a versão que guarda o porquê:

import requests

# A transportadora encerra a conexão em 3 s (documentação da API v2).
# Com 2 s sobra margem para uma segunda tentativa antes de o checkout
# desistir e mostrar o frete padrão.
TIMEOUT_COTACAO_S = 2

URL_COTACAO = "https://api.transportadora.exemplo/v2/cotacao"

def cotar_frete(cep, peso_g):
    resposta = requests.post(
        URL_COTACAO,
        json={"cep": cep, "peso": peso_g},
        timeout=TIMEOUT_COTACAO_S,
    )
    resposta.raise_for_status()
    return resposta.json()["valor"], peso_cobrado_kg(peso_g)

def peso_cobrado_kg(peso_g):
    # A tabela da transportadora cobra por quilo iniciado: 1.001 g paga 2 kg.
    return -(-peso_g // 1000)

Sobraram dois comentários, e os dois guardam informação que não estava em lugar nenhum do código. O resto virou nome: a URL ganhou uma constante, e o cálculo do peso ganhou uma função cujo nome diz o que ela entrega. O truque -(-peso_g // 1000) é divisão inteira arredondando para cima; o comentário explica a regra de negócio, não a aritmética.

A escolha do timeout também tem um motivo técnico que vale um comentário quando não for óbvio para a equipe: a biblioteca requests não aplica timeout por padrão, então sem esse parâmetro a chamada pode esperar indefinidamente, o problema descrito no guia de timeout antes do infinito.

Os comentários que merecem existir

  1. Restrição externa: limite do fornecedor, comportamento de um navegador, exigência de um órgão. "A Sefaz recusa lotes com mais de N notas" (com o N que você conferiu na documentação).
  2. Regra de negócio com origem: "Desconto máximo de 15% definido pelo financeiro em 2026, ver chamado FIN-212". Quem quiser mudar sabe com quem falar.
  3. Incidente que motivou a decisão: "Ordenar por id e não por data: duas notas com o mesmo segundo duplicaram a exportação no incidente de março".
  4. Contorno temporário com condição de saída: "A versão 4.2 da biblioteca de PDF corta a última linha; remover este ajuste quando atualizarmos". Sem a condição, o contorno vira permanente.
  5. Aviso de "não simplifique": quando a forma óbvia já foi tentada e falhou. "Não trocar por cache: o preço muda durante a promoção relâmpago".
  6. Documentação de interface pública: docstring dizendo o que a função recebe, devolve e que exceções lança, para quem vai chamar sem ler o corpo.

Os comentários que devem sair

  • Paráfrase da linha: "incrementa i", "retorna o usuário".
  • Código comentado: o histórico do Git guarda a versão antiga com data, autor e motivo. Bloco comentado no arquivo só confunde quem lê.
  • Diário de alterações no topo do arquivo: "12/03 Fulano alterou X". Isso é o que o git log faz, e faz melhor.
  • Comentário de seção numa função gigante: "# valida cliente", "# calcula imposto", "# grava". Cada um desses blocos é uma função esperando um nome.

O último item merece atenção. Quando você sente necessidade de dividir uma função de oitenta linhas com comentários de seção, o comentário está compensando um desenho ruim. Extraia cada bloco numa função com nome que diga o efeito, como mostra o post sobre nome que não mente. O comentário some e a leitura melhora.

Um teste rápido para cada comentário

Antes de escrever ou manter um comentário, faça duas perguntas. Primeira: se eu apagar esta linha de comentário, alguém perde informação que não consegue recuperar lendo o código? Se não perde, apague. Segunda: se o código mudar de implementação amanhã, este comentário continua verdadeiro? Se não continua, provavelmente está descrevendo o quê, e não o porquê.

No review, aplique o mesmo filtro ao diff. Uma mudança que altera a lógica e deixa o comentário vizinho intocado merece uma pergunta: o comentário ainda vale?

Erros comuns

  • Narrar cada linha: o arquivo dobra de tamanho, ninguém atualiza, e em meses os comentários descrevem outro programa.
  • Deixar código comentado "por segurança": quem lê não sabe se aquilo é para voltar, se foi esquecido ou se é a versão certa.
  • Usar comentário para justificar função enorme: o problema de estrutura continua, agora com texto em cima.
  • Contorno sem condição de saída: o ajuste temporário vira regra permanente que ninguém tem coragem de remover.
  • Regra de negócio sem origem: quem precisa mudar o número não sabe se foi decisão, lei ou chute, e não mexe ou mexe errado.
  • Corrigir o código e não o comentário ao lado: a próxima pessoa confia no texto, que é o que se lê primeiro, e erra com confiança.

Checklist

  • Todo número mágico tem nome ou comentário dizendo de onde vem.
  • Nenhum comentário repete em português o que a linha seguinte faz.
  • Não há blocos de código comentado no arquivo.
  • Todo contorno temporário diz quando pode ser removido.
  • Regras de negócio citam a origem: chamado, documento ou área responsável.
  • Funções públicas têm docstring com entrada, saída e exceções.
  • No review, mudanças de lógica são conferidas contra os comentários vizinhos.

Abra o arquivo que você mais editou este mês e apague mentalmente todos os comentários: o código ainda se explica, e os comentários que você sentiria falta são justamente os que dizem por quê?

Avalie este artigo

Referência: https://www.python.org/dev/peps/pep-0008/#comments