Pular para o conteúdo
Atualizado em 13 min de leitura

Comentários no código: quando ajudam e quando são cheiro

Por Lucas Andrade ·

Comentário não é sempre virtude. Entenda quando ele esclarece o porquê e quando denuncia código confuso, comentando o óbvio ou mentindo com o tempo.

Neste artigo

Poucos hábitos de programação são ensinados com tanta convicção e tão pouca nuance quanto o de comentar código. Muita gente aprende, cedo na carreira, que comentar é sempre bom, que um código "bem documentado" é aquele cheio de anotações, e que a diligência de um bom profissional se mede pela quantidade de explicações que ele deixa pelo caminho. Essa crença, bem-intencionada, produz alguns dos códigos mais poluídos e enganosos que existem, porque parte de uma premissa equivocada: a de que o comentário e o código são aliados naturais.

Na prática, comentário e código competem. Toda vez que você escreve uma frase em português explicando o que uma linha faz, você está admitindo, ainda que sem perceber, que a linha por si só não conseguiu comunicar sua intenção. Às vezes essa admissão é legítima e o comentário é a melhor ferramenta disponível. Muitas outras vezes, porém, ela é um sintoma de que o próprio código poderia ter sido escrito de forma mais clara, e o comentário está apenas remediando uma falha de expressão que deveria ter sido resolvida na origem.

Este artigo propõe uma postura mais madura diante dos comentários: tratá-los como último recurso, não como primeiro. Vamos entender por que o código autoexplicativo é preferível, por que comentários envelhecem e mentem, quais são os usos genuinamente bons, quais são os maus usos que só geram ruído, e por que, em muitos casos, um comentário é menos uma virtude e mais um cheiro que aponta para um problema estrutural.

O comentário como último recurso#

A regra de ouro que orienta desenvolvedores experientes é simples de enunciar e difícil de internalizar: antes de escrever um comentário, tente reescrever o código para que ele não seja necessário. O comentário deveria ser aquilo que sobra quando você já esgotou os recursos de expressão da própria linguagem, e não o primeiro reflexo diante de um trecho complicado.

A razão dessa hierarquia é que o código é verificado pela máquina e o comentário não é. Quando você renomeia uma variável para revelar seu propósito, extrai uma função com um nome descritivo ou reorganiza uma condição para deixar a intenção explícita, essa clareza fica travada dentro da estrutura do programa. Ela não pode divergir da realidade, porque é a realidade. Já o comentário flutua livre ao lado do código, sem nenhum vínculo obrigatório com o que a máquina de fato executa.

Considere o impulso de escrever algo como "verifica se o usuário é maior de idade" acima de uma condição. Se, em vez disso, a condição comparar uma idade contra uma constante chamada IDADE_MINIMA_LEGAL, o comentário se torna redundante, porque o código já diz aquilo em voz alta. O esforço que iria para a frase explicativa foi redirecionado para tornar o próprio programa mais legível, e o resultado é superior justamente porque não depende de ninguém manter duas fontes de verdade em sincronia.

Isso não significa que comentários sejam proibidos ou indesejáveis por natureza. Significa apenas que a sequência correta é primeiro exaurir a expressividade do código e só então, para o que restou, recorrer ao comentário. Invertendo essa ordem, você acaba comentando o que deveria ter sido reescrito e deixando de reescrever o que só o comentário conseguiria explicar.

Código autoexplicativo vem antes#

A ideia de código autoexplicativo é frequentemente mal compreendida como uma proibição religiosa a qualquer comentário. Não é isso. Código autoexplicativo é o compromisso de fazer o programa comunicar sua própria intenção pelos meios que a linguagem oferece, reservando o comentário para aquilo que a linguagem genuinamente não alcança.

Os meios são conhecidos. Nomes descritivos de variáveis, funções e tipos carregam significado sem custo de manutenção adicional. A extração de funções pequenas transforma um bloco obscuro em uma sequência de chamadas cujos nomes contam a história do algoritmo. A decomposição de condições complexas em variáveis booleanas intermediárias, com nomes que revelam o critério, substitui a necessidade de explicar em prosa o que aquela expressão booleana representa.

Quando essas técnicas são aplicadas com disciplina, uma parcela enorme dos comentários que antes pareciam indispensáveis simplesmente desaparece, não porque a informação foi perdida, mas porque ela migrou para dentro do código, onde é mais durável. O leitor deixa de precisar alternar entre a explicação em português e a implementação em código, reconciliando as duas na cabeça, e passa a ler uma coisa só, coerente consigo mesma.

Há um limite claro, no entanto. Nem tudo cabe no código. O código expressa muito bem o "o quê" e o "como", mas é péssimo para expressar o "porquê". Ele não tem como registrar por que uma decisão foi tomada em detrimento de outra, que restrição externa obrigou uma escolha estranha, ou que armadilha um trecho aparentemente inofensivo esconde. É exatamente nesse território, o do porquê, que o comentário deixa de ser um remendo e passa a ser insubstituível.

Comentários que mentem e envelhecem#

O problema mais insidioso dos comentários é que eles apodrecem. O código é executado, testado e revisado o tempo todo; qualquer divergência entre o que ele deveria fazer e o que faz tende a aparecer. O comentário não passa por nenhum desses filtros. Ele pode contradizer o código ao lado dele por anos sem que ninguém perceba, porque nenhuma máquina o verifica e nenhum teste o quebra.

O ciclo é conhecido de qualquer pessoa que já manteve um sistema antigo. Alguém escreve um comentário fiel ao código no momento em que o escreve. Meses depois, outra pessoa altera a lógica por baixo, corrige um bug, muda um limite, inverte uma condição, e, na pressa, esquece de atualizar o comentário. A partir dali, existe uma frase explicativa que descreve um comportamento que o programa não tem mais. O comentário virou uma mentira, e uma mentira especialmente perigosa, porque tem a aparência de autoridade.

Um comentário desatualizado é pior do que nenhum comentário. A ausência de comentário obriga o leitor a ler o código, que é a fonte da verdade. A presença de um comentário falso convida o leitor a confiar nele e a tomar decisões com base em uma descrição incorreta, o que produz bugs sutis e desperdício de tempo em investigações que partem de premissas erradas. É por isso que cada comentário que você escreve é também uma dívida de manutenção: alguém terá de mantê-lo em sincronia com o código para sempre.

Essa fragilidade reforça a hierarquia proposta. Informação que pode viver no código, dentro de nomes e estrutura, é imune a esse apodrecimento, porque muda junto com o programa. Informação que precisa viver em comentário deve ser aquela que vale o risco: o porquê raro e importante, não a repetição preguiçosa do que a linha já diz.

Os bons usos: quando o comentário é insubstituível#

Existe um conjunto de situações em que o comentário não é um remendo, mas a ferramenta certa, e reconhecê-las é tão importante quanto evitar os maus usos. O denominador comum de todos os bons comentários é que eles agregam informação que o código, por sua natureza, não consegue carregar.

  • O porquê de uma decisão. O código mostra o que foi feito; o comentário registra por que foi feito assim e não de outro jeito. "Usamos ordenação estável aqui porque a interface depende de manter a ordem de inserção em empates" é o tipo de contexto que nenhum nome de variável expressa, e que evita que um futuro mantenedor "otimize" para uma solução que quebra um requisito invisível.
  • Decisões contraintuitivas. Quando o código parece errado mas está certo, um comentário curto explicando a razão poupa horas de alguém tentando "consertar" o que já está correto. Uma multiplicação por um fator estranho, uma ordem de operações incomum, um caso especial tratado de forma diferente: tudo isso pede uma linha de justificativa.
  • Avisos de consequência. "Não chame isto dentro de um laço, o custo é quadrático" ou "alterar esta ordem quebra a compatibilidade com clientes antigos" são comentários que protegem o leitor de armadilhas que ele não teria como prever só olhando a estrutura.
  • TODO com contexto. Um marcador de pendência só é útil se disser o que falta, por que ficou para depois e, idealmente, sob que condição deve ser retomado. Um TODO solto, sem dono nem critério, é lixo; um TODO que explica a dívida e aponta o caminho é documentação honesta de uma decisão consciente.
  • Documentação de API pública. Na fronteira que outros vão consumir, a docstring que descreve contrato, parâmetros, valores de retorno, efeitos colaterais e condições de erro é parte da interface, não ruído. Quem usa a função não deveria precisar ler sua implementação para saber como chamá-la com segurança.

O que une esses casos é que o comentário fala de algo que está fora do alcance do código: intenção histórica, restrição externa, contrato de uso, risco não óbvio. Ele complementa o código em vez de repeti-lo, e por isso ganha o direito de existir.

Os maus usos: ruído, redundância e código morto#

Do outro lado estão os comentários que só degradam a base de código. O mais comum é o comentário redundante, aquele que traduz para o português o que a linha de código já diz com clareza. Escrever "incrementa o contador em um" acima de uma linha que soma um a um contador não adiciona informação nenhuma; apenas dobra o volume de texto a ser lido e cria mais uma coisa que pode ficar desatualizada.

Esse tipo de comentário nasce do hábito mecânico de comentar por comentar, como se a quantidade de anotações fosse por si só uma medida de qualidade. O efeito é o oposto: o excesso de ruído afoga os poucos comentários que realmente importam. Quando cada linha tem uma explicação óbvia ao lado, o leitor aprende a ignorar todos os comentários, inclusive aquele único que carregava o aviso crucial.

Outro mau uso clássico é o código comentado, deixado no arquivo "para o caso de precisar depois". Esse hábito é um resquício de uma época sem controle de versão. Hoje, o histórico do repositório guarda qualquer código que já existiu; deixar blocos inteiros comentados no arquivo só polui a leitura, gera dúvida sobre se aquilo ainda é relevante e faz o leitor perder tempo tentando entender por que um trecho aparentemente importante está desativado. Código que não é mais usado deve ser removido, não sepultado em comentários.

Há ainda o ruído dos comentários decorativos e dos cabeçalhos vazios, aquelas caixas de asteriscos e separadores que prometem estrutura mas não dizem nada, e os comentários que documentam o autor e a data em cima de cada função, informação que o controle de versão já registra com precisão muito maior. Tudo isso ocupa espaço, cansa a vista e não paga o custo que impõe.

O comentário como cheiro de código#

A forma mais avançada de pensar sobre comentários é enxergá-los, em muitos casos, como um cheiro, um sintoma de que algo no código poderia estar melhor. Quando você sente a necessidade de explicar em prosa o que um bloco faz, vale a pena parar e perguntar por que aquele bloco não consegue se explicar sozinho.

Frequentemente, a resposta é que ele está fazendo coisas demais. Um comentário do tipo "primeiro validamos, depois calculamos, depois persistimos" costuma ser um mapa das funções que deveriam existir. Cada frase daquele comentário-roteiro é candidata a virar uma função com aquele nome, transformando a explicação em estrutura verificável. O comentário, nesse caso, foi útil, mas como diagnóstico: ele revelou uma função longa demais que pedia decomposição.

O mesmo vale para o comentário que explica uma expressão booleana complicada. A necessidade da explicação denuncia que a expressão é obscura, e a cura não é a frase em português, e sim uma variável intermediária com nome revelador ou uma pequena função de predicado. Quando você aplica a refatoração sugerida pelo cheiro, o comentário deixa de ser necessário, porque a informação que ele carregava passou a viver no código.

Isso não transforma todo comentário em cheiro, e é importante não cair no extremo oposto, o do fanatismo que proíbe qualquer anotação. O porquê, o aviso e o contrato de API continuam legítimos. Mas o comentário que explica o "como" quase sempre é um sinal de que o "como" poderia ser mais claro, e tratá-lo como sintoma, e não como solução, é o que separa quem apenas comenta de quem escreve código que dispensa comentários.

Docstrings e a fronteira da documentação#

As docstrings ocupam uma posição especial nesse debate, porque não são comentários internos de implementação, e sim documentação de interface. A docstring de uma função pública, de um módulo ou de uma classe descreve o contrato daquilo para quem vai consumir, e esse público muitas vezes nunca vai ler o corpo da implementação. Aqui, a lógica do "código autoexplicativo" tem alcance limitado, porque a assinatura sozinha raramente comunica tudo o que o consumidor precisa saber.

Uma boa docstring diz o que a função faz em termos de resultado observável, quais são as pré-condições sobre os parâmetros, o que ela retorna, quais efeitos colaterais provoca e em que situações falha ou levanta erro. Ela descreve o "o quê" e o contrato, não o "como" da implementação, justamente porque o como pode mudar sem que o contrato mude, e amarrar a documentação aos detalhes internos a tornaria frágil.

Vale notar que docstrings também apodrecem, e que a disciplina de mantê-las fiéis ao comportamento real é parte do custo de tê-las. A vantagem é que, por descreverem contrato e não implementação, elas mudam com menos frequência: enquanto a interface for estável, a docstring permanece válida ainda que o interior seja reescrito. Essa estabilidade relativa é o que justifica o investimento nelas mesmo em bases de código que, no restante, perseguem o ideal de dispensar comentários.

Uma postura equilibrada#

Comentar bem não é comentar muito nem comentar pouco; é comentar o que precisa ser comentado e deixar o resto para o código. A postura madura reconhece que a linguagem de programação é a ferramenta primária de comunicação e que o comentário entra em cena quando essa ferramenta chega ao seu limite, para carregar o porquê, o aviso e o contrato que a estrutura não alcança.

Adotar essa postura muda a forma como você revisa código, o seu e o dos outros. Diante de um comentário, a pergunta deixa de ser "está bem escrito?" e passa a ser "isto precisa existir ou é o código que precisa melhorar?". Diante da ausência de comentário em um trecho contraintuitivo, a pergunta é se falta ali um porquê que evitaria uma futura "correção" indevida. Esse escrutínio, aplicado com constância, produz bases de código onde os poucos comentários existentes têm peso, são confiáveis e realmente ajudam, em vez de se perderem num mar de ruído redundante.

No fim, o objetivo não é orgulhar-se de um código sem comentário algum nem de um código coberto de anotações, mas de um código honesto, onde cada palavra em português está lá porque nenhuma linha de código conseguiria dizer aquilo, e onde tudo o que podia ser dito em código foi. Esse equilíbrio é discreto, quase invisível para quem lê, e é exatamente essa invisibilidade que denuncia que ele foi bem-feito.

Leituras relacionadas

Nenhum comentário ainda

Seja o primeiro a comentar.

Deixe seu comentário

Entre com sua conta Canverly para comentar. Você pode usar a mesma conta em qualquer site da rede.

Entrar com Canverly