Domanda

Sono nuovo nella programmazione e mi chiedo se esiste un modo corretto di ordinare la logica della struttura di controllo.

Sembra più naturale verificare prima il caso più probabile, ma ho la sensazione che alcune strutture di controllo non funzioneranno se non controllano tutto ciò che è falso per arrivare a qualcosa di vero (deduzione logica?)

Sarebbe difficile adattarsi a questa visione 'negativa', preferisco una visione più positiva, presumendo che tutto sia vero :)

È stato utile?

Soluzione

Nella maggior parte dei casi, la leggibilità è più importante della velocità di esecuzione. Quindi ci provo ottimizzare per facilità di comprensione, utilizzando il seguente approccio:

Tutto " asserzione " i controlli vengono effettuati in anticipo. questo garantisce che tutti i casi errati vengono affrontati all'inizio. questo è particolarmente importante per i controlli puntatore null, ad esempio

    if(arg == null){ 
      throw new IllegalArgumentException();  // harsh (correct)
    }
    // or 
    if(arg == null){
        arg = "";  // forgiving (lazy)
    }

Quindi, provo a verificare 1 condizione solo in ogni if-statement. anziché

    if(condition1 && condition2) {
        ...
    } else {
        ...
    }

generalmente preferisco

    if(condition1) {
        if(condition2) {
            ...
        } else {
            ...
        }
    } else {
        ...
    }

Questo approccio è più semplice per l'impostazione dei punti di interruzione e rende la logica più vaga.

Evito le negazioni; anziché

    if(! condition) {
        ...a...
    } else {
        ...b...
    }

le cose sono meglio riorganizzate in

    if(condition) {
        ...b...
    } else {
        ...a...
    }

Infine, tutti i metodi che restituiscono un risultato booleano dovrebbero avere un "positivo" nome che indica il significato dei risultati:

    boolean checkSomething(Something x){ ... }     // bad -- whats the result?
    boolean isSomethingInvalid(Something x){ ... } // better, but ...
    boolean isSomethingValid(Something x){ ... }   // best, no "mental negation"

Altri suggerimenti

Esiste un'eccellente discussione proprio su questo argomento nel Codice completo di McConnell. È un libro che consiglio vivamente. Comunque la discussione pertinente è alle pagine 706-708 della prima edizione o pag. 749-750 della seconda edizione (grazie zoccolo). Da quel libro:

  

Organizza i test in modo che quello sia quello   è il più veloce e più probabile che sia vero   eseguita per prima. Dovrebbe essere facile   passare attraverso il caso normale e se   ci sono inefficienze, dovrebbero   essere in fase di elaborazione delle eccezioni.

Vi sono aspetti da considerare oltre al valore dell'istruzione condition. Ad esempio, se le dimensioni dei blocchi di codice sono significativamente diverse, è consigliabile inserire prima il blocco piccolo in modo che sia più facile da vedere. (Se il blocco più grande è veramente grande, potrebbe essere necessario eseguire il refactoring o forse estrarlo in un metodo separato.)

if( condition is true ) {
    do something small;
} else { 
    do something;
    and something else; 
    . . .
    and the 20th something;
}

All'interno della condizione, sì, ci sono alcune lingue che smetteranno di valutare un'espressione quando una parte di essa è falsa. Questo è importante da ricordare se includi una sorta di logica definita nel tuo codice: se la tua lingua valuta l'intera espressione, dovresti farlo:

if( variable is defined ) {
    if( variable == value ) {
        ...
    }
}

piuttosto che questo:

if( (variable is defined) && (variable == value) ) {
     ...
}

Non credo ci sia un " corretto " modo di progettare le tue condizioni. Se lavori per un'azienda con standard di codifica, dovresti verificare se è incluso negli standard. (L'ultimo posto in cui ho lavorato aveva un numero ragionevole di standard definiti, ma non ho specificato come scrivere la logica condizionale.)

In generale, verificherei prima gli elementi imprevisti, il che mi costringe a gestire un flusso eccezionale del programma.

In questo modo, posso lanciare eccezioni / interrompere operazioni prima di iniziare " impostazione " per il normale flusso del programma.

Mi propongo di strutturare le mie condizioni in modo da ridurre al minimo la quantità di informazioni che il lettore deve prendere. A volte è più facile testare il negativo per dimostrare il positivo:

Un esempio: il test per vedere se un periodo di 2 date si interseca con un altro periodo di 2 date è più facile da scrivere come test di nessuna intersezione di 2 periodi

Se si tratta di una semplice domanda sì o errore, di solito strutturo le cose in modo che il ramo di gestione degli errori sia la clausola else. Se si tratta di una domanda sì o no (ovvero nessuna delle due filiali è un errore), è puramente una chiamata di giudizio su ciò che sembra più naturale. Se ci sono molti test che devono essere fatti prima che il cuore del codice possa essere eseguito, di solito provo a strutturare le cose in modo che i test negativi vengano prima e in qualche modo salti il ??codice che segue (ritorna dalla funzione, rompi o continua da un ciclo).

O / Or. In genere, tuttavia, utilizzo l'approccio "negativo".

if (! qualcosa) {

}

Questo è un po 'fuori dalla portata della domanda, ma in genere vuoi anche che i tuoi metodi falliscano rapidamente. Per questo motivo tendo a fare tutta la mia convalida dell'argomento all'inizio del metodo, anche se non userò l'argomento fino a tardi nel codice. Ciò danneggia la leggibilità, ma solo nel caso in cui il metodo sia veramente lungo (per vederlo è necessario scorrere fuori dallo schermo). Ovviamente, questo è un odore di codice in sé e tende a essere riformulato.

D'altra parte, se il controllo non è semplice e lo passerò a un altro metodo che lo controllerà comunque, non ripeterò il codice per verificare il metodo corrente. Come per la maggior parte delle cose c'è un equilibrio.

(Contesto: Java)

READABILITY1: la condizione che si risolve in un blocco di codice più piccolo inizia per prima

if (condition) {
  smallBlock();
} else {
  bigBlockStart();
  ........
  bigBlockEnd();
}

READABILITY2: l'affermazione positiva inizia per prima, poiché è più facile non notare un segno di negazione

EFFETTUARE IL SENSO: asserire tutte le pre-condizioni per un metodo usando Assert.blabla () e usare i condizionali solo per ciò che fa il metodo.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top