Replace conditional with...



Conditional statements like "If" and "switch" multiply the number of possible flows the code execution can follows. So they increase the complexity and the number of tests required to verify the code.

=> Conditional statements are time and effort (costs €€€) multipliers






Here is a list of known techniques to eliminate conditionals :



  1. Replace conditional with polymorphism (look also the patterns template method and pluggable selector and  abstract factory)

  2. The patterns Null Object and Special Case

  3. The pattern State

  4. The pattern Pluggable Object

  5. The pattern Strategy

  6. The pattern Composite

  7. The pattern Visitor

  8. Replace conditional with a Dictionary (or with a conversion operator)

  9. Replace Conditional Dispatcher with Command

  10. Linearize the algorithm

Look also  "Replace nested conditionals with guards" to simplify the conditional before eliminating it.

some solutions like 6 and 10 completely eliminate the IF, some like 1 and 2 eliminate the duplication of the IF putting the IF logic in just one place, some like 8 reuse a IF logic tha is already implemented in the Framework so it prevent from creating a new IF.


Now I challenge you, show me an IF that cannot be eliminated !


Edit 5-Sep-2010:

  1. Replaced IF used to emulate break; or continue; in a nested FOR loop with a Return after extracting the nested IF in a new method. See Structured programming, Edsger Dijkstra (1969)
See also an example of code after removing IF and before full of IF here.

Look also: http://www.antiifcampaign.com/

Tags :   |  |  |  |

Print | posted @ mercoledì 21 aprile 2010 02:58

Comments on this entry:

Gravatar # re: Replace conditional with...
by Antonio Ganci at 21/04/2010 13:28

> Now I challenge you, show me an IF that cannot be eliminated !

l'elenco che hai scritto serve per togliere gli if sul valore di variabili. Ci sono if che non si possono togliere perchè descrivono un comportamento mi spiego meglio:
if queue.IsEmpty
non lo puoi togliere.
Mentre:
If queue == null
if elementType == ...
ecc. si possono togliere.
Gravatar # re: Replace conditional with...
by Antonio Ganci at 21/04/2010 15:05

Volendo puoi fare così:
IF(queue.IsEmpty, true actions, false actions)

dove

void IF(bool condition, Action trueAction, Action falseAction)

o qualcosa di simile, così avresti un solo if nel calcolo della complessità ciclomatica, ma secondo me non andresti verso una migliore leggibilità del codice e avresti solo spostato l'if da un altra parte.
Non credo sia questo l'obiettivo del post di Luka ma quello di andare verso una minore complessità effettiva.
Gravatar # re: Replace conditional with...
by LudovicoVan at 21/04/2010 18:59

Personalmente sono daccordo: a volte il branching davvero denota una scarsa familiarita' con -per esempio- il poliformismo e persino le piu' elementari tecniche di programmazione strutturata; d'altra parte anche gli if/switch ecc. hanno un loro ruolo basilare nell'implementazione degli algoritmi in un linguaggio imperativo, e in quel caso fare a meno degli if adottando tecniche piu' di alto livello aggiunge solo complessita' non necessaria, mentre sicuramente toglie alla leggibilita'.

Fra parentesi, noterei che gli automi a stati finiti rappresentano un modello computazionale relativamente semplice, che non risolve le nostre esigenze di programmazione in generale: per esempio un parser vero e proprio si puo' fare con gli automi a stati finiti (o le sole regular expressions).

-LV
Gravatar # re: Replace conditional with...
by LudovicoVan at 21/04/2010 19:01

> per esempio un parser vero e proprio si puo' fare con gli automi a stati finiti

Pardon, ovviamente intendo *non* si puo' fare...

-LV
Gravatar # re: Replace conditional with...
by LudovicoVan at 21/04/2010 19:09

> quel "If sounds.Contains(keyCode)" andrebbe spostato dentro l'indexer sounds[keyCode] facendo in modo che restituisca il defaultSound per i tasti/keyCode non esplicitamente definiti

Ti risponderei che dipende: metti che e' un view-model, magari ha davvero senso restituire un default (ma comunque dipenderebbe dai requisiti), se invece fosse un model o una data class che ci sta sotto, restituirei il null e lascerei al client decidere se e come gestire la situazione, intercettare eccezioni, sollevare errori, e quant'altro.

Piu' in generale, mi sembra che il problema come al solito sia riuscire di volta in volta a capire dove sta quella soglia oltre la quale l'utile e dilettevole diventa inutile e addirittura dannoso.

My 2c, interessante dicussione.

-LV
Gravatar # re: Replace conditional with...
by Antonio Ganci at 21/04/2010 19:35

@Antonio
quel "If sounds.Contains(keyCode)" andrebbe spostato dentro l'indexer sounds[keyCode] facendo in modo che restituisca il defaultSound per i tasti/keyCode non esplicitamente definiti

Si ok, sono d'accordo l'ho scritto perchè si capisse all'interno di un commento del blog.
Comunque mccabe rimarrebbe uguale ;-).

> o meglio ancora inizializzi la collezione sounds per tutti i keycode col suono di default e cosi non hai nemmeno un if.

Non sono d'accordo perchè non beccheresti le combinazioni con shift + tasto, ecc.
Gravatar # re: Replace conditional with...
by miv at 25/04/2010 18:57

piu' che altro vorrei capire se in un caso come questo vale la pena implementare altre classi/metodi per evitare 'una' condizione
Gravatar # re: Replace conditional with...
by vic at 26/04/2010 01:18

ok, se cambiamo la questione originale:

Now I challenge you, show me an IF that cannot be eliminated !


in "gli if non si devono ripetere ma isolare"
(come peraltro ogni altro tipo di logica)

direi che siamo tutti d'accordo...

poi, sicuramente, alcuni if si possono realmente eliminare, ma non tutti; questi possono di norma essere isolati.
Gravatar # re: Replace conditional with...
by Tonino at 26/04/2010 18:26

Interessante discussione.

Piccola esperienza:
Mi sono trovato a gestire una serie classi che applicavano regole di validazione, precedentemente gestite con degli "if", che venivano a volte rimesse in discussione, come requisiti, o in base al tipo di utente.
(un dato e' obbligatorio per qualcuno, non obbligatorio per qualcun'altro, e in un dato momento le cose cambiano)

Le regole di validazione erano codificata un po' come nel seguente modo:
if (string.IsNullOrEmpty(Nazionalita)) strErrore += ....


e di "if" ve ne erano un po' tanti, per ogni classe e per ogni tipo di dato coinvolto in quella classe.

Ho sostituito gli if (non tutti) con chiamate a un generico "constraintchecker" basato su dictionary nel quale vengono "iniettate" le logiche di validazione (con la tecnica dei delegates).

Quindi ora gli if sono sostituititi con la chiamata:
CheckConstraintForObject(this);

che a sua volta scandisce ed invoca i delegates, verificando prima se, da file di configurazione, e' stato definito che la regola deve essere attiva o meno.

Mi piaca abbastanza, anche nel senso del single responsability principle (la validazione, ed essa sola, e' affidata a...)

Non e' che ho ridotto di molto la complessita', pero' almeno e' stata separata e centralizzata una certa logica, ed e' stata consentita la possibilita' di decidere per diverse regole intervenendo in configurazione.

my 2 cents.

(p.s. sono stati comunque introdotti due if, che sono tra quelli che secondo me dovrebbero restare, un po' come nell'esempio fatto da Antonio. Se ne puo' parlare)

Ciao.
Comments have been closed on this topic.