Odeio fazer referência a conteúdo pago, mas este vídeo mostra exatamente do que estou falando. Precisamente 12 minutos em Robert Martin olha para isso:
E diz: "Uma das minhas coisas favoritas a fazer é se livrar de aparelhos inúteis", como ele transforma isso:
Há muito tempo, em uma educação distante, fui ensinado a não fazer isso porque facilita a introdução de um bug adicionando outra linha recuada, pensando que é controlada pelo if
quando não é.
Para ser justo com o tio Bob, ele está refatorando um longo método Java para minúsculas funções que, eu concordo, são muito mais legíveis. Quando ele termina de mudar, (22.18) fica assim:
Gostaria de saber se isso deve validar a remoção dos aparelhos. Eu já estou familiarizado com as melhores práticas . O tio Bob pode ser desafiado nesse ponto? O tio Bob defendeu a ideia?
fonte
if
bloco é apenas uma linha, isso não importa. Se você precisar adicionar mais linhas, deve ser outra função que reduz oif
bloco de volta a uma linha (a chamada de função). Se você aderir a isso, os aparelhos simplesmente não importam - de maneira alguma .return (page==null) ? "" : includePage(mode,page);
se quiser ser mais conciso ... Pensei que o estilo sem chaves é legal até começar a desenvolver aplicativos profissionalmente. Ruído difuso, possíveis erros de digitação, etc. Os aparelhos, estando lá o tempo todo, economizam o tempo e as despesas gerais que você precisará para apresentá-los mais tarde.Respostas:
Legibilidade não é pouca coisa.
Eu tenho uma mente confusa quando se trata de aparelhos que envolvem um único método. Eu pessoalmente os removo para coisas como declarações de retorno de linha única, mas deixar esses aparelhos de fora realmente nos incomodou muito no último lugar em que trabalhei. Alguém adicionou uma linha de código a uma
if
instrução sem também adicionar as chaves necessárias e, por ser C, travou o sistema sem aviso.Eu nunca desafio alguém religioso a usar sempre aparelho depois desse pequeno fiasco.
Portanto, vejo o benefício da legibilidade, mas tenho plena consciência dos problemas que podem surgir quando você deixa esses aparelhos de lado.
Eu não me incomodaria em tentar encontrar um estudo ou a opinião publicada de alguém. Todo mundo tem uma (uma opinião), e por ser uma questão estilística, uma opinião é tão boa quanto qualquer outra. Pense sobre o assunto você mesmo, avalie os prós e os contras e faça sua própria mente. Se a loja em que você trabalha tiver um padrão de codificação que cubra esse problema, basta seguir isso.
fonte
-Wmisleading-indentation
.Você pode encontrar várias promoções ou rejeições publicadas de estilos sem suporte aqui ou aqui ou onde quer que sejam pintados os galpões de bicicletas.
Afastando-se dos galpões das bicicletas, lembra-se do grande bug SSL do OS X / iOS de 2014?
Sim, "causado" por blocos sem colchetes https://www.imperialviolet.org/2014/02/22/applebug.html
As preferências podem depender do estilo da chave. Se eu tivesse que escrever
Eu posso estar inclinado a economizar espaço também. Mas
usa apenas uma linha "extra".
Sei que você não perguntou, mas se estou trabalhando sozinho, sou herege. Se eu remover aparelho, prefiro
Ele não tem o mesmo problema visual que o bug no estilo SSL do iOS, mas salva ainda mais linhas "desnecessárias" do que o tio Bob;) Lê bem se você está acostumado a isso e tem uso convencional em Ruby (
includePage(mode, suiteSetup) unless suiteSetup.nil?
). Oh, bem, apenas saiba que existem muitas opiniões.fonte
} else[if(...)] {
, isso não adiciona nenhuma linha extra adicional, adicionando apenas uma linha extra ao longo da coisa toda.O tio Bob tem muitas camadas de defesa contra esse erro que não eram tão comuns quando "sempre usar aparelho" era a sabedoria predominante:
Acho que se alguém publicasse um desafio para o tio Bob, ele teria uma boa refutação com os pontos acima. Este é um dos erros mais fáceis de detectar cedo.
fonte
while(true);{break;}
. Se realmente existe um contexto válido para isso, levarei um tempo para superar isso.includePage()
não é uma macro mal escrita com mais de uma instrução?Na maioria das vezes, essa é uma preferência pessoal, mas há algumas coisas a considerar.
Possíveis erros
Embora se possa argumentar que os erros causados por esquecer de adicionar-in chaves são raros, pelo que tenho visto que eles não acontecem de vez em quando (não esquecer a famosa Goto IOS falhar bug). Portanto, acho que isso deve ser um fator ao considerar seu estilo de código (algumas ferramentas alertam sobre indentação enganosa , portanto depende da sua cadeia de ferramentas) .
Código válido (que pode parecer um bug)
Mesmo assumindo que o seu projeto não sofrem de tais erros, ao ler o código que você pode ver alguns blocos de código que se parecem com eles poderia ser erros - mas não são, tendo alguns dos seus ciclos mentais.
Começamos com:
Um desenvolvedor adiciona um comentário útil.
Mais tarde, um desenvolvedor se expande.
Ou adiciona um bloco aninhado:
Ou usa uma macro:
"... Como as macros podem definir várias linhas de código, a macro usa
do {...} while (0)
para várias linhas? Deve ser porque está no nosso guia de estilo, mas é melhor verificar apenas por precaução!"Os exemplos acima são todos códigos válidos; no entanto, quanto mais conteúdo no bloco de códigos, mais você precisa ler para garantir que não haja erros.
Talvez o seu estilo de código defina que os blocos de várias linhas exigem uma chave (não importa o que aconteça, mesmo que não sejam códigos) , mas vi esses tipos de comentários sendo adicionados ao código de produção. Quando você o lê, há uma pequena dúvida de que quem quer que tenha editado essas linhas pela última vez se esqueceu de adicionar uma chave, às vezes sinto que a necessidade de verificar duas vezes está funcionando conforme o esperado (especialmente ao investigar um bug nesta área do código) .
Diff Noise
Uma razão prática para usar chaves para linhas únicas é reduzir o ruído diferencial .
Ou seja, mudando:
Para:
... faz com que a linha condicional apareça em um diff como sendo alterada, isso adiciona uma sobrecarga pequena, mas desnecessária.
Dito isto, nem todas as ferramentas suportam diffing baseado em palavras, diff (svn, git, hg ... etc) será exibido como se toda a linha tivesse mudado, mesmo com ferramentas sofisticadas, às vezes você pode precisar olhar rapidamente sobre uma linha simples diff baseado em para ver o que mudou.
git blame
) mostrarão a linha como sendo alterada, tornando o rastreamento da origem de uma linha mais uma etapa para encontrar a mudança real .Ambos são pequenos e dependem de quanto tempo você gasta na revisão ou rastreamento de código que confirma as linhas de código alteradas.
Um inconveniente mais tangível de ter alterações de linhas extras em um diff, é mais provável que alterações no código causem conflitos que se fundem e precisam ser resolvidos manualmente .
Há uma exceção a isso, para bases de código que possuem
{
sua própria linha - não é um problema.O argumento diff noise não se aplica se você escrever neste estilo:
No entanto, essa não é uma convenção tão comum, portanto contribuindo principalmente para a resposta de completude (não sugerindo que os projetos usem esse estilo) .
fonte
{
-own-line. Eu realmente odeio esse estilo e não gosto de trabalhar em projetos nos quais esse estilo é necessário. Talvez com isso em mente, eu ache um pouco menos frustrante ter que codificar dessa maneira. A densidade do código é importante. Se você puder ver todas as funções no monitor de uma só vez, poderá entender mais facilmente tudo. Eu gosto de deixar linhas em branco entre blocos de código separados dentro de uma função para facilitar a leitura (para agrupar instruções relacionadas), e ser forçado a perder espaço em outros lugares torna as quebras pretendidas mais fracas.{
on-your-own-line', apenas o incluiu para completar as respostas. Quanto à confiança na utilização de macrosdo{}while(0)
, acho que o problema é que você pode confiar nela quase o tempo todo. O problema é que acidentes acontecem, erros podem passar por revisão de código ... e erros podem ser introduzidos que não seriam de outra forma.Anos atrás, fui trazido para depurar algum código C. O bug era muito difícil de encontrar, mas acabou se resumindo a uma declaração como:
E aconteceu que a pessoa que o havia escrito definiu
foo
como macro. Uma macro com duas linhas de código. E, claro, apenas a primeira dessas duas linhas estava sujeita aoif
. (Portanto, a segunda linha foi executada incondicionalmente.)Isso pode ser absolutamente exclusivo para C e seu pré-processador - que faz substituições antes da compilação - mas nunca esqueci. Esse tipo de coisa deixa uma marca em você e por que não jogar pelo seguro - especialmente se você usa uma variedade de idiomas e cadeias de ferramentas e não pode ter certeza de que essas travessuras não sejam possíveis em outros lugares?
Agora eu recuo e uso aparelhos de maneira diferente de todos os outros, aparentemente. Para uma única linha
if
, eu faria:portanto, não são necessárias linhas adicionais para incluir os chavetas.
fonte
do { ... } while(0)
loop. Isso não apenas garantirá que sempre seja tratado corretamente porif()
declarações anexadas , mas também que o ponto-e-vírgula no final da declaração seja engolido corretamente. Quem não conhece essas regras simples, simplesmente não deve escrever macros de pré-processador. A defesa no local de chamada é o lugar errado para se defender."Tio Bob" pode ter sua opinião, você pode ter sua opinião. Não há necessidade de desafiá-lo.
Se você deseja apelar à autoridade, use Chris Lattner. Em Swift, as declarações se perderam entre parênteses, mas sempre vêm com chaves. Sem discussão, faz parte do idioma. Portanto, se "Tio Bob" começar a remover chaves, o código para de compilar.
Examinar o código de outra pessoa e "se livrar de aparelhos inúteis" é um mau hábito. Só causa trabalho extra quando o código precisa ser revisado e quando conflitos são desnecessariamente criados. Talvez "Tio Bob" seja um programador tão bom que ele não precise de revisões de código? Perdi uma semana da minha vida porque um dos principais programadores mudou "if (p! = NULL)" para "if (! P)" sem uma revisão de código, oculta no pior lugar possível.
Este é principalmente um debate de estilo inofensivo. Chaves tem a vantagem de poder inserir outra linha de código sem adicionar chaves. Como uma declaração de log ou um comentário (se seguido de um comentário seguido de uma declaração é horrível). declaração na mesma linha como se tivesse a desvantagem prática de que você tem problemas com muitos depuradores. Mas faça o que você preferir.
fonte
Minhas razões para não remover chaves são:
reduzir a fadiga da decisão. Se você sempre usa aparelho, nunca precisa decidir se vai precisar de aparelho ou não.
reduzir o arrasto desenvolvimento: mesmo se você se esforçar para , eventualmente, extrair todas as várias linhas de lógica para métodos, tendo que converter um braceless se a um preparou se para adicionar lógica é um pouco chato de arrasto desenvolvimento. Portanto, há o esforço de remover os chavetas e o esforço de adicioná-los novamente quando você precisar de mais código. Minúsculo, mas irritante.
fonte
Um jovem colega de trabalho disse que os aparelhos que consideramos redundantes e supérfluos são de fato úteis para ele. Não me lembro exatamente o porquê, mas se isso permite que ele escreva um código melhor mais rapidamente, esse é o único motivo para mantê-lo.
Fwiw, chegámos a acordo sobre um compromisso que colocá-los em uma linha não faz tais pré-condições curtas un legível / distraindo-me. Por exemplo
Também aponto que essas pré-condições introdutórias são frequentemente declarações de fluxo de controle para o corpo (por exemplo, a
return
); portanto, o medo de adicionar uma segunda declaração que deveria estar sob a mesma condição e o esquecimento de escrever chaves são discutíveis. Uma segunda declaração sob a condição seria um código morto de qualquer maneira e não faria sentido.Suspeito que a fluência na questão da leitura seja causada pelo fato de o analisador de cérebros da pessoa ter que usar o aparelho como parte da declaração condicional. Essa não é uma representação precisa da gramática do C ++, mas pode ser um efeito colateral do aprendizado de outras línguas primeiro, onde é esse o caso.
fonte
Tendo assistido a esse vídeo agora, notei que a eliminação de chaves facilita a visualização de onde o código ainda precisa ser refatorado. Se você precisar de aparelhos, seu código provavelmente poderá ser um pouco mais limpo.
Dito isto, quando você está em uma equipe, a eliminação de aparelhos provavelmente levará a um comportamento inesperado algum dia. Eu digo, mantenha-os, e você economizará muitas dores de cabeça quando as coisas derem errado.
fonte
Se o seu código for bem testado por unidade , esse tipo de "bug" explodirá na cara.
Limpar o código, evitando colchetes inúteis e feios, é uma prática que sigo.
fonte