As declarações if / else devem ser organizadas pela conscientização dos casos ou pela dificuldade de lidar com eles?

18

Em algum código que estou escrevendo agora, tenho algo parecido com isto:

if (uncommon_condition) {
    do_something_simple();
} else {
    do();
    something();
    long();
    and();
    complicated();
}

Parte de mim pensa: "Está tudo bem do jeito que está escrito. Casos simples devem ser os primeiros e casos mais complicados devem ser os próximos." Mas outra parte diz: "Não! O elsecódigo deve ficar abaixo do if, porque ifé para lidar com casos incomuns e elsepara todos os outros casos". Qual é correto ou preferível?

EMBLEMA
fonte
4
Ordem por simplicidade / compreensibilidade das condições! O restante pode ser resolvido por otimizadores, preditores de ramificação e refatoração.
Marjan Venema
É por isso que recebemos muito dinheiro: tomar essas decisões difíceis.

Respostas:

24

Ordem pela probabilidade de serem executadas. As condições mais comuns, mais prováveis ​​etc. devem ser as primeiras.

A "dificuldade de lidar com eles" deve ser tratada pela estrutura de código, abstração etc. no exemplo, o bloco else pode ser refatorado para chamada de método único. Você deseja que suas ifcláusulas estejam no mesmo nível abstrato.

if ( ! LotteryWinner ) {
    GoToWorkMonday();
} else {
    PlanYearLongVacation();
}
radarbob
fonte
6
Para obter o desempenho que eu poderia concordar. Mas, novamente, a maioria dos otimizadores e preditores de ramificação são perfeitamente capazes de cuidar disso. Para facilitar a leitura que eu poderia concordar se o caso mais provável tem significativamente mais linhas do que o caso menos provável. Mas para mim isso indicaria mais cedo a necessidade de extrair um método do que usar a not. Pessoalmente, eu me concentraria em evitar notcondições. Foi provado que eles induzem mais carga cognitiva a entender do que condições "positivas" e são prejudiciais à legibilidade / compreensão do código. Costumo usá-los apenas em declarações de guarda.
Marjan Venema
2
@MarjanVenema, entendo seu ponto de vista sobre "não". Mas o duplo negativo é o real "não" WTF. No outro dia, encontrei isso em nosso código doesNotAllowxxFiles = false. Ruim o suficiente, mas, em seguida, fazer issoif(! doesNotAllowxxFiles)
radarbob
Sim, negativas duplas, negativos combinados com e de e / ou ou do e negativos combinados com um método / var com não no nome, buscar o meu cérebro em uma torção cada vez :-) (sic!)
Marjan Venema
Se você está tendo dificuldade para entender o que está acontecendo, eu acho que muitas vezes é útil para fazer algo como: simpleBool = && randomFlag ((complexBool || randomfFlag)!)!
TruthOf42
2
Eu concordo com você, exceto pela existência de cláusulas de guarda (que sempre têm a condição excepcional na parte THEN da declaração SE, não a condição comum).
Robert Harvey
5

Tente melhorar a legibilidade. Uma maneira é colocar o bloco de código mais longo na parte else.

if (s == null)
     // short code
else 
     // long 
     // code
     // block

é mais legível do que

if (s != null)
    // long
    // code
    // block
else
    // short code
CWallach
fonte
2
por que é mais legível? Não vejo nenhuma diferença entre os dois em termos de legibilidade
John Demetriou
2
@JohnDemetriou The Else é mais visível se o Then for curto. As pessoas examinam primeiro a estrutura e depois atribuem significado a ela. Código sem Else é diferente do código com um, portanto, tornar o Else mais visível é mais compreensível. (Todas as outras coisas sendo iguais, às terças-feiras, quando não está chovendo, etc)
4

Nenhuma regra fixa, como tal, ouvi falar sobre o uso, mas sigo assim

if(usual)
{
(more often)
}
else (unusual)
{
(rarely occurring)
}

Mas se ambos tiverem a mesma função com propriedades diferentes, é melhor optar por algo incomum primeiro do que o habitual, para que você possa salvar uma instrução.


if(x == 0)  // 1
  {x = 1;}  // 2
else
  {x = 2;}  // 3

Para o código de montagem acima, o código será algo como isto:

1. 000d 837DFC00        cmpl    $0, -4(%ebp)
   0011 7509            jne .L2

2. 0013 C745FC01        movl    $1, -4(%ebp)
   001a EB07            jmp .L3

    .L2:
3.001c C745FC02         movl    $2, -4(%ebp)

        .L3:

Se a condição interna se for verdadeira, o fluxo será 1-> 2 (4 intruções)
Se a condição interna for falsa, o fluxo será 1-> 3 (3 intruções)

Portanto, é melhor colocar eventos incomuns ou que ocorrem raramente, caso sejam parte e condição normal, para que possamos salvar uma instrução toda vez ;-)

Santosh Mudhol
fonte
2

Descobri que o padrão oposto exato leva a uma leitura mais fácil do código e reduz ou elimina instruções if aninhadas. Eu me refiro a isso como um padrão de "manopla". (Na narração de histórias, uma luva seria uma série de desafios que precisam ser enfrentados com êxito antes que a tarefa final seja concluída.) Ao lidar com seus casos extremos primeiro , você permite que o corpo principal do seu código seja limpo e conciso:

if(gauntlet_1){ handle the first gauntlet condition }; 
if(gauntlet_2){ handle the second gauntlet condition };
...
// All preconditions (gauntlets) have been successfully handled

// Perform your main task here
Byron Jones
fonte
Portanto, a parte "manopla da manivela" teria que ser uma transferência de controle, como uma declaração de arremesso ou retorno, ou teria que realmente corrigir a falha. Algumas pessoas desaprovam uma série de declarações if ... return, mas eu não faço e acho que isso realmente facilita a leitura do código, como você disse.
1
Se a condição da luva for algo que impediria o êxito da função, ela retornará um erro imediatamente. Se a condição da manopla puder ser tratada, eu o faço antes de entrar no corpo principal do código sempre que possível. Eu estou principalmente tentando evitar instruções IF aninhadas, que na minha experiência são uma das principais causas de erros de codificação obscuros e difíceis de depurar.
Byron Jones
0

Para mim, é mais sobre as condições do que sobre a complexidade do código que eles executam. Você precisa solicitar as condições para capturar primeiro condições incomuns, depois as mais comuns depois. Além disso, se o código else for realmente longo e complicado, eu provavelmente faria um sub para isso, para manter a parte condicional óbvia para o leitor.

Steve Thomas
fonte
-1

Eu não tenho uma regra fixa, mas geralmente eu a sigo - primeiro, considere onde há um padrão de design ausente que levará isso em consideração. Caso contrário, escrevo para que a condição no if seja a mais claramente compreendida. Ou seja, evitando duplos negativos e similares.

Don Branson
fonte