Le dichiarazioni if ​​/ else dovrebbero essere organizzate in base alla rarità dei casi o alla difficoltà di affrontarli?


18

In alcuni codici che sto scrivendo proprio ora, ho qualcosa del genere:

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

Una parte di me pensa "Va bene il modo in cui è scritto. I casi semplici dovrebbero andare prima e quelli più complicati dovrebbero andare dopo". Ma un'altra parte dice: "No! Il elsecodice dovrebbe andare sotto il if, perché ifè per gestire casi insoliti ed elseè per gestire tutti gli altri casi." Qual è corretto o preferibile?


4
Ordina per semplicità / comprensibilità delle condizioni! Il resto può essere curato da ottimizzatori, predittori di filiali e refactoring.
Marjan Venema,

Questo è il motivo per cui veniamo pagati un sacco di soldi: prendere queste decisioni difficili.

Risposte:


24

Ordina per la loro probabilità di essere giustiziati. Le condizioni più comuni, più probabili, ecc. Dovrebbero andare per prime.

La "difficoltà di gestirli" dovrebbe essere affrontata dalla struttura del codice, dall'astrazione, ecc. Nell'esempio il blocco else potrebbe essere refactored alla singola chiamata di metodo. Volete che le vostre ifclausole siano allo stesso livello astratto.

if ( ! LotteryWinner ) {
    GoToWorkMonday();
} else {
    PlanYearLongVacation();
}

6
Per la prestazione potrei essere d'accordo. Ma ancora una volta, la maggior parte degli ottimizzatori e predittori di ramo sono perfettamente in grado di occuparsene. Per leggibilità, potrei essere d'accordo sul fatto che il caso più probabile abbia molte più righe rispetto al caso meno probabile. Ma per me ciò indicherebbe prima la necessità di estrarre un metodo che di usare a not. Personalmente mi concentrerei sull'evitare le notcondizioni. È stato dimostrato che inducono più carico cognitivo a comprendere delle condizioni "positive" e sono dannose per la leggibilità / comprensibilità del codice. Tendo a usarli solo nelle dichiarazioni di guardia.
Marjan Venema,

2
@MarjanVenema, vedo il tuo punto sul "non" ing. Ma il doppio negativo è il vero "non" WTF. L'altro giorno mi sono imbattuto in questo nel nostro codice doesNotAllowxxFiles = false. Abbastanza male, ma poi falloif(! doesNotAllowxxFiles)
radarbob

Sì, doppi negativi, negativi combinati con and's e / o's (sic!) E negativi combinati con un metodo / var con Not nel nome, mi fanno venire il cervello ogni volta :-)
Marjan Venema

se ti accorgi che hai difficoltà a capire cosa sta succedendo, penso che sia spesso utile fare cose del tipo: simpleBool = (! (complexBool || randomfFlag)) &&! randomFlag
TruthOf42

2
Concordo con te, fatta eccezione per l'esistenza di clausole di guardia (che hanno sempre la condizione eccezionale nella parte THEN della dichiarazione IF, non la condizione comune).
Robert Harvey,

5

Cerca di migliorare la leggibilità. Un modo è posizionare il blocco di codice più lungo nella parte else.

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

è più leggibile di

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

2
perché è più leggibile? Non vedo alcuna differenza tra i due in termini di leggibilità
John Demetriou,

2
@JohnDemetriou The Else è più visibile se Then è breve. Le persone cercano prima la struttura, quindi assegnano un significato ad essa. Il codice senza Else è diverso dal codice con uno, quindi rendere più visibile l'Else è più comprensibile. (A parità di altre condizioni, il martedì quando non piove, ecc.)

4

Nessuna regola fissa in quanto tale ho sentito parlare dell'uso ma seguo così

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

Ma se entrambi hanno la stessa funzione con proprietà diverse, allora è meglio andare prima inusuali prima del solito in modo da poter salvare un'istruzione.


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

Per il codice di assemblaggio sopra il codice sarà qualcosa del genere:

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 la condizione dentro è vera, allora il flusso è 1-> 2 (4 istruzioni)
SE la condizione dentro è falsa, allora il flusso è 1-> 3 (3 istruzioni)

Quindi è meglio mettere eventi insoliti o che si verificano raramente in parte e in condizioni normali in modo da poter salvare un'istruzione ogni volta ;-)


2

Ho scoperto che l'esatto modello opposto porta a una lettura più semplice del codice e riduce o elimina le istruzioni if ​​annidate. Mi riferisco a questo come a un modello "guanto". (Nel racconto di storie, un guanto sarebbe una serie di sfide che devono essere affrontate con successo prima che il compito finale sia completato.) Gestendo prima i casi limite , si consente al corpo principale del codice di essere pulito 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

Quindi la parte "handle gauntlet" dovrebbe essere un trasferimento di controllo, come un'istruzione di lancio o di ritorno, o dovrebbe effettivamente correggere l'errore. Alcune persone aggrottano le sopracciglia su una serie di dichiarazioni if ​​... return, ma io no e penso che in effetti renda il codice più facile da leggere, come hai detto.

1
Se la condizione del guanto è qualcosa che impedisce la riuscita della funzione, restituisce immediatamente un errore. Se è possibile gestire la condizione del guanto, lo faccio prima di inserire il corpo principale del codice ogni volta che è possibile. Sto principalmente cercando di evitare dichiarazioni IF annidate, che nella mia esperienza sono una delle cause primarie di errori di codifica oscuri e difficili da eseguire il debug.
Byron Jones,

0

Per me si tratta più delle condizioni che della complessità del codice che eseguono. È necessario ordinare le condizioni in modo da intrappolare prima le condizioni insolite, quindi quelle più comuni dopo. Inoltre, se il codice else è davvero lungo e complicato, probabilmente farei un sub per questo, per mantenere ovvia la parte condizionale per il lettore.


-1

Non ho una regola fissa, ma generalmente seguo questo: prima di tutto, considera dove c'è un modello di progettazione mancato che lo terrà conto. In caso contrario, lo scrivo in modo che la condizione in if sia la più chiaramente compresa. Cioè, evitando doppi negativi e simili.


Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.