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 usings
sem 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:
- É 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.
- 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?
- Existe outro argumento que estou perdendo?
Respostas:
Na verdade, a única vez que realmente me mordeu foi quando eu estava depurando e comentei o bar ():
Fora isso, eu costumo usar:
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.
fonte
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:
Um pouco mais rápido do que eu li:
Eu o li um pouco mais devagar se parece com isso:
Eu li isso significativamente mais lento que o anterior:
porque não posso deixar de lê-lo novamente, apenas no caso, e me pergunto se o autor pretendia:
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.
fonte
Se for algo pequeno, escreva assim:
Se for longo o suficiente para dividir em duas linhas, use chaves.
fonte
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:
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.
fonte
!a || !b
) do que com (!a
) ou sem (a && !b
) chaves adicionais.Isso nem sempre é considerado uma má prática. As Diretrizes de codificação do projeto mono sugerem não usar chaves, se não for necessário. O mesmo para os padrões de codificação GNU . Eu acho que é uma questão de gosto pessoal, como sempre, com os padrões de codificação.
fonte
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).
fonte
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.
fonte
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:
eu prefiro
fonte
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 {}.
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.
fonte
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.
O que veio depois foi
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.
Depois de assistir a um desenvolvedor de superstar fazendo isso.
fonte
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.
fonte
if
instrução controla um bloco, mas evita a necessidade de um bloco nos casos em que umaif
instrução controla uma única ação em vez de um bloco.Estou muito feliz por:
Pessoalmente, não vejo por que
é 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
vs
é terrivelmente confuso, então eu sempre o escrevo como:
Sempre que possível, uso operadores ternários, mas nunca os aninho .
fonte
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.
fonte
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.
fonte
Sempre há exceções, mas eu argumentaria contra a omissão de chaves somente quando estiver em uma das formas:
Caso contrário, não tenho nenhum problema com isso.
fonte
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
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.)
fonte
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:
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.
fonte
Das três convenções:
e:
e (que representam qualquer estilo de indentação usando uma chave de abertura e fechamento):
Eu prefiro o último como:
fonte
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.
fonte
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;
E outro assim;
Prefiro escolher um estilo geral e segui-lo :)
fonte
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:
fonte
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:
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:
Dessa forma, o desenvolvedor que precisa adicionar bar () à condição estaria mais apto a reconhecer a falta de chaves e adicioná-las.
fonte
Use algum julgamento pessoal.
está bem por si só. A menos que você esteja realmente preocupado com idiotas colocando algo assim depois:
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:
Qual foi o meu favorito desde que me lembro. Além disso:
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.
fonte
if (parameter == null) return null;
.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:
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:
fonte
para impedir que o código com chaves ocupe muito espaço, eu uso a técnica recomendada no livro Código completo :
fonte
if
que é 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 umaif
instruçã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 (...)`.Digamos que você tenha algum código:
e então alguém aparece e acrescenta:
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.
fonte
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.
fonte
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 )
vsif ( 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.fonte
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.
fonte
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:
Se a linha for muito pesada, use o seguinte:
fonte