Pergunta

Como parte de um documento de padrões de código que escrevi há algum tempo, aplico "você deve sempre usar aparelhos para loops e/ou blocos de código condicional, mesmo (especialmente) se eles são apenas uma linha".

Exemplo:

// this is wrong
if (foo) 
    //bar
else 
    //baz
while (stuff)
    //things

// This is right.
if (foo) {
    // bar
} else {
    // baz
}
while (things) {
    // stuff
}

Quando você não prepara uma linha única e, em seguida, alguém comenta, você está com problemas. Se você não prepara uma linha única e o recuo não exibe o mesmo na máquina de outra pessoa ... você está com problemas.

Então, pergunta: existem boas razões pelas quais isso seria um padrão equivocado ou irracional? Houve alguma discussão sobre isso, mas ninguém pode me oferecer um contra -argumento melhor do que "parece feio".

Foi útil?

Solução

Aplico isso a um ponto, com pequenas exceções para as declarações if que avaliam para retornar ou continuar um loop.

Então, isso está correto pelo meu padrão:

if(true) continue;

Como é isso

if(true) return;

Mas a regra é que é um retorno ou continua, e tudo está na mesma linha. Caso contrário, aparece para tudo.

O raciocínio é para ter uma maneira padrão de fazê -lo e evitar o problema de comentários que você mencionou.

Outras dicas

O melhor argumento contra o que posso oferecer é que as linhas extras adotadas pelo espaço reduzem a quantidade de código que você pode ver ao mesmo tempo, e a quantidade de código que você pode ver ao mesmo tempo é um grande fator para o quão fácil É para identificar erros. Concordo com as razões que você deu para incluir aparelhos, mas em muitos anos de C ++ só consigo pensar em uma ocasião em que cometi um erro como resultado e foi em um lugar onde não tive um bom motivo para pular o aparelho de qualquer forma. Infelizmente, eu não sabia dizer se ver essas linhas extras de código ajudou a praticar ou não.

Talvez eu seja mais tendencioso porque gosto da simetria de aparelhos correspondentes no mesmo nível de indentação (e do agrupamento implícito das declarações contidas como um bloco de execução) - o que significa que adicionar aparelhos tudo O tempo adiciona muitas linhas ao projeto.

Eu vejo essa regra como um exagero. Os padrões draconianos não são bons programadores, eles apenas diminuem as chances de que um desleixo faça uma bagunça.

Os exemplos que você dá são válidos, mas eles têm melhores soluções do que forçar o aparelho:

Quando você não prepara uma linha única e, em seguida, alguém comenta, você está com problemas.

Duas práticas resolvem isso melhor, escolha uma:

1) Comente o if, while, etc. Antes da liner com a liner. Ou seja, tratar

if(foo)
    bar();

Como qualquer outra instrução multilina (por exemplo, uma tarefa com várias linhas ou uma chamada de função de linha múltipla):

//if(foo)
//    bar();

2) prefixo o // com um ;:

if(foo)
;//    bar();

Se você não prepara uma linha única e o recuo não exibe o mesmo na máquina de outra pessoa ... você está com problemas.

Não, você não é; O código funciona da mesma forma, mas é mais difícil de ler. Corrija seu recuo. Escolha guias ou espaços e fique com eles. Não misture guias e espaços para o recuo. Muitos editores de texto corrigirão isso automaticamente para você.

Escreva algum código Python. Isso consertará pelo menos alguns maus hábitos de indentação.

Além disso, estruturas como } else { Parece uma versão Nethack de um lutador de TIE para mim.

Existem boas razões pelas quais esse seria um padrão equivocado ou irracional? Houve alguma discussão sobre isso, mas ninguém pode me oferecer um contra -argumento melhor do que "parece feio".

Aparelhos redundantes (e parênteses) são uma desordem visual. A desordem visual dificulta a leitura do código. O código mais difícil é ler, mais fácil é ocultar bugs.

int x = 0;
while(x < 10);
{
    printf("Count: %d\n", ++x);
}

Forçar o aparelho não ajuda a encontrar o bug no código acima.

PS Eu sou um assinante da escola "todas as regras deve dizer por que", ou como o Dalai Lama, "saiba as regras para que você possa quebrá -las corretamente".

Ainda tenho que alguém inventar um bom motivo para nem sempre usar aparelhos encaracolados.

Os benefícios excedem em muito qualquer razão "parecer feia" que já ouvi.

O padrão de codificação existe para facilitar a leitura e a redução do código.

Este é um padrão que realmente compensa.

Acho difícil argumentar com padrões de codificação que reduzem erros e tornam o código mais legível. Pode parecer feio para algumas pessoas a princípio, mas acho que é uma regra perfeitamente válida para implementar.

Fico no chão de que os aparelhos devem corresponder de acordo com o recuo.

// This is right.
if (foo) 
{
    // bar
}
else 
{
    // baz
}

while (things) 
{
    // stuff
}

No que diz respeito aos seus dois exemplos, eu consideraria o seu um pouco menos legível, pois encontrar os parênteses finais de encerramento pode ser difícil, mas mais legível nos casos em que o recuo está incorreto, permitindo que a lógica seja inserida com mais facilidade. Não é uma grande diferença.

Mesmo que o recuo esteja incorreto, a instrução IF executará o próximo comando, independentemente de estar na próxima linha ou não. A única razão para não colocar os dois comandos na mesma linha é para suporte ao depurador.

A única grande vantagem que vejo é que é mais fácil adicionar mais declarações a condicionais e loops apoiados, e não são necessárias muitas teclas adicionais para criar os aparelhos no início.

Minha regra pessoal é que, se for muito curta 'se', coloque tudo em uma linha:

if(!something) doSomethingElse();

Geralmente eu uso isso apenas quando há um monte de IFs como esse em sucessão.

if(something == a) doSomething(a);
if(something == b) doSomething(b);
if(something == b) doSomething(c);

Essa situação não surge com muita frequência; caso contrário, eu sempre uso aparelho.

Atualmente, trabalho com uma equipe que vive com esse padrão e, embora seja resistente a ela, cumbo por causa da uniformidade.

Oponho pelo mesmo motivo que me oponho a equipes que proíbem o uso de exceções ou modelos ou macros: Se você optar por usar um idioma, use todo o idioma. Se os aparelhos forem opcionais em C e C ++ e Java, exigir -os por convenção mostra algum medo do próprio idioma.

Eu entendo os riscos descritos em outras respostas aqui, e entendo o desejo de uniformidade, mas não sou simpático a subconjunto de idiomas exceto alguns rigorosos razão técnica, como o único compilador para algum ambiente que não acomoda modelos ou a interação com o código c que impedia o amplo uso de exceções.

Grande parte do meu dia consiste em revisar as mudanças enviadas por programadores juniores, e os problemas comuns que surgem não têm nada a ver com a colocação ou declarações de cinta no local errado. O perigo é exagerado. Prefiro gastar meu tempo focando em mais problemas materiais do que procurar violações do que o compilador aceitaria com prazer.

A única maneira de os padrões de codificação podem ser seguidos bem por um grupo de programadores é manter o número de regras no mínimo.

Equilibre o benefício contra o custo (cada regra extra confunde e confunde programadores e, após um certo limite, reduz a chance de os programadores seguirem qualquer uma das regras)

Então, para fazer um padrão de codificação:

  • Certifique -se de justificar todas as regras com evidências claras de que é melhor que as alternativas.

  • Veja alternativas à regra - é realmente necessário? Se todos os seus programadores usarem espaço em branco (linhas em branco e recuo), uma instrução IF é muito fácil de ler, e não há como mesmo um programador iniciante pode confundir uma instrução dentro de um "se" com uma declaração independente. Se você estiver recebendo muitos bugs relacionados à escopo de IF, a causa raiz é provavelmente que você tem um estilo de pobre WhitePsace/indentação que torna o código desnecessariamente difícil de ler.

  • Priorize suas regras pelo efeito mensurável na qualidade do código. Quantos bugs você pode evitar, aplicando uma regra (por exemplo, "sempre verifique nulo", "sempre valide parâmetros com uma afirmação", "sempre escreva um teste de unidade" versus "sempre adicione alguns aparelhos, mesmo que não sejam necessários") . As regras anteriores economizarão milhares de bugs por ano. A regra do aparelho pode salvar um. Pode ser.

  • Mantenha as regras mais eficazes e descarte o palha. Chaff é, no mínimo, qualquer regra que custará mais a você implementar do que qualquer bug que possa ocorrer ignorando a regra. Mas provavelmente se você tiver mais de 30 regras principais, seus programadores ignorarão muitos deles, e suas boas intenções serão como poeira.

  • Demoie qualquer programador que comenta pedaços aleatórios de código sem lê-lo :-)

PS Minha postura sobre o suporte é: se a instrução "se" ou o conteúdo dela são uma única linha, você poderá omitir os aparelhos. Isso significa que, se você tiver um se contendo um comentário de uma linha e uma única linha de código, o conteúdo pega duas linhas e, portanto, os aparelhos são necessários. Se a condição se abrange duas linhas (mesmo que o conteúdo seja uma única linha), você precisará de aparelhos. Isso significa que você apenas omita aparelhos em casos triviais, simples e facilmente lidos em que os erros nunca são cometidos na prática. (Quando uma declaração está vazia, não uso aparelho, mas sempre coloco um comentário claramente afirmando que está vazio e intencionalmente. Mas isso está na fronteira com um tópico diferente: ser explícito no código para que os leitores saibam que você quis dizer Um escopo para estar vazio em vez do telefone tocou e você esqueceu de terminar o código)

Muitos idiomas têm uma sintaxe para um revestimento como esse (estou pensando em Perl em particular) para lidar com essa "feiúra". Então, algo como:

if (foo)     
//bar
else     
//baz

pode ser escrito como um ternário usando o operador ternário:

foo ? bar : baz

e

while (something is true)
{
blah 
}

pode ser escrito como:

blah while(something is true)

No entanto, em idiomas que não têm esse "açúcar", eu definitivamente incluiria o aparelho. Como você disse, impede que bugs desnecessários surgam e tornam a intenção do programador mais claro.

Não estou dizendo que não é razoável, mas em mais de 15 anos de codificação com idiomas do tipo C, não tive um único problema em omitir o aparelho. Comentar um ramo parece um problema real em teoria - eu nunca vi isso acontecendo na prática.

Outra vantagem de sempre usar o aparelho é que ele facilita a pesquisa e o substituto e as operações automatizadas semelhantes.

Por exemplo: suponha que eu noto que functionB é geralmente chamado imediatamente após functionA, com um padrão semelhante de argumentos, e então eu quero refatorar esse código duplicado em um novo combined_function. Um regex poderia facilmente lidar com essa refatoração se você não tiver uma ferramenta de refatoração poderosa o suficiente (^\s+functionA.*?;\n\s+functionB.*?;) Mas, sem aparelhos, uma abordagem simples de regex pode falhar:

if (x)
  functionA(x);
else
  functionA(y);
functionB();

se tornaria

if (x)
  functionA(x);
else
  combined_function(y);

Regexes mais complicados funcionariam nesse caso em particular, mas achei muito útil poder usar pesquisa e substituição baseada em regex, scripts perl único e manutenção de código automatizado semelhante, por isso prefiro um estilo de codificação Isso não torna isso desnecessariamente complicado.

Eu não compro seu argumento. Pessoalmente, não conheço ninguém que nunca tenha "acidentalmente" uma segunda linha em um if. Eu entenderia dizendo que aninhado if As declarações devem ter aparelhos para evitar um outro pendurado, mas, como eu vejo, você está aplicando um estilo devido ao medo de que, Imo, seja extraviada.

Aqui estão as regras não escritas (até agora, suponho) que eu passo. Eu acredito que isso fornece legibilidade sem sacrificar a correção. É baseado na crença de que a forma curta é de alguns casos mais legível que a forma longa.

  • Sempre use aparelhos se algum Bloco do if/else if/else A declaração tem mais de uma linha. Os comentários contam, o que significa um comentário em qualquer lugar do condicional significa todas as seções do aparelho condicional.
  • Opcionalmente, use aparelhos quando tudo Os blocos da declaração são exatamente uma linha.
  • Nunca coloque a declaração condicional na mesma linha que a condição. A linha após a instrução IF é sempre executada condicionalmente.
  • Se a própria declaração condicional executar a ação necessária, o formulário será:

    for (init; term; totalCount++)
    {
        // Intentionally left blank
    }
    

Não há necessidade de padronizar isso de maneira detalhada, quando você pode apenas dizer o seguinte:

Nunca deixe aparelhos de fora às custas da legibilidade. Em caso de dúvida, escolha usar aparelhos.

Eu acho que o importante sobre os aparelhos é que eles definitivamente expressam a intenção do programador. Você não deve ter que inferir a intenção do indentação.

Dito isto, eu gosto dos retornos de linha única e continua sugerida por Gus. A intenção é óbvia e é mais limpa e mais fácil de ler.

Se você tiver tempo para ler tudo isso, terá tempo para adicionar aparelhos extras.

Prefiro adicionar aparelhos a condicionais de linha única para manutenção, mas posso ver como isso sem aparelho parece mais limpo. Isso não me incomoda, mas algumas pessoas podem ser desligadas pelo ruído visual extra.

Também não posso oferecer um contra -argumento melhor. Desculpe! ;)

Para coisas como essa, eu recomendaria apenas criar um modelo de configuração para a auto -forma do seu IDE. Então, sempre que seus usuários atingem o alt-shift-f (ou qualquer que seja o pressionamento de tecla no seu IDE de escolha), o aparelho será adicionado automaticamente. Depois, diga a todos: "Vá em frente e altere a coloração da fonte, as configurações de PMD ou o que for. Por favor, não altere as regras de recuo ou brace de automóveis".

Isso aproveita as ferramentas disponíveis para evitar discutir sobre algo que realmente não vale o oxigênio que normalmente gasta nele.

Dependendo no Língua, ter aparelho para uma única declaração condicional ou uma declaração de loop não é obrigatória. Na verdade, eu os removeria para ter menos linhas de código.

C ++:

Versão 1:

class InvalidOperation{};

//...
Divide(10, 0);
//...
Divide(int a, in b)
{
   if(b == 0 ) throw InvalidOperation();
   return a/b;
}

Versão 2:

class InvalidOperation{};

//...
Divide(10, 0);
//...
Divide(int a, in b)
{
   if(b == 0 )
   { 
      throw InvalidOperation();
   }
   return a/b;
}

C#:

Versão 1:

foreach(string s in myList)
   Console.WriteLine(s);

Versão 2:

foreach(string s in myList)
{
   Console.WriteLine(s);
}

Dependendo da sua perspectiva, a versão 1 ou a versão 2 será mais legível. A resposta é bastante subjetivo.

Uau. NINGUÉM está ciente do Pergando mais problema? Isso é essencialmente A Razão para sempre usar aparelhos.

Em poucas palavras, você pode ter uma lógica ambígua desagradável com outras declarações, especialmente quando estão aninhadas. Diferentes compiladores resolvem a ambiguidade à sua maneira. Pode ser um grande problema deixar de lado o aparelho, se você não souber o que está fazendo.

Estética e legibilidade não têm nada a fazer.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top