Código curto comentado e mais fácil de entender - mais preferido?

18

Às vezes, um algoritmo pode ser escrito de duas maneiras:

  • O caminho curto e chique; ou
  • A maneira mais longa e fácil de entender.

Por exemplo, aqui está uma maneira mais longa e fácil de copiar uma string sourcepara destC:

*dest = *source;
while (*source != '\0') {
    source++;
    dest++;
    *dest = *source;
} (true);

E aqui está uma maneira curta e chique.

// Copy string source to dest
while (*dest++ = *source++);

Eu sempre ouvi e li que códigos sofisticados devem ser evitados, e costumo concordar. Mas e se levarmos em conta os comentários? Suponha que, como nos exemplos acima, tenhamos um código não comentado, mais longo e supostamente mais fácil de entender, e um código bem comentado, curto e sofisticado? O código não sofisticado ainda é o preferido?

Edição: Muitos comentaram sobre nomes de variáveis, então eu modifiquei o código de exemplo para não tornar isso um fator ao preferir sobre o outro. Tentei remover a atribuição dupla no primeiro exemplo, mas isso apenas tornou o código menos legível.

Talvez este não tenha sido o melhor dos exemplos, porque muitos acham o código "sofisticado" mais legível e compreensível que o código mais longo. A idéia era ter um código mais longo que fosse muito mais fácil de entender do que um código muito curto, mas complicado.

EDIT2: Aqui está um novo exame que recebi da SO :

Versão chique comentada:

//direct formula for xoring all numbers from 1 to N
int Sum = (N & (N % 2 ? 0 : ~0) | ( ((N & 2)>>1) ^ (N & 1) ) );

Versão longa não comentada:

int Sum = 0;
for (int i = 1; i < N; ++i)
{
   Sum ^= i; //or Sum = Sum ^ i;
}
gablin
fonte
2
@ gablin: "goodly" é uma palavra, mas é um adjetivo com um significado um pouco diferente de "good", e não é mais amplamente usado (pelo menos nos EUA). A forma adverbial de "good" é "well". como em "código bem comentado".
John M Gant
@ John: Ah sim, claro. Atualizei a pergunta de acordo. Obrigado.
gablin
2
De que maneira o caminho curto é "chique"? Essa é uma parte do código C do livro que qualquer pessoa que alega conhecer C deve poder ler sem nenhum problema. Dispersão não significa 'fantasia'.
JBRWilkinson
@JBRWilkinson: Como eu disse na parte modificada da pergunta, este exemplo não é bom, pois a versão "sofisticada" aparentemente não é tão sofisticada. O objetivo era ter uma maneira curta, mas não compreensível, com comentários e, em seguida, uma maneira mais longa, mas muito mais legível, sem comentários.
gablin
@ gablin: sua edição compromete as respostas atuais.
Maniero

Respostas:

28

Eu geralmente preferiria extrair o código sofisticado em seu próprio método ..

Em vez de comentar o código sofisticado, o nome do método deve ser tudo o que precisa para deixar as coisas claras.

char *copy_string(char *s, const char *t) {    
    while (*s++ = *t++); 
    return s;
}
Mongus Pong
fonte
3
Ótimo ponto. Fatorar o código independente é muito melhor do que comentários. O compilador sabe como incorporá-lo, se necessário.
dbkk
Ah, sim, é uma ótima maneira de tornar o comentário obsoleto. Mas, apesar disso, você prefere sempre o código sofisticado ao longo do código mais longo?
gablin
Em geral, sim. Eu sinto que métodos curtos e bem nomeados facilitam a leitura e a manutenção do código. A complexidade consignada em seus próprios métodos torna a reutilização mais acessível e aparente. Sempre há exceções, no final das contas, sempre depende do código.
Mongus Pong 04/10/10
Certamente sua função deve ser nomeada 'strcpy'?
JBRWilkinson
Há um erro nesse pedaço de código. O que é devolvido? O que deveria ser devolvido? Basta torná-lo um método nulo e ser feito com ele;)
Christian Mann
10

Sou a favor da versão mais longa. O problema com a versão curta do código, além de ser mais difícil para alguns programadores de ler, é que na maioria das vezes é mais difícil detectar erros apenas olhando para ele.

Eu tenho um exemplo da vida real. Em nosso produto, tivemos o seguinte trecho de código:

if (++someCounter < MAX_VALUE) {
    // Do something that has to be done only MAX_VALUE times
}

Esse código parece perfeitamente razoável à primeira vista, mas após um longo período de tempo, esse contador transborda e quebra a condição (no cenário da vida real, esmagamos o sistema de produção de nossos clientes com uma OOM). Esse código é um pouco menos "sofisticado", mas é claro que ele faz o que deve fazer:

if (someCounter < MAX_VALUE) {
    ++someCounter;
    // Do whatever it is we came here for
}

E você pode dizer que o desenvolvedor que escreveu esse código simplesmente não era bom o suficiente (o que não é verdade, ele era um cara bastante inteligente), mas acho que se sua técnica de codificação exigir que você seja um super habilidoso programador de DEUS em Para obter seu código correto, você está fazendo algo errado. Seu código deve ser o mais à prova de idiotas possível para você e para quem tiver que manter esse código depois de você (que pode não ser tão inteligente quanto você).

Então - sou a favor da simplicidade e clareza.

Edit: Ah, e sobre comentários - não importa. Muitas pessoas não lêem comentários de qualquer maneira ( http://www.javaspecialists.co.za/archive/Issue039.html ) e aqueles que não entenderão seu código sem comentários, não o entenderão suficientemente bem para que possam pode mantê-lo. O objetivo é ajudar as pessoas a ver que determinado código está "correto", os comentários não podem ajudar com isso.

Hila
fonte
1
"esmagou o sistema de produção de nossos clientes" - isso é muito ruim: -S
"O problema com a versão curta do código, além de ser mais difícil para alguns programadores lerem" - qualquer parte do código pode ser difícil "para alguns programadores" lerem. Você só precisa encontrar programadores estúpidos o suficiente. Não reduza o código para o denominador mais baixo.
Quant_dev 16/05/12
@quant_dev: por outro lado, "A depuração é duas vezes mais difícil do que escrever o código. Portanto, se você escrever o código da maneira mais inteligente possível, você não é, por definição, inteligente o suficiente para depurá-lo." - Brian W. Kernighan
Michael Borgwardt
@MichaelBorgwardt Eu não aplicaria o ditado de Kernighan cegamente a todas as situações possíveis. O exemplo dos OPs é uma função escrita "da maneira mais inteligente possível" (ou próxima a ela) e, no entanto, deve ser bastante fácil de depurar, se for necessária alguma depuração. Por outro lado, oneliners complicados e complicados podem ser muito inteligentes, mas certamente serão ainda mais difíceis de depurar. (Também: Kernighan assume que habilidades de codificação = depuração habilidades Ele não tem que ser o caso que eu depurado com êxito código que eu não teria sido capaz de escrever...)
quant_dev
6

Eu geralmente preferiria a versão mais longa. Duas razões principais vêm à mente:

  • É provável que mais pessoas o entendam com menos esforço (supondo que não seja um exemplo "padrão" como esta cópia de cadeia).
  • É possível colocar pontos de interrupção em instruções individuais e avançar com um depurador.

Para o melhor dos dois mundos, envolva o código em uma função, cujo nome faz o comentário para você:

void copy_string(char *s, char *t)
{
    *s = *t;
    while (*t != '\0') {
        t++;
        s++;
        *s = *t;
    }
}

A única razão para não fazer isso seria se o desempenho fosse um problema e os perfis mostrassem genuinamente que a sobrecarga da função era significativa.

Paul Stephenson
fonte
1
Não é para isso que serve o inline?
Antsan 04/10
De fato, embora inlining venha com seu próprio compartilhamento de problemas, como ter que expor o corpo da função nos arquivos de cabeçalho. Os compiladores modernos não incorporam coisas automaticamente automaticamente para você, de qualquer maneira?
Paul Stephenson
4

O que for mais claro. Muitas vezes, é um trecho de código compacto e fácil de entender que não requer comentários ... como o seu segundo exemplo.

Geralmente, trechos mais curtos de código são mais fáceis de entender, pois há menos para o leitor manter em mente por vez. Obviamente, há um limite quando o código fica ofuscado demais e não quero dizer que o espaço em branco que aprimora a clareza deve ser aparado.

Os comentários nunca devem declarar nada óbvio no código, que apenas faça o leitor ler a mesma coisa duas vezes. Para mim, o primeiro trecho exige esclarecimentos. Por que o desenvolvedor não usou um do...whileloop para remover a duplicação da *s = *t;tarefa? Eu tenho que analisar mais código para perceber que está implementando uma cópia de seqüência de caracteres. Um comentário seria mais útil nesse código mais longo do que no código mais curto.

O comentário no segundo trecho é quase redundante, já que o loop while é praticamente idiomático, mas diz o que o código faz em um nível superior ao do próprio código, o que o torna um comentário útil.

CB Bailey
fonte
O desenvolvedor (eu) não usou do ... whilesimplesmente porque não pensei nisso quando escrevi a pergunta. Obrigado por apontar isso. ^^ O segundo trecho pode ser óbvio para você, mas certamente não é para mim.
gablin
4

O problema é que não há uma definição clara, short fancy codepois depende muito do nível do programador. Enquanto algumas pessoas não têm problemas para entender uma while(*s++ = *t++);expressão, outras o fazem .

Pessoalmente, acho o mais while(*s++ = *t++);legível e o mais difícil de ler. Outros podem não concordar.

Independentemente disso, é apenas uma questão de usar o bom senso. A legibilidade deve ser definitivamente uma prioridade, mas há um ponto em que um código mais longo fica menos legível quando mais longo. A verbosidade geralmente reduz a legibilidade da minha experiência.

Wolph
fonte
Fico triste por um tema de muitas dessas respostas ser "os desenvolvedores podem não reconhecer a maneira padrão de escrever strcpy () em C"
AShelly
Não deveria - isso não significa que não existem mais bons programadores, e sim que a) não ensinamos muito mais C eb) que a força de C também é sua fraqueza - enquanto esse ciclo é compreensível para um praticada em C seu também bastante misteriosa e em um mundo esforçando-se para escrever código seguro bastante assustador para que isso implica sobre o que você pode fazer em C
Murph
Então nos encontramos com outro desafio para nossas tarefas diárias. Precisando adivinhar o nível geral de compreensão de idiomas de nossos pares diretos, para que nossas revisões de código permaneçam construtivas. Não cair em batalhas é a expressão "correta" e mais limpa da intenção.
frogstarr78
2

Eu tenho que discordar da maioria das outras respostas aqui - acho que (pelo menos nesse caso) o código mais curto é melhor. Contrariamente à sua reivindicação, o código mais longo não é "mais fácil", pelo menos para um leitor. De qualquer forma, parece que você deixou de desejar prolongá-lo, mesmo que isso torne o código mais difícil de entender e / ou tenha certeza da operação correta.

Em particular, ter a atribuição do primeiro byte da string fora do loop, separada da atribuição para os outros bytes, significa que é preciso ter muito mais cuidado na leitura para garantir que todos os bytes sejam copiados corretamente. A sequência básica de ações na versão mais curta é muito mais fácil de verificar. Seu único problema real está na formatação - quando você tem um corpo de loop intencionalmente vazio, é melhor deixar isso claro, algo como:

while (*dest++ = *source++)
    ;

ou até:

while (*dest++ = *source++)
    ; /* no body */

Algumas pessoas preferem usar aparelhos:

while (*dest++ = *source++)
    {}

Independentemente da formatação exata de sua preferência, erros suficientes foram cometidos com coisas como:

if (x>y);
     x = z;

... que é importante ter certeza de que 1) é óbvio o que é realmente controlado por qualquer controle de fluxo e 2) é óbvio que o código foi escrito sabendo o que foi controlado por ele, para que alguém que o leia não perca tempo tentando para descobrir se eles acabaram de encontrar um bug.

Jerry Coffin
fonte
Sim, em retrospecto a este exemplo em particular, a versão 'sofisticada' provavelmente é mais legível que a versão mais longa. Se eu pudesse pensar em um exemplo melhor, pensaria, mas no momento não consigo. Mas eu não "saí do meu caminho" para prolongá-lo - é assim que eu escreveria uma cópia de string, pelo menos inicialmente. Pode não ser a melhor abordagem, mas não foi feita mais do que o necessário por intenção.
gablin
2
Keep it simple, stupid!

Certifique-se de que qualquer outro programador possa entender o que seu código faz - e melhor ainda, se for de relance (é aqui que bons nomes e comentários se encaixam).

O kung-fu extravagante e a montagem embutida são ótimos em nome da otimização (talvez desnecessária e prematura), mas quando você nem consegue entender o código que escreveu quando se depara com um bug dois meses depois .. Qual era o objetivo? Você vai gastar tempo e esforço.

Costumo me referir ao Zen de Python nessas situações. Em particular:

Explicit is better than implicit.
Simple is better than complex.
Humphrey Bogart
fonte
1

Não escreva código sofisticado no software de produção. Eu sei que é bom poder escrever isso, e é mais curto. Escrever código sofisticado aumenta significativamente o valor "WTF / minuto", ou seja, diminui a qualidade.

texto alternativo

Tamás Szelei
fonte
1

É claro que depende inteiramente das circunstâncias. mas, em geral, acho que essa é uma boa regra geral:

A depuração é duas vezes mais difícil do que escrever o código em primeiro lugar. Portanto, se você escrever o código da maneira mais inteligente possível, por definição, você não é inteligente o suficiente para depurá-lo.

~ Brian Kernighan

violet313
fonte
mais longo, mas mais significativo, elegante mesmo, que o mais compacto BEIJO sigla ~ espero que a ironia não é perdida; p
violet313
0

Na minha experiência, a maior vitória em termos de códigos extravagantes curtos tende a usar recursão do que iteração. É também uma das coisas mais difíceis de entender em um relance de código, a menos que você esteja trabalhando no tipo de linguagem em que tudo é recursivo de qualquer maneira. Eu ainda o favoreceria pela elegância e velocidade de desenvolvimento que oferece, mas tento garantir que ele tenha comentários detalhados, se parecer que será opaco para futuros mantenedores ou para o meu eu futuro.

glenatron
fonte
0

Estou começando a nunca confiar em comentários. Com muita frequência, os comentários não são atualizados quando o código é atualizado e estão muito desatualizados ou representam regras de clientes / gerenciamento que não são mais relevantes.

Chegou ao ponto em alguns casos em que os comentários nem sequer correspondem ao código que estão descrevendo mais.

Se eu tiver que escolher entre curto / extravagante e mais longo / mais fácil de entender, sempre escolho o último, a menos que haja um motivo realmente bom.

Steven Evers
fonte
0

A legibilidade e a manutenção são essenciais, e seu segundo exemplo (ou seja, o mais longo) é muito mais dos dois. Mas por que se limitar a duas opções? Mesmo o código mais longo é muito complexo (IMHO) para não anotar mais. Eu o colocaria em um método próprio com Javadoc apropriado (ou o que seja) e um nome de método adequado.

Chris Knight
fonte