O código comentado pode ser uma documentação valiosa?

83

Eu escrevi o seguinte código:

if (boutique == null) {
    boutique = new Boutique();

    boutique.setSite(site);
    boutique.setUrlLogo(CmsProperties.URL_FLUX_BOUTIQUE+fluxBoutique.getLogo());
    boutique.setUrlBoutique(CmsProperties.URL_FLUX_BOUTIQUE+fluxBoutique.getUrl());
    boutique.setNom(fluxBoutique.getNom());
    boutique.setSelected(false);
    boutique.setIdWebSC(fluxBoutique.getId());
    boutique.setDateModification(new Date());

    boutiqueDao.persist(boutique);
} else {
    boutique.setSite(site);
    boutique.setUrlLogo(CmsProperties.URL_FLUX_BOUTIQUE+fluxBoutique.getLogo());
    boutique.setUrlBoutique(CmsProperties.URL_FLUX_BOUTIQUE+fluxBoutique.getUrl());
    boutique.setNom(fluxBoutique.getNom());
    //boutique.setSelected(false);
    boutique.setIdWebSC(fluxBoutique.getId());
    boutique.setDateModification(new Date());

    boutiqueDao.merge(boutique);
}

Há uma linha comentada aqui. Mas acho que isso torna o código mais claro, tornando óbvia a diferença entre ife else. A diferença é ainda mais visível com o realce de cores.

Comentar códigos como esse pode ser uma boa idéia?

Alexis Dufrenoy
fonte

Respostas:

109

A maioria das respostas se concentra em como refatorar esse caso específico, mas deixe-me oferecer uma resposta geral para o motivo pelo qual o código comentado geralmente é ruim:

Primeiro, o código comentado não é compilado. Isso é óbvio, mas significa que:

  1. O código pode nem funcionar.

  2. Quando as dependências do comentário mudam, obviamente não será interrompido.

O código comentado é muito "código morto". Quanto mais ele fica lá, mais apodrece e fornece cada vez menos valor ao próximo desenvolvedor.

Segundo, o objetivo não é claro. Você realmente precisa de um comentário mais longo que forneça contexto para o motivo de existirem linhas comentadas aleatoriamente. Quando vejo apenas uma linha de código comentada, tenho que pesquisar como chegou lá apenas para entender por que chegou lá. Quem escreveu isso? O que comprometer? Qual foi a mensagem / contexto de confirmação? Etcetera.

Considere alternativas:

  • Se o objetivo for fornecer exemplos de uso de uma função / API, faça um teste de unidade. Os testes de unidade são um código real e serão interrompidos quando não estiverem mais corretos.
  • Se o objetivo é preservar uma versão anterior do código, use o controle de origem. Prefiro fazer check-out de uma versão anterior do que alternar os comentários em toda a base de código para "reverter" uma alteração.
  • Se o objetivo é manter uma versão alternativa do mesmo código, use o controle de origem (novamente). Afinal, é para isso que servem os ramos.
  • Se o objetivo é esclarecer a estrutura, considere como você pode reestruturar o código para torná-lo mais óbvio. A maioria das outras respostas são bons exemplos de como você pode fazer isso.
Chris Pitman
fonte
5
Acho que falta um motivo importante: Documentação: Se o objetivo é documentar opções alternativas de design, deve ser fornecida uma explicação da alternativa e, principalmente, o motivo pelo qual ela foi descartada, em vez do código original.
Sarien
14
As opções de design são melhor explicadas em uma linguagem humana do que em uma linguagem de programação.
Mark E. Haase
3
Como seria possível para desenvolvedores subsequentes assumirem meu projeto saberem que existe uma implementação alternativa / anterior / com falha no controle de origem? Espera-se que os novos desenvolvedores passem por todos os históricos de versões e logs de alterações? Ou é uma prática comum usar o comentário para vincular ao hash de um commit anterior para cada implementação alternativa útil? Se assim for, eu nunca notei.
Moobie 5/09/18
Há uma ressalva nisso. Às vezes, duas abordagens de código equivalentes podem diferir no desempenho e na reatividade, de uma maneira que um seja de desempenho e o outro seja legível. Nesse caso, é aceitável usar a variante de desempenho, mas coloque a variante legível nos comentários, para que seja mais fácil entender a finalidade do código. Às vezes, uma linha de código (comentada) pode ser mais clara do que uma explicação detalhada.
Flater
263

O maior problema com esse código é que você duplicou essas 6 linhas. Depois de eliminar essa duplicação, esse comentário é inútil.

Se você criar um boutiqueDao.mergeOrPersistmétodo, poderá reescrever isso como:

if (boutique == null) {
    boutique = new Boutique();
    boutique.setSelected(false);
}

boutique.setSite(site);
boutique.setUrlLogo(CmsProperties.URL_FLUX_BOUTIQUE+fluxBoutique.getLogo());
boutique.setUrlBoutique(CmsProperties.URL_FLUX_BOUTIQUE+fluxBoutique.getUrl());
boutique.setNom(fluxBoutique.getNom());
boutique.setIdWebSC(fluxBoutique.getId());
boutique.setDateModification(new Date());

boutiqueDao.mergeOrPersist(boutique);

O código que cria ou atualiza um determinado objeto é comum; portanto, você deve resolvê-lo uma vez, por exemplo, criando um mergeOrPersistmétodo. Você certamente não deve duplicar todo o código de atribuição para esses dois casos.

Muitos ORMs criaram suporte para isso de alguma forma. Por exemplo, eles podem criar uma nova linha se idfor zero e atualizar uma linha existente se idnão for zero. A forma exata depende do ORM em questão e, como não estou familiarizado com a tecnologia que você está usando, não posso ajudá-lo.


Se você não deseja criar um mergeOrPersistmétodo, deve eliminar a duplicação de alguma outra maneira, por exemplo, introduzindo um isNewBoutiquesinalizador. Isso pode não ser bonito, mas ainda é muito melhor do que duplicar toda a lógica de atribuição.

bool isNewBoutique = boutique == null;
if (isNewBoutique) {
    boutique = new Boutique();
    boutique.setSelected(false);
}

boutique.setSite(site);
boutique.setUrlLogo(CmsProperties.URL_FLUX_BOUTIQUE + fluxBoutique.getLogo());
boutique.setUrlBoutique(CmsProperties.URL_FLUX_BOUTIQUE + fluxBoutique.getUrl());
boutique.setNom(fluxBoutique.getNom());
boutique.setIdWebSC(fluxBoutique.getId());
boutique.setDateModification(new Date());

if (isNewBoutique)
    boutiqueDao.persist(boutique);
else
    boutiqueDao.merge(boutique);
CodesInChaos
fonte
166

Esta é uma ideia absolutamente horripilante . Não fica claro qual é a intenção. O desenvolvedor comentou a linha por engano? Para testar alguma coisa? O que está acontecendo?!

Além do fato de que vejo 6 linhas absolutamente iguais nos dois casos. Em vez disso, você deve impedir essa duplicação de código. Então ficará mais claro que, em um caso, você também chama setSelected.

JustAnotherUserYouMayKnowOrNot
fonte
9
Acordado. Eu diria que a linha comentada é um comportamento antigo que foi removido. Se for necessário um comentário, ele deve estar em linguagem natural, não em código.
Jules
4
Eu concordo inteiramente! Recentemente, passei horas a fio tentando entender e limpar alguns aplicativos que eu herdei que são quase completamente ilegíveis por causa dessa prática. Ele também inclui código que foi desconectado de todos os outros códigos, mas não removido! Acredito que esse seja o principal objetivo dos sistemas de controle de versão. Tem comentários, bem como as alterações que os acompanham. No final, tive pelo menos duas semanas de trabalho adicionadas ao meu prato em grande parte por causa dessa prática.
bsara
ponto de vista semelhante neste post: Não polua a base de código com código comentado
Nick Alexeev
120

Não, é uma péssima ideia. Com base nesse código, os seguintes pensamentos vêm à minha mente:

  • Esta linha é comentada porque o desenvolvedor a estava depurando e esqueceu de restaurar a linha para seu estado anterior
  • Esta linha é comentada porque já fez parte da lógica de negócios, mas não é mais o caso
  • Esta linha é comentada porque causou problemas de desempenho na produção e o desenvolvedor queria ver qual era o impacto em um sistema de produção

Depois de ver milhares de linhas de código comentado, agora estou fazendo a única coisa sensata quando o vejo: removo-o imediatamente.

Não há razão sensata para fazer check-in do código comentado em um repositório.

Além disso, seu código usa muita duplicação. Sugiro que você otimize isso para facilitar a leitura humana o mais rápido possível.

Dibbeke
fonte
1
No entanto, como me livrei do código duplicado, ele dificilmente pode ser visto como uma otimização.
Alexis Dufrenoy
23
é uma otimização para legibilidade humana
jk.
11
@Traroth, você pode otimizar a velocidade, o uso da memória, o consumo de energia ou qualquer outra métrica, de modo que não vejo que você não possa otimizar a legibilidade (embora, como métrica, seja um pouco mais irregular)
jk.
3
Na verdade, eu quis dizer legibilidade humana. Pequena dica aqui: sua responsabilidade mais importante na programação é o seu código. Então, menos é realmente mais aqui.
Dibbeke
4
O software como um passivo também é tratado em c2.com/cgi/wiki?SoftwareAsLiability A partir daí: "Produzir mais código nem sempre é um ganho. O código é caro para testar e manter, portanto, se o mesmo trabalho puder ser feito com menos código que é uma vantagem. Não comente o código morto, apenas exclua-o. O código comentado torna-se obsoleto e inútil muito rápido; portanto, você pode excluí-lo mais cedo ou mais tarde para perder a confusão. Mantenha bons backups para facilitar . "
Ninjalj 11/03/2013
51

Gostaria apenas de acrescentar à resposta de CodesInChaos, apontando que você pode refatorá-la ainda mais em métodos pequenos . Compartilhar funcionalidades comuns por composição evita os condicionais:

function fill(boutique) {    
  boutique.setSite(site);
  boutique.setUrlLogo(CmsProperties.URL_FLUX_BOUTIQUE+fluxBoutique.getLogo());
  boutique.setUrlBoutique(CmsProperties.URL_FLUX_BOUTIQUE+fluxBoutique.getUrl());
  boutique.setNom(fluxBoutique.getNom());
  boutique.setIdWebSC(fluxBoutique.getId());
  boutique.setDateModification(new Date());
}    

function create() {
  boutique = new Boutique();      
  fill(boutique);
  boutique.setSelected(false);
  return boutiqueDao.persist(boutique);
}

function update(boutique) {
  fill(boutiquie);
  return boutiquieDao.merge(boutique); 
}

function createOrUpdate(boutique) {
  if (boutique == null) {
    return create();
  }
  return update(boutique);  
}
Alexander Torstling
fonte
6
Eu acho que é a sugestão mais limpa aqui.
Alexis Dufrenoy
+1 e também acrescentaria que quanto mais você evitar passar nullobjetos, melhor (acho que essa solução é um bom exemplo).
Nadir Sampaoli 12/03
Eu passaria boutiqueDaocomo entradas para createe update.
Happy Green Kid Naps
Como isso pode funcionar? Como você pode saber quando ligar para criar e quando ligar para atualizar? O código original analisa a boutique e sabe se precisa atualizar ou criar. Isso só não faz nada até que você chamar criar ou atualizar ...
Lyrion
Lyrion: Trivial, vou adicionar esse código também para maior clareza.
Alexander Torstling
27

Embora esse claramente não seja um bom argumento para o código comentado, há uma situação que eu acho que merece:

// The following code is obvious but does not work because of <x>
// <offending code>
<uglier answer that actually does work>

É um aviso para quem vê mais tarde que a melhoria óbvia não é.

Edit: Estou falando de algo pequeno. Se for grande, você explica.

Loren Pechtel
fonte
5
O que há de errado // the following part done like it is because of X? Explique por que você fez algo do jeito que fez, e não por que não fez isso de alguma maneira específica . No seu exemplo particular, elimina a necessidade de potencialmente um grande bloco de código comentado completamente. (Eu não downvote, mas certamente pode ver por que isso iria ficar downvoted.)
um CVn
13
Michael, porque ele deixa claro para outros programadores (e você mesmo dias / semanas / meses posteriores) sim, você fez tentar essa abordagem mais limpo / mais inteligente, mas não, não funcionou por causa de X, de modo que não devem se preocupe em tentar novamente. Eu acho que essa é uma abordagem completamente legítima e aprovamos esta resposta tristemente enterrada.
Garrett Albright
1
@GarrettAlbright: Obrigado, fico feliz em ver alguém entender.
Loren Pechtel 13/03/2013
3
@ LorenPechtel: Não só isso, eu estava escrevendo mais ou menos exatamente o mesmo. Há situações em que é muito, muito útil saber rapidamente quais soluções "óbvias" já foram tentadas sem sucesso e por que elas não funcionam.
JensG
3
Além do código com falha com a explicação, também gostaria de comentar implementações alternativas do código que podem ser mais eficientes em um ambiente de produção diferente. Por exemplo, codifiquei uma versão em tempo exponencial direta de um algoritmo e uma versão em tempo polinomial complexo. Mas na produção atual, né pequeno, e o algo exponencial é muito mais rápido. Se, de alguma forma, nmudar posteriormente, como um desenvolvedor futuro que acompanha o meu projeto saberá de uma implementação diferente do código enterrado nas centenas de confirmações no controle de origem?
Moobie 5/09/18
14

Neste exemplo específico, considero o código comentado muito ambíguo, principalmente pelas razões descritas na resposta de Dibkke . Outros sugeriram maneiras de refatorar o código para evitar até a tentação de fazer isso. No entanto, se isso não for possível por algum motivo (por exemplo, as linhas são semelhantes, mas não suficientemente próximas), eu gostaria de um comentário como:

// Não é necessário desmarcar esta boutique, porque [WHATEVER]

No entanto, acho que há algumas situações em que deixar (ou mesmo adicionar comentários) código não é repreensível. Ao usar algo como MATLAB ou NumPY, geralmente é possível escrever um código equivalente que 1) itera sobre uma matriz, processando um elemento de cada vez ou 2) opera a matriz inteira de uma só vez. Em alguns casos, o último é muito mais rápido, mas também muito mais difícil de ler. Se eu substituir algum código por seu equivalente vetorizado, incorporei o código original em um comentário próximo, como este:

%% O código vetorizado abaixo faz isso:

% for ii in 1:N
%    for jj in 1:N
%      etc.

%, mas a versão da matriz é executada ~ 15x mais rapidamente na entrada típica (MK, 10/03/2013)

Obviamente, é preciso cuidar para que as duas versões realmente façam a mesma coisa e que o comentário permaneça sincronizado com o código real ou seja removido se o código for alterado. Obviamente, as advertências usuais sobre otimização prematura também se aplicam ...

Matt Krause
fonte
"Obviamente, é preciso cuidar para que as duas versões realmente façam a mesma coisa e que o comentário permaneça sincronizado com ..." - aí mesmo, você explicou por que essa não é uma boa ideia.
sleske
1
Bem, isso é um problema com todos os comentários, certo? Alguns códigos vetorizados são suficientemente opacos para que os comentários valham a pena, e ter uma versão "desenrolada" pode ser útil para depuração.
Matt Krause
Verdadeiro. Ainda assim, tentaria manter o comentário o mais breve possível, sem usar o código fonte completo. De qualquer forma, se você tem um exemplo, perguntar como torná-lo melhor seria uma boa pergunta (aqui ou no codereview.se).
sleske
1
No seu último caso, eu manteria as duas variantes de código como código compilável.
CodesInChaos
12

A única vez que vi o código comentado útil foi nos arquivos de configuração, onde o código para todas as opções é fornecido, mas comentado, facilitando a ativação das configurações, removendo apenas os marcadores de comentário:

## Enable support for mouse input:
# enable_mouse = true

Nesse caso, o código comentado ajuda a documentar todas as opções disponíveis e como usá-las. Também é convencional usar os valores padrão por toda parte, portanto o código também está documentando as configurações padrão.

Carl Smith
fonte
7

De um modo geral, o código é apenas auto-documentado para a pessoa que escreveu o código. Se a documentação for necessária, escreva a documentação. É inaceitável esperar que um desenvolvedor novo em uma base de código-fonte se sente sentado lendo milhares de linhas de código para tentar descobrir de alto nível o que está acontecendo.

Nesse caso, o objetivo da linha de código comentada é mostrar a diferença entre duas instâncias do código duplicado. Em vez de tentar documentar a diferença com um comentário, reescreva o código para que faça sentido. Então, se você ainda achar necessário comentar o código, escreva um comentário apropriado.

Mike Van
fonte
2
Isso soa bem verdade. Muitas pessoas (inclusive eu) acham que o código é tão impressionante que não precisa de documentação. No entanto, todos os outros no mundo acham que isso não é nada a menos que seja completamente documentado e comentado.
Ryan Amos
"o código é apenas auto-documentado para a pessoa que escreveu o código " - Escolha um código complexo e não comentado que você escreveu há um ano e tente compreendê-lo em um período limitado de tempo. Você não pode? Opa.
JensG
Eu acho que é um pouco mais sutil. Muitos códigos bem escritos são inteligíveis e podem ser entendidos sem comentários. A questão está tentando descobrir o quadro geral (mesmo em um nível bastante local) quando você tem apenas detalhes intricados para continuar. Os comentários são bons para explicar trechos não óbvios de código, mas quando você tem bons documentos, explicando para que servem cada função, classe e módulo, você precisa de muito menos ajuda para entender a implementação.
Carl Smith
4

Não, o código comentado fica obsoleto e logo é pior do que inútil, geralmente é prejudicial, pois cimenta algum aspecto da implementação, juntamente com todas as suposições atuais.

Os comentários devem incluir detalhes da interface e função pretendida; "função pretendida": pode incluir, primeiro tentamos isso, depois tentamos isso, depois falhamos dessa maneira.

Os programadores que eu vi tentando deixar as coisas nos comentários estão apaixonados pelo que escreveram, não querem perdê-lo, mesmo que não esteja adicionando nada ao produto final.

Grady Player
fonte
2

Pode ser em casos muito raros, mas não como você fez. As outras respostas explicaram muito bem as razões para isso.

Um dos raros casos é uma especificação de modelo RPM que usamos em minha loja como ponto de partida para todos os novos pacotes, principalmente para garantir que nada de importante seja deixado de fora. A maioria, mas nem todos os nossos pacotes têm um pacote contendo fontes com um nome padrão e especificado com uma tag:

Name:           foomatic
Version:        3.14
 ...
Source0:        %{name}-%{version}.tar.gz

Para pacotes sem fontes, comentamos a tag e colocamos outro comentário acima dela para manter o formato padrão e indicar que alguém parou e pensou no problema como parte do processo de desenvolvimento:

Name:           barmatic
Version:        2.71
 ...
# This package has no sources.
# Source0:        %{name}-%{version}.tar.gz

Você não adiciona o código que sabe que não será usado porque, como outros já explicaram, pode ser confundido com algo que pertence a ele. Pode. no entanto, seja útil adicionar um comentário explicando por que falta o código esperado:

if ( condition ) {
  foo();
  // Under most other circumstances, we would do a bar() here, but
  // we can't because the quux isn't activated yet.  We might call
  // bletch() later to rectify the situation.
  baz();
}
Blrfl
fonte
5
indiscutivelmente, esse comentário não é um código comentado.
jk.
1
@jk: Você está sem dúvida correto.
Blrfl
1

O código comentado não é usado pelo aplicativo, portanto, ele precisa ser acompanhado por outros comentários, informando por que ele não está sendo usado. Mas dentro desse contexto, são situações em que código comentado-out podem ser úteis.

O que me vem à cabeça é um caso em que você resolve um problema usando uma abordagem comum e atraente, mas depois acontece que os requisitos do seu problema real são ligeiramente diferentes desse problema. Especialmente se seus requisitos exigirem consideravelmente mais código, a tentação dos mantenedores de "otimizar" o código usando a abordagem antiga provavelmente será forte, mas isso só trará o bug de volta. Manter a implementação "errada" nos comentários ajudará a dissipar isso, porque você pode usá-la para ilustrar exatamente por que essa abordagem está errada nessa situação.

Não posso imaginar que isso ocorra com muita frequência. Normalmente, deve ser suficiente explicar as coisas sem incluir uma implementação "errada" de amostra. Mas posso imaginar um caso em que isso não seja suficiente; portanto, como a pergunta é se ela pode ser útil, sim, pode. Apenas não na maioria das vezes.

The Spooniest
fonte
1
Desculpe, mas não vejo nenhum valor do código de comentário. O código comentado não é usado e, portanto, não tem lugar no código de produção.
Vladimir Kocjancic
1
Por favor, defina "usado".
JensG
Eu acho que ele quis dizer "executado"
Alexis Dufrenoy 03/01
-2

Isso não parece bom amigo.

O código comentado é ... apenas não o código. O código é para implementação da lógica. Tornar um código mais legível por si só é uma arte. Como o @CodesInChaos já sugeriu que linhas de código repetitivas não são uma implementação muito boa da lógica .

Você realmente acha que um verdadeiro programador prefere a legibilidade à implementação lógica. (pela maneira como temos comentários e 'complementos' para colocar em nossa representação lógica).

No que me diz respeito, deve-se escrever um código para o compilador e isso é bom - se 'ele' entender esse código. Para legibilidade humana, os comentários são bons, para os desenvolvedores (a longo prazo), para as pessoas que reutilizam esse código (por exemplo, testadores).

Caso contrário, você pode tentar algo mais flexível aqui, algo como

boutique.setSite (site) pode ser substituído por

setsiteof.boutique (site). Existem diferentes aspectos e perspectivas do POO através dos quais você pode aumentar a legibilidade.

Embora esse código pareça muito atraente a princípio, pode-se pensar que ele encontrou um caminho para a legibilidade humana, enquanto o compilador também faz seu trabalho perfeitamente, e todos nós começamos a seguir essa prática, o que levará a um arquivo difuso que ficará menos legível no tempo e mais complexo, pois ele se expandirá.

Aura
fonte
15
"No que me diz respeito, deve-se escrever um código para o compilador" Oh, por favor, não. É assim que você acaba com monstruosidades que parecem ser tiradas diretamente do concurso Ofuscado C e afins. Os computadores são binários, enquanto os humanos usam lógica nebulosa (a propósito, isso vale para os donos de animais). Hoje, o tempo do computador é praticamente grátis (basicamente apenas o uso de eletricidade), enquanto o tempo do programador é comparativamente muito caro. Escreva um código para humanos e o compilador o entenderá. Escreva um código para o compilador sem considerar os humanos, e você não fará muitos amigos na equipe.
a CVn
3
" escreve código para um compilador " - Na verdade você não. A pessoa que você deve ter em mente é a pessoa que entregou a tarefa de manter seu código.
JensG