Por que é considerado uma má prática omitir chaves? [fechadas]


177

Por que todo mundo me diz que escrever um código como esse é uma prática ruim?

if (foo)
    Bar();

//or

for(int i = 0 i < count; i++)
    Bar(i);

Meu maior argumento para omitir as chaves é que às vezes pode haver o dobro de linhas com elas. Por exemplo, aqui está um código para pintar um efeito de brilho para um rótulo em C #.

using (Brush br = new SolidBrush(Color.FromArgb(15, GlowColor)))
{
    for (int x = 0; x <= GlowAmount; x++)
    {
        for (int y = 0; y <= GlowAmount; y++)
        {
            g.DrawString(Text, this.Font, br, new Point(IconOffset + x, y));
        }
     }
 }
 //versus
using (Brush br = new SolidBrush(Color.FromArgb(15, GlowColor)))
    for (int x = 0; x <= GlowAmount; x++)
        for (int y = 0; y <= GlowAmount; y++)
            g.DrawString(Text, this.Font, br, new Point(IconOffset + x, y));

Você também pode obter o benefício adicional de encadear usingssem precisar recuar um milhão de vezes.

using (Graphics g = Graphics.FromImage(bmp))
{
    using (Brush brush = new SolidBrush(backgroundColor))
    {
        using (Pen pen = new Pen(Color.FromArgb(penColor)))
        {
            //do lots of work
        }
    }
 }
//versus
using (Graphics g = Graphics.FromImage(bmp))
using (Brush brush = new SolidBrush(backgroundColor))
using (Pen pen = new Pen(Color.FromArgb(penColor)))
{
    //do lots of work
}

O argumento mais comum para chavetas gira em torno da programação de manutenção e os problemas que surgiriam com a inserção de código entre a instrução if original e o resultado pretendido:

if (foo)
    Bar();
    Biz();

Questões:

  1. É errado querer usar a sintaxe mais compacta que o idioma oferece? As pessoas que projetam essas linguagens são inteligentes, não consigo imaginar que colocariam um recurso que é sempre ruim de usar.
  2. Devemos ou não devemos escrever código para que o menor denominador comum possa entender e não ter problemas ao trabalhar com ele?
  3. Existe outro argumento que estou perdendo?

6
Eu concordo com você. Omita-os. Período.
Andrei Rînea

67
QUEM SE IMPORTA EM QUANTAS LINHAS É ALGO EM 2010. Os monitores são amplos, baratos e de alta resolução! Meu monitor é 2048 x 1152 e tenho DOIS! A legibilidade é muito mais importante do que salvar duas linhas verticais quando você pode introduzir facilmente erros sutis que são difíceis de encontrar.

51
Os monitores são amplos e baratos, mas não altos e baratos. O espaço vertical é mais escasso que o espaço horizontal.
Adam Says - Restabelecer Monica

32
@AdamRuth Transformá-los de lado :)
Zachary Yates

16
Então você não estraga como a Apple com o bug SSL encontrado em fevereiro de 2014, LOL.
24514 Learnvst

Respostas:


183

Na verdade, a única vez que realmente me mordeu foi quando eu estava depurando e comentei o bar ():

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

Fora isso, eu costumo usar:

if(foo) bar();

Que cuida do caso acima.

EDIT Obrigado por esclarecer a questão, eu concordo, não devemos escrever código para o menor denominador comum.


31
Isso é difícil, é claro, mas acho que o maior problema para os mantenedores é que eles adicionem uma segunda linha e não percebam que não faz parte da declaração condicional, mesmo que realmente pareça que deveria ser.
Danieltalsky 12/12/08

23
Não gosto do estilo liner porque sempre procuro o corpo do loop abaixo.
Nosredna

18
Acho o estilo de uma linha mais irritante do que útil, porque (especialmente no assentamento profundo - ugh) a declaração pode ser facilmente exagerada e pode haver confusão. Eu uso quase exclusivamente esses ifs de instrução única para validação de entrada (ou seja, retornos antecipados) ou controle de loop (por exemplo, ignorando nomes irrelevantes de arquivos nas caminhadas pelo sistema de arquivos), no entanto, onde linhas em branco ajudam a diferenciá-las do código principal.
Alan Plum

1
O estilo de uma linha também oculta a barra () da cobertura do teste. Ele parecerá coberto, mesmo que foo seja sempre falso.
precisa

1
Essa é outra maneira de dizer: "se a fonte incluísse o aparelho, eu não teria perdido tempo enquanto depurava". - adicionar os aparelhos é trivialmente simples e evita deixar armadilhas para a próxima pessoa. O único argumento contra é a "legibilidade", o que é bastante tênue, pois esse é um caso em que algo implicitamente acontece se você os omitir.
Andrew Theken

156

Velocidade de leitura ...

Além do que já foi mencionado. Neste ponto, eu já fui condicionada a analisar as declarações com chaves e espaço em branco. Então eu li:

if (condition)
{
    DoSomething();
}

DoSomethingElse();

Um pouco mais rápido do que eu li:

if (condition) DoSomething();

DoSomethingElse();

Eu o li um pouco mais devagar se parece com isso:

if (condition) DoSomething();
DoSomethingElse();

Eu li isso significativamente mais lento que o anterior:

if (condition) 
    DoSomething();
DoSomethingElse();

porque não posso deixar de lê-lo novamente, apenas no caso, e me pergunto se o autor pretendia:

if (condition)
{
    DoSomething();
    DoSomethingElse();
}

Já abordado em geral, mas quando se trata de ler o abaixo, analisarei isso por um bom tempo para garantir o que o autor pretendia. Eu posso até caçar o autor original para confirmar.

if (condition) 
    DoSomething();
    DoSomethingElse();

29
O problema é resolvido quando, na sua quarta amostra, você apenas coloca uma linha vazia após a declaração if para separá-la de DoSomethingElse () É o que eu faço e a legibilidade é praticamente a mesma da primeira amostra (se não melhor ;-P) Outra coisa é que a colocação de linhas em grupos de 2 ou 3 ajuda significativamente a legibilidade, você apenas digitaliza o código muito mais rapidamente.
Piotr Owsiak 19/08/09

6
Talvez seja porque eu estou acostumado com Python, mas colocar a primeira chave na mesma linha que a instrução if me permite ler + entendê-la ainda mais rapidamente.
Ponkadoodle

16
O problema com o estilo sem pulseira faz com que você desperdice sua preciosa concentração pensando se o bloco tem ou não chaves, em vez de coisas mais importantes. Isso por si só é uma razão boa o suficiente para usar a convenção mais simples possível, que é sempre aparelho.
Nate CK

2
O aparelho é explícito por natureza. Eu vou ficar com isso, obrigado.
TheOptimusPrimus

2
No último caso, caçar o autor original e discipliná-lo ...;)
Per Lundberg

55

Se for algo pequeno, escreva assim:

if(foo()) bar();

Se for longo o suficiente para dividir em duas linhas, use chaves.


Sim, é o que eu faço também. Isso o força a adicionar chaves se você adicionar outra linha, e é bem claro que a barra () faz parte do if, então coisas ruins acontecerão se você comentar.
jalf

10
Não é muito amigável para depurador, no entanto. Como você configura um ponto de interrupção na parte "barra"?
Nemanja Trifunovic

9
@ Nemanja: Basta colocar o cursor na barra (); e pressione F9. O VS2005 e o VS2008 lidam com pontos de interrupção intra-linha, se forem "instruções" separadas.
GalacticCowboy

4
GalanticCowboy: Existem mais ambientes do que aqueles que você conhece. :-)

20
Claro, mas como o contexto é C #, isso deve abranger uma maioria significativa dos usuários ...
GalacticCowboy

47

Eu também costumava pensar que é melhor usar aparelho apenas quando realmente necessário. Mas não é mais, o principal motivo, quando você tem muito código, ele fica mais legível e você pode analisar o código mais rapidamente quando tiver um estilo de suporte consistente.

Outro bom motivo para sempre usar chaves, além de alguém adicionar uma segunda declaração ao if, é algo como isso:

if(a)
   if(b)
     c();
else
   d();

Você notou que a cláusula else é realmente a do "if (b)"? Você provavelmente fez, mas confiaria em alguém que estivesse familiarizado com essa pegadinha?

Portanto, se apenas por consistência e porque você nunca sabe o que pode acontecer de inesperado quando outra pessoa (são sempre as outras idiotas) muda o código, eu sempre uso chaves, porque torna o código fonte mais legível, mais rápido de analisar seu cérebro. Somente para as declarações if mais simples, como uma se uma delegação é feita ou é alternada, onde você sabe que a cláusula nunca será estendida, eu deixaria de fora as chaves.


12
Este é um dos dois casos em que eu uso aparelho. Caso contrário, não.
Andrei Rînea

3
Isso deve ser escrito como se (a && b) ... em primeiro lugar, parece.
alexander.biskop

8
@ alexander.biskop: Certamente que não, pois isso dá ao bloco else um significado diferente ( !a || !b) do que com ( !a) ou sem ( a && !b) chaves adicionais.
Ben Voigt

1
@ Ben Voigt: Verdade! Me apaixonei ;-) Meio ano e duas votações depois, alguém percebe que a afirmação que fiz está errada ... Acho que não prestei atenção suficiente aos detalhes, principalmente porque a intenção por trás do meu comentário era diferente de apontar uma transformação tecnicamente correta dessa cláusula if. O que eu quis dizer foi que as declarações if aninhadas geralmente diminuem a legibilidade (e, especialmente, a rastreabilidade do fluxo de controle) imho significativamente e, portanto, devem ser combinadas em uma declaração (ou contornadas por completo). Cheers
alexander.biskop

3
@ alexander.biskop: Ao mesmo tempo, a depuração é mais fácil com ifs aninhados, cada um com condições mais simples, já que você pode dar um passo para cada um.
precisa


35

As linhas são baratas. A energia do processador é barata. O tempo do desenvolvedor é muito caro.

Como regra geral, a menos que eu esteja desenvolvendo algum aplicativo absolutamente crítico em termos de recursos / velocidade, sempre errei ao escrever código

(a) Fácil para qualquer outro desenvolvedor seguir o que estou fazendo

(b) Comente partes específicas do código que possam precisar dele

(c) Fácil de depurar se algo der errado

(d) Fácil de modificar se for necessário no futuro (por exemplo, adicionar / remover código)

A velocidade ou elegância acadêmica do código é secundária a esses fatores da perspectiva dos negócios. Isso não quer dizer que me proponha a escrever códigos desajeitados ou feios, mas essa é a MINHA ordem de prioridade.

Ao omitir chaves, na maioria dos casos, torna-me (b), (c) e (d) mais difícil (no entanto, não é impossível). Eu diria que o uso de chaves ou não não tem efeito em (a).


9
Sua última declaração sobre (a) é uma opinião de que um grande número de desenvolvedores, incluindo outros pôsteres aqui, argumentaria.
55578 Kelly S. French

34

Eu prefiro a clareza que o colar oferece. Você sabe exatamente o que se entende e não precisa adivinhar se alguém apenas brincou e os deixou (e introduziu um bug). A única vez que eu os omito é quando coloco o if e a ação na mesma linha. Também não faço isso com muita frequência. Na verdade, eu prefiro o espaço em branco introduzido colocando a chave em sua própria linha, embora, a partir de anos de programação K&R tipo C, encerrar a linha com uma chave seja uma prática que tenho que trabalhar para superar se o IDE não a aplicar para mim.

if (condition) action();  // ok by me

if (condition) // normal/standard for me
{
   action();
}

23

Eu acho que é uma questão de diretrizes para o projeto no qual você está trabalhando e gosto pessoal.

Normalmente, eu os omito quando não são necessários, exceto em alguns casos como o seguinte:

if (something)
    just one statement; // i find this ugly
else
{
    // many
    // lines
    // of code
}

eu prefiro

if (something)
{
    just one statement; // looks better:)
}
else
{
    // many
    // lines
    // of code
}

15

Uma das instâncias em que isso pode te morder está de volta aos velhos tempos das macros C / C ++. Sei que essa é uma pergunta em C #, mas geralmente os padrões de codificação são transferidos sem os motivos pelos quais o padrão foi criado.

Se você não for muito cuidadoso ao criar suas macros, poderá causar problemas nas instruções if que não usam {}.

#define BADLY_MADE_MACRO(x) function1(x); function2(x);

if (myCondition) BADLY_MADE_MACRO(myValue)

Agora, não me entenda mal, não estou dizendo que você deve sempre {} evitar esse problema no C / C ++, mas tive que lidar com alguns erros muito estranhos por causa disso.


2
Se somente todo o código se declarou como tal ... suspiro
Nathan Strong

15

Eu costumo pensar da mesma maneira.

Até um dia (por que sempre existe esse "dia" que muda sua vida para sempre?), Passamos de 24 a 36 horas seguidas sem dormir depurando o código de produção apenas para descobrir que alguém não colocou chaves combinadas com uma alteração de pesquisa / substituição .

Foi algo assim.

 if( debugEnabled ) 
      println( "About to save 1 day of work to some very important place.");
 saveDayData();

O que veio depois foi

 if( debugEnabled ) 
 //     println( "About to save 1 day of work to some very important place.");
 saveDayData();

Acontece que o sistema estava gerando 500 mb de logs diariamente e fomos solicitados a pará-lo. O sinalizador de depuração não era suficiente; portanto, uma pesquisa e substituição de println estavam em ordem.

Ainda quando o aplicativo entrou em produção, o sinalizador de depuração estava desativado e o importante "saveDayData" nunca foi chamado.

EDITAR

Agora, o único lugar em que não uso o aparelho é na construção if / try.

if( object != null ) try { 
     object.close();
} catch( .....

Depois de assistir a um desenvolvedor de superstar fazendo isso.


3
Eu não entendo Você tem uma variável que controla a depuração (debugEnabled) e ainda usa comentários para desativar a depuração ??? Por que você não definiu debugEnabled como false?
Igor Popov

Este não é exatamente o cenário, mas você faz uma boa observação. Coisas estúpidas (como não definir debug para false) criam erros sutis e estúpidos que são mais difíceis de encontrar do que erros "óbvios". Não usar aparelho não ajudou muito nesse caso.
OscarRyz 27/12/2010

1
@igor Que tal porque eles só queriam remover uma linha de registro, nem todas as linhas de registro?
precisa

14

Para ser franco, vejo como:

Bons programadores programam defensivamente, maus programadores não.

Como existem vários exemplos acima e minhas próprias experiências semelhantes com bugs relacionados ao esquecimento de aparelhos, então aprendi da maneira mais difícil a SEMPRE COLOCAR Cintas.

Qualquer outra coisa é escolher o estilo pessoal em vez da segurança e isso é claramente uma programação ruim.

Joel até menciona isso em Fazendo Código Errado parecer Errado

Depois que você é mordido por um bug por causa da falta de chaves, você aprende que elas parecem erradas porque você sabe que é um local em potencial para a ocorrência de outro bug.


Se as chaves abertas forem colocadas nas linhas por si mesmas, qualquer lugar em que duas ou mais linhas sejam recuadas sem um par de chaves parecerá errado, assim como qualquer par de chaves incomparável. Esse uso custará uma linha em branco nos casos em que uma ifinstrução controla um bloco, mas evita a necessidade de um bloco nos casos em que uma ifinstrução controla uma única ação em vez de um bloco.
Supercat

14

Estou muito feliz por:

foreach (Foo f in foos)
  foreach (Bar b in bars)
    if (f.Equals(b))
      return true;

return false;

Pessoalmente, não vejo por que

foreach (Foo f in foos)
{
  foreach (Bar b in bars)
  {
    if (f.Equals(b))
    {
      return true;
    }
  }
}

return false;

é mais legível.

Sim, as linhas são gratuitas, mas por que eu deveria rolar pelas páginas e páginas de código quando ele poderia ter metade do tamanho?

Se houver uma diferença de legibilidade ou manutenção, é claro, coloque chaves ... mas, neste caso, não vejo motivo para isso.

Além disso, sempre colocarei chaves para if aninhados onde aninhei outros

if (condition1)
  if (condition2)
    doSomething();
  else (condition2)
    doSomethingElse();

vs

if (condition1)
  if (condition2)
    doSomething();
else (condition2)
  doSomethingElse();

é terrivelmente confuso, então eu sempre o escrevo como:

if (condition1)
{
  if (condition2)
    doSomething();
  else (condition2)
    doSomethingElse();
}

Sempre que possível, uso operadores ternários, mas nunca os aninho .


acabei de ver isso quase acontecendo no meu código :) imaginei que vou dar uma olhada ao redor, e eis que ... já está lá fora :) :)
Noctis

10

Concordo que "se você é inteligente o suficiente para conseguir que alguém lhe pague para escrever código, você deve ser inteligente o suficiente para não confiar apenas no recuo para ver o fluxo do código".

No entanto ... erros podem ser cometidos, e este é um problema para depurar ... especialmente se você está olhando o código de outra pessoa.


10

Minha filosofia é que, se torna o código mais legível, por que não fazê-lo?

Obviamente, você precisa traçar a linha em algum lugar, como encontrar esse meio termo entre nomes de variáveis ​​concisos e excessivamente descritivos. Mas os colchetes realmente evitam erros e melhoram a legibilidade do código.

Você pode argumentar que as pessoas inteligentes o suficiente para serem codificadoras serão inteligentes o suficiente para evitar erros que resultem em declarações sem suporte. Mas você pode dizer honestamente que nunca foi enganado por algo tão simples quanto um erro de ortografia? Minutia como essa pode ser avassaladora quando se olha para grandes projetos.


7
Claro que isso é muito subjetivo. Deixá-los em algum momento melhora a legibilidade.
Brian Knoblauch

É verdade que, se eu deixar os colchetes de fora, mantenho uma linha, como outros já mencionaram. Fui mordido muitas vezes, mas com declarações de várias linhas sem suporte. Mesmo se você souber cuidar dele, ele ainda poderá ocasionalmente pegá-lo.
James McMahon

10

Sempre há exceções, mas eu argumentaria contra a omissão de chaves somente quando estiver em uma das formas:

if(x == y)
   for(/* loop */)
   {
      //200 lines
   }

//rampion's example:
for(/* loop */)
{
   for(/* loop */)
      for(/* loop */)
      {
         //several lines
      }
}

Caso contrário, não tenho nenhum problema com isso.


4
Maus exemplos. Nos dois casos, eu fatoraria essa linha 200 para loop em seu próprio método, ou preferencialmente em vários métodos.
Adam Jaskiewicz

2
É verdade, mas acontece. Além disso, sempre que um bloco for maior que a tela do leitor, você terá esse problema. E você não pode controlar a altura da tela do seu leitor de código. Eles podem ver apenas algumas linhas de cada lado.
Rampion

2
Isso acontece. Isso não significa que isso deva acontecer.
Adam Jaskiewicz

3
@AdamJaskiewicz Right. Isso acontece. Temos que pensar sobre o que não aconteça, ao invés do que deveria acontecer. Se pudéssemos nos restringir ao que deveria acontecer, não precisaríamos nos preocupar com bugs.
Beska

10

Ocasionalmente, uso o código mais baixo (várias instruções de uso), mas, além disso, sempre coloco os chavetas. Só acho que isso torna o código mais claro. É flagrantemente óbvio por mais do que apenas um recuo que uma declaração faz parte de um bloco (e, portanto, provavelmente parte de um if etc).

Eu vi o

if (...)
    foo();
    bar();

o bug me mordeu (ou melhor, "eu e colegas" - eu não o introduzi) uma vez . Isso apesar do fato de que nossos padrões de codificação na época recomendavam o uso de chaves em todos os lugares. Levei um tempo surpreendentemente longo para descobrir - porque você vê o que deseja ver. (Isso foi há cerca de 10 anos. Talvez eu ache mais rápido agora.)

É claro que se você usar "cinta no final da linha", isso reduzirá as linhas extras incorridas, mas eu pessoalmente não gosto desse estilo. (Eu uso no trabalho e achei menos desagradável do que eu esperava, mas ainda é um pouco desagradável.)


Eu sempre argumento que a consistência é mais importante do que o estilo real, por que devemos abrir uma exceção apenas no caso de usos?
1112 Bob

@ Bob: Bom ponto, e eu faço isso apenas ocasionalmente. Eu não gostaria de fingir que tenho razões reais aqui :) Na verdade, há uma razão razoável - aninhar os usos (e apenas os usos) assim é bastante óbvio, e você ainda acaba com um bloqueio. Não consigo ver imediatamente o perigo.
Jon Skeet

O que não quer dizer que há não é nenhum perigo, é claro.
Jon Skeet

1
Melhor solução para esse bug: Use Python. (Brincando, é claro.)
Joel Wietelmann

10

Estou impressionado e humilhado por meus colegas neste campo de programação de computadores (vocês) não se assustarem com a perspectiva de possíveis erros quando você pula os aparelhos nos blocos de linha única.

Suponho que isso significa que não sou inteligente. Eu cometi erros em torno disso várias vezes. Eu depurei os erros dos outros em torno disso. Eu assisti o software ser enviado com erros por causa disso (o RDP para uma máquina executando o VS2002 e a fonte da janela do relógio ficará instável).

Se eu olhar para todos os erros que cometi que poderiam ter sido evitados com uma mudança no estilo de codificação, a lista é muito longa. Se eu não tivesse mudado minha abordagem em cada um desses casos, provavelmente nunca teria feito isso como programador. Mais uma vez, acho que não sou inteligente. Para compensar, sou um usuário fiel de aparelhos em blocos de linha única há muito tempo.

Dito isto, algumas coisas mudaram no mundo que tornam a regra "usarás aparelhos em blocos de linha única" hoje menos relevante hoje do que quando Moisés trouxe isso para nós:

  • Algumas linguagens populares resolvem o problema fazendo o computador ler o recuo, assim como o programador (por exemplo, Python).

  • Meu editor formata automaticamente para mim, então as chances de eu ser enganado por indentação são muito reduzidas.

  • TDD significa que, se eu introduzir um bug, porque fico confuso com um bloco de linha única, é muito mais provável que ele descubra rapidamente.

  • A refatoração e a expressividade do idioma significam que meus blocos são muito mais curtos e os blocos de linha única acontecem com muito mais frequência do que os usados ​​anteriormente. Hipoteticamente, com uma aplicação implacável do ExtractMethod, eu poderia ter apenas blocos de linha única em todo o meu programa. (Gostaria de saber como seria isso?)

De fato, pode haver um benefício distinto em refatorar impiedosamente e omitir aparelhos em blocos de linha única: quando você vê aparelhos, um pequeno alarme pode disparar em sua cabeça que diz "complexidade aqui! Cuidado!". Imagine se essa fosse a norma:

if (condition) Foo();   // normal, everyday code

if (condition) 
{
    // something non-trivial hapening; pay attention!
    Foo();
    Bar();
}

Estou me abrindo para a ideia de alterar minha convenção de codificação para algo como "blocos de linha única podem nunca ter chavetas" ou "se você puder colocar o bloco na mesma linha que a condição e tudo se encaixar em 80 caracteres, omita o aparelho ". Veremos.


Como ex-programador Java, eu tenho que concordar plenamente com a formatação automatizada sendo a resposta real para o problema. Você nem precisa que seu editor adicione chaves automaticamente - o recuo automático sozinho pode ajudar a evitar muitas ambiguidades. É claro que agora que mudei para Python, me acostumei a formatar meu código corretamente em primeiro lugar.
Alan Plum

Eu sinto o mesmo sobre aparelhos. É tudo sobre a complexidade. Idealmente, teríamos apenas um bloco de linhas. É o que chamo de legibilidade, não de aparelhos desnecessários.
Igor Popov

9

Das três convenções:

if(addCurleyBraces()) bugFreeSofware.hooray();

e:

if(addCurleyBraces())
    bugFreeSofware.hooray();

e (que representam qualquer estilo de indentação usando uma chave de abertura e fechamento):

if(addCurleyBraces()) {
    bugFreeSofware.hooray();
}

Eu prefiro o último como:

  • Acho mais fácil ler se todas as declarações if são escritas de maneira uniforme.
  • Isso pode tornar o software um pouco mais robusto e livre de erros. No entanto, todos os IDE's modernos e editores de texto avançados têm ótimos recursos de recuo automático, que eu acho que todo mundo deveria usar, desde que não estrague a formatação de comentários ou vá contra os padrões da equipe (em muitos casos, é possível criar um esquema de formatação personalizado e compartilhe com a equipe). Meu argumento aqui é que, se o recuo for feito corretamente, o risco de introdução de bugs será reduzido um pouco.
  • Prefiro que a expressão e as instruções booleanas sejam executadas para estar em linhas diferentes. Eu gosto de poder marcar uma linha para fins de depuração. Mesmo que eu esteja usando um IDE em que possa marcar uma declaração e avançar, é uma operação interativa e posso esquecer onde comecei a depurar ou, pelo menos, levará um pouco mais de tempo para percorrer o código várias times (como eu tenho que marcar a posição manualmente todas as vezes durante a depuração).

8

Seus principais argumentos contra o uso de chaves são que eles usam linhas adicionais e que requerem indentação adicional.

As linhas são (quase) gratuitas, minimizar o número de linhas no seu código não deve ser um objetivo.

E o recuo é independente do uso de chaves. No seu exemplo de "uso" em cascata, ainda acho que você deve recuá-los mesmo quando omitir os aparelhos.


8

Eu acredito muito em escrever código conciso e organizado, mas eu sempre usava chaves. Acho que eles são uma maneira conveniente de ver rapidamente o escopo em que existe uma linha de código específica. Não há ambiguidade, é apenas explicitamente definido na sua frente.

Alguns podem dizer que é um caso de preferência, mas acho o fluxo lógico de um programa muito mais fácil de seguir, se for internamente consistente, e não acredito que seja consistente escrever uma declaração IF como esta;

if(x < y)
    x = y;
else
    y = x;

E outro assim;

if(x < y)
{
    x = y;
    x++;
}
else
{
    y = x;
    y++;
}

Prefiro escolher um estilo geral e segui-lo :)


7

Um dos principais problemas é quando você tem regiões de um e de um lado, além da separação da declaração de controle ( for,if , o que você tem) e no final do statment.

Por exemplo:

for (...)
{
  for (...)
    for (...) 
    {
      // a couple pages of code
    }
  // which for block is ending here?  A good text editor will tell you, 
  // but it's not obvious when you're reading the code
}

4
Por que você tem algumas páginas de código no seu loop for?
11118 Adam Adamkiewicz

b / c Sou um torrão insensível e obcecado em me livrar do "custo" das chamadas de função. :)
rampion

4
O par de páginas de código deve estar em uma função separada, geralmente.
11138 Jonathan Leffler

1
com licença, eu quis dizer que estava fazendo o papel de tal torrão. No entanto, considero que o mesmo problema pode ocorrer para regiões mais curtas, quando visualizadas através de uma pequena janela de visualização. E isso está fora do controle do codificador.
Rampion

7

Eu costumava ser um grande defensor de "chaves são obrigatórias!", Mas desde a adoção do teste de unidade, acho que meus testes de unidade protegem as declarações sem pulseira de cenários como:

if (foo)
    snafu();
    bar();

Com bons testes de unidade, posso omitir com confiança chaves para declarações simples para melhorar a legibilidade (sim, isso pode ser subjetivo).

Como alternativa, para algo como o acima, eu provavelmente incluiria isso:

if (foo) snafu();

Dessa forma, o desenvolvedor que precisa adicionar bar () à condição estaria mais apto a reconhecer a falta de chaves e adicioná-las.


2
Você disse "não preciso disso" e, em seguida, deu uma razão para usá-lo: legibilidade!
tvanfosson

4
Eu não confiaria em um teste de unidade para descobrir isso. Talvez, teste de unidade não!
Kristen

2
@ Kristen - A idéia do teste de unidade é afirmar o comportamento do método. Se o comportamento mudar (como descrito acima), o teste de unidade falhará. Eu não vejo o problema nisso.
Liggy 27/11/2009

Mas por que confiar no teste de unidade para captar o óbvio óbvio que deve ser corrigido antes de ir para a UT?
Andrew

7

Use algum julgamento pessoal.

if (foo)
  bar();

está bem por si só. A menos que você esteja realmente preocupado com idiotas colocando algo assim depois:

if (foo)
  bar();
  baz();

Se você não está preocupado com idiotas, está bem (eu não estou - se eles não conseguem acertar a sintaxe básica do código, esse é o menor dos problemas deles)>

Em troca, é muito mais legível.

O resto do tempo:

if (foo) {
  bar();
  baz();
}

Qual foi o meu favorito desde que me lembro. Além disso:

if (foo) {
  bar();
  baz();
} else {
  qux();
}

Funciona para mim.

O espaço vertical por si só não é terrivelmente relevante, a legibilidade é. A chave de abertura em uma linha por si só interrompe a conversa para um elemento sintático, até que seu olho se desloque para a próxima linha. Não é o que eu gosto.


A única vez que prefiro o primeiro estilo é quando preciso retornar imediatamente ou gerar um erro, caso algo esteja errado. Like if (parameter == null) return null;.
Nawfal

7

Ok, esta é uma pergunta antiga que foi respondida até a morte. Eu tenho algo a acrescentar.

Primeiro, só tenho que dizer UTILIZE O SUSPENSÃO. Eles só podem ajudar na legibilidade, e a legibilidade (para você e para os outros!) Deve estar muito alta na sua lista de prioridades, a menos que você esteja escrevendo montagem. Código ilegível sempre, sempre leva a erros. Se você achar que chaves usam muito espaço, seu método provavelmente é muito longo. A maioria ou todo o método deve caber dentro de uma altura de tela, se você estiver fazendo o certo, e o Find (F3) é seu amigo.

Agora, para minha adição: Há um problema com isso:

if (foo) bar();

Tente definir um ponto de interrupção que só será atingido se bar () for executado. Você pode fazer isso em C # colocando o cursor na segunda metade do código, mas isso não é óbvio e é um pouco trabalhoso. Em C ++, você não conseguiu fazer nada. Um de nossos desenvolvedores mais experientes trabalhando no código C ++ insiste em dividir as instruções 'if' em duas linhas por esse motivo. E eu concordo com ele.

Então faça o seguinte:

if (foo)
{
    bar(); //It is easy to put a breakpoint here, and that is useful.
}

2
Clique com o botão direito do mouse na barra e escolha Inserir ponto de interrupção ... Não é difícil. Conheça suas ferramentas.
Bob

Clicar com o botão direito na barra do indicador não faz nada; você quer dizer clique direito no texto? De qualquer forma, se você deseja que o ponto de interrupção seja atingido apenas quando a instrução "if" for verdadeira e "bar ()" estiver em sua própria linha, você poderá colocar o cursor em qualquer lugar dessa linha e pressionar F9 ou clicar com o botão esquerdo do mouse no botão margem do indicador. Se, no entanto, todo o código estiver em uma única linha, você deverá posicionar o cursor em "bar ()" ou clicar com o botão direito exatamente ali antes de pressionar F9, e clicar na margem do indicador não funcionará (coloca o ponto de interrupção no campo ' E se'). Não é "difícil", mas requer menos concentração quando o código está em duas linhas.
stone

Ah, ha ha, clique com o botão direito em "bar ()". Você quis dizer o texto. Peguei vocês. Claro, ou apenas pressione F9 ...
pedra

>> você tem que posicionar o cursor no "bar ()" ou clique direito exatamente lá antes de pressionar F9, (eu quis dizer a posição do cursor exatamente lá antes, quer pressionando F9 ou clique direito)
pedra

7

para impedir que o código com chaves ocupe muito espaço, eu uso a técnica recomendada no livro Código completo :

if (...) {
    foo();
    bar();
}
else {
    ...
}

Eu não entendo por que ele foi downmodded ele salva uma linha para cada par suporte i usá-lo o tempo todo
Eric

2
Isso é conhecido popularmente como estilo K&R. Baseado no livro The C Programming Language de Kernighan e Ritchie: en.wikipedia.org/wiki/The_C_Programming_Language_(book) . E isso não deve te deixar deprimido.
jmucchiello

Obrigado! Achei que era apenas gosto pessoal. Eu costumava achar essa sintaxe irritante, mas eu a adotei depois de ler Code Complete, e realmente a aprecio agora.
18419 Nathan Prather

eu estava lendo todas as respostas acima desta pensando "por que ninguém sugeriu isso ainda ???" Faz com que o colchete se alinhe com o bloco que está fechando, ou seja, "se" ou "enquanto", etc, não um "{" sem sentido. +1.
nickf

Se os chavetas abertos sempre são colocados nas linhas por si mesmos, então um ifque é seguido por uma única linha recuada pode ser visualmente reconhecido como controle de uma única instrução sem a necessidade de chavetas. O estilo de abertura por si só, portanto, economiza espaço em branco na situação em que uma ifinstrução controla algo que é semanticamente uma ação única (distinto de uma sequência de etapas que por acaso contém apenas uma única etapa). Por exemplo, if (someCondition)/ `lança novo SomeException (...)`.
Supercat

6

Digamos que você tenha algum código:

if (foo)
    bar();

e então alguém aparece e acrescenta:

if (foo)
    snafu();
    bar();

De acordo com a forma como está escrito, bar (); agora é executado incondicionalmente. Ao incluir as chaves, você evita esse tipo de erro acidental. O código deve ser escrito de maneira a dificultar ou impossibilitar tais erros. Se eu estivesse fazendo uma revisão de código e visse as chaves ausentes, especialmente espalhadas por várias linhas, eu criaria um defeito. Nos casos em que for justificado, mantenha-o em uma linha para que a chance de cometer esse erro seja novamente reduzida ao mínimo.


Esse ponto já foi levantado na questão.
Mike Scott

Na verdade não. Sim, ele mencionou o potencial para esse tipo de bug, mas eu estava falando sobre tornar seu código à prova de erros e remover o potencial de erro como parte das práticas recomendadas.
Elie

Existe realmente algo como código à prova de erros?
1012 Bob

Não, mas você pode torná-lo mais difícil. Leia "Os segredos mais bem guardados da revisão de códigos por pares", de Jason Cohen (veja o link ao lado de algumas páginas aqui) para ter uma idéia melhor de por que você faz isso.
Elie

Quem é esse Mike Scott e por que ele é a resposta da polícia? Sempre me surpreende que as pessoas tenham que dizer o que é óbvio. Então, por que Mike não continuou a comentar a descrição adicionada que os usuários estão postando sobre esse problema. Todas as respostas não estão se referindo à pergunta?
Br

6

Reduzir linhas não é realmente um bom argumento para descartar chaves. Se o seu método for muito grande, provavelmente deverá ser refatorado em pedaços menores ou reestruturado. Fazer isso sem dúvida aumentará a legibilidade mais do que simplesmente tirar aparelho.


5

Eu sempre os omito quando apropriado, como no seu primeiro exemplo. Código limpo e conciso que posso ver e entender, olhando para é mais fácil de manter, depurar e entender do que o código que tenho para rolar e ler linha por linha. Eu acho que a maioria dos programadores concorda com isso.

É fácil ficar fora de controle se você começar a aninhar várias cláusulas if / else e assim por diante, mas acho que a maioria dos programadores deve ser capaz de dizer onde traçar a linha.

Eu vejo isso como o tipo de argumento para if ( foo == 0 )vs if ( 0 == foo ). O último pode evitar bugs para novos programadores (e talvez até ocasionalmente para veteranos), enquanto o primeiro é mais fácil de ler e entender rapidamente quando você está mantendo o código.


4

Na maioria das vezes, ele está enraizado como um padrão de codificação, seja para uma empresa ou para um projeto de software livre.

Em última análise, alguém precisará grok seu código e é uma perda de tempo importante para cada desenvolvedor descobrir o estilo específico da seção de código em que está trabalhando.

Além disso, imagine que alguém esteja entre Python e uma linguagem Cish mais de uma vez por dia ... No Python, o recuo faz parte da semântica de blocos da linguagem e seria muito fácil cometer um erro como o que você cita.


+1 para comentar sobre python. Sempre fico impressionado com o quão "estúpido" posso ser ao alternar continuamente entre idiomas.
1133 Kena

3

Erre no lado mais seguro - apenas mais um bug que você potencialmente não precisará corrigir.

Pessoalmente, me sinto mais seguro se todos os meus blocos estiverem embrulhados em curlys. Mesmo para one-liners, essas são notações simples que evitam facilmente erros. Torna o código mais legível no sentido de que você vê claramente o que está no bloco para não confundir o corpo do bloco com as seguintes instruções fora do bloco.

Se eu tenho uma linha, normalmente a formato da seguinte maneira:

if( some_condition ) { do_some_operation; }

Se a linha for muito pesada, use o seguinte:

if( some_condition )
{
    do_some_operation;
}
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.