17 de julho de 2010

// Não comente seu código

Você usa desodorante nas axilas? Se usa, provavelmente o faz por causa do mau cheiro produzido pelas suas glândulas sudoríparas dessa região.

É por um motivo semelhante que muitos programadores escrevem comentários. Seu código é difícil de compreender, por isso precisa ser comentado. Mas se o código ruim fosse refatorado até se tornar um bom código, a maioria dos comentários seriam desnecessários.

1 - Comentários como desodorante

Com a ajuda do Martin Fowler no seu livro sobre refatoração, me dei conta de que muitos dos comentários que eu escrevia no passado eram usados para minimizar os efeitos de um código ruim (do ponto de vista da clareza, não da eficiência). O código ruim, segundo Fowler, cheira mal e os comentários, neste caso, agem como desodorante. A seguir, alguns desses maus usos de comentários.

1.1 - Para compensar a má nomeação de identificadores

Se você sentir a necessidade de comentar pra que serve uma váriável, constante, função, parâmetro de função, atributo, classe ou método*, provavelmente o nome que você deu ao identificador não é um bom nome.

Sem ser dogmático, sugiro o seguinte:

'Quando você sentir a necessidade de escrever um comentário para explicar o que faz ou pra que serve determinado identificador, transforme o comentário que você escreveria no nome do identificador.' (uma adaptação de algumas frases do Fowler)

Transformar um comentário curto em um nome de variável é fácil (a menos que você use uma variável para várias coisas diferentes). Mas, transformar um comentário de várias linhas em um nome de função dará mais trabalho, porém, neste caso, os comentários longos são consequência de um outro problema: funções longas.

1.2 - Para compensar a escrita de funções longas

Quem escreve uma função com muitas linhas, normalmente sente a necessidade de adicionar um comentário junto à declaração da função para explicar as coisas que ela faz. No corpo de funções desse tipo, também é comum encontrar comentários para explicar certos agrupamentos de código. Em ambos os casos, os comentários são um indício de que o código não está suficientemente claro.

Ao invés de se eximir da responsabilidade pelo mau código atrás de comentários, refatore o código desmembrando a função longa em várias funções menores. Se há comentários ao longo do corpo da função, esses comentários dão uma dica do que pode ser extraído e do nome que você pode dar a cada função extraída.

Laços com muitas linhas de código dentro de uma função são terríveis para compreender, especialmente laços aninhados. Se você reduzir o número de linhas dentro de um laço de forma que possa observar sem usar scroll onde começa e onde termina o laço, seu código será mais fácil de compreender.

1.3 - Para explicar o uso de strings e números literais

Strings e números literais são valores escritos diretamente no código. Por exemplo, em certo programa, pode ser convencionado que os tipos de inscrição CPF e CNPJ serão representados pelos inteiros 1 e 2, respectivamente. Se o programador decidir usar os literais 1 e 2 em todo código que lide com os tipos de inscrição, ele provavelmente compensará isso com o uso de comentários. Exemplo (em Java):

/* Exemplo A */
String getInscricaoFormatada1(int tipoInscricao, String inscricao) {

  if (tipoInscricao==1) /* 1=CPF */
    return formatarTexto("999.999.999-99", inscricao);
  else if (tipoInscricao==2) /* 2=CNPJ */
    return formatarTexto("99.999.999/9999-99", inscricao);
  else
    return inscricao;
}

Apesar de o código acima permitir uma fácil compreensão, o próximo código - que não usa comentários - tende a ser mais adequado.

/* Exemplo B */
static final int TIPO_INSCRICAO_CPF = 1;
static final int TIPO_INSCRICAO_CNPJ = 2;

String getInscricaoFormatada2(int tipoInscricao, String inscricao) {

  if (tipoInscricao == TIPO_INSCRICAO_CPF)
    return formatarTexto("999.999.999-99", inscricao);
  else if (tipoInscricao == TIPO_INSCRICAO_CNPJ)
    return formatarTexto("99.999.999/9999-99", inscricao);
  else
    return inscricao;
}

A alternativa "B" é preferível porque, além de dispensar o uso de comentários, evita erros. Se você digitar incorretamente o nome de uma constante ao fazer uso dela, o compilador perceberá, enquanto ele não poderá ajudar se você fizer uso de um literal incorreto.

3 - Quando usar comentários?

Tudo bem se você achar que estou sendo contraditório neste tópico por causa do título que escolhi para o artigo. A verdade é que eu gosto dos comentários, desde que não sejam usados como desodorante. Aqui vão alguns dos usos que considero adequados.

3.1 - Para organizar o pensamento sobre o código

Quando não uso um quadro ou papel para rascunhar o que vou codificar, uso comentários para criar uma lista de passos que preciso seguir para atingir o objetivo do código. Esses passos não precisam ser precisos, apenas precisam ser "persistidos" em algum lugar para que eu não esqueça deles. À medida que os passos são concluídos, removo os comentários, pois nesse ponto se tornam irrelevantes.

3.2 - Para marcar código duvidoso, passível de melhora ou incompleto

Há casos em que algumas suposições precisam ser temporariamente assumidas como verdadeiras para que a codificação flua sem empecilhos. Nestes casos, é útil marcar o código duvidoso com um comentário precedido por um "TODO" ("fazer", em inglês). O mesmo se dá com códigos passíveis de melhora ou incompletos. Alguns exemplos:

  /* TODO: confirmar se o DV da conta é calculado com módulo 10 */
  /* TODO: refatorar este código para remover as duplicações /*
  /* TODO: validar campos obrigatórios antes de gravar /*

PS: IDE's de desenvolvimento modernas permitem a fácil localização dos comentários marcados com "TODO".

3.3 - Para explicar porque você fez algo

Há certas ocasiões em que você precisa explicar porque fez algo no código - especialmente quando isso torna o código mais complexo. Quando não é óbvio o porquê de uma decisão e você não esclarece isso com comentários, há o risco de que algum programador, ao assumir o seu trabalho, torne o código mais simples - o que pode levar a falhas que ele não tem condições de prever ou a um mau desempenho.

Um bom exemplo é um comentário escrito por nada menos que Linus Torvalds num arquivo fonte do Git (em C) para justificar a criação de um alocador de memória especializado ao invés de utilizar a função malloc() padrão:

  /*
   * alloc.c  - specialized allocator for internal objects
   *
   * Copyright (C) 2006 Linus Torvalds
   *
   * The standard malloc/free wastes too much space for objects, partly
   * because it maintains all the allocation infrastructure (which isn't
   * needed, since we never free an object descriptor anyway), but even
   * more because it ends up with maximal alignment because it doesn't
   * know what the object alignment for the new allocation is.
   */

Conclusão

Para encerrar, duas ótimas citações:

"Qualquer tolo consegue escrever código que um computador entenda. Bons programadores escrevem código que humanos possam entender." (Martin Fowler)
"Sempre codifique como se o programador que vai dar manutenção no seu código fosse um serial killer maníaco que sabe onde você mora." (autor desconhecido)

Gostou do que leu? Deixe seu /*comentário*/.

* ^ A rigor, variável e atributo são coisas diferentes, assim como função e método. Mas, para fins de simplificação, quando eu disser "variável", estarei me referindo também a "atributo" e quando disser "função" estarei me referindo também a método.

Crédito da foto: George Marks

Referências:

Postar um comentário