Predicati con stile

Summary: with careful refactoring you get concision and clarity.

Questo è un frammento di codice di una famosa applicazione open source:

  public boolean isTitleValid() {
    if((title==null) || "".equals(title)) {
    return false;
    }
    return true;
  }

Brutto vero? Perché scomodare un if-then-else? Un valore booleano può essere restituito direttamente. Prima facciamo un passo di refactoring:

  public boolean isTitleValid() {
    if (! ((title==null) || "".equals(title))) {
      return true;
    }
    return false;
  }

Ora possiamo eliminare l’if-then-else.

  public boolean isTitleValid() {
    return (! ((title==null) || "".equals(title)));
  }

E così risparmiamo tre righe su sei: 50%. Eliminiamo tutte le parentesi inutili, per capirci meglio:

  public boolean isTitleValid() {
    return ! (title==null || "".equals(title));
  }

Applichiamo De Morgan per portare la negazione all’interno:

  public boolean isTitleValid() {
    return title != null && !"".equals(title);
  }

E non è finita; eliminiamo una delle negazioni:

  public boolean isTitleValid() {
    return title != null && title.length() > 0;
  }

Ora questo codice è 50% più corto, e molto più “parlante”: l’intento è evidente, tanto che si può leggere “il titolo è valido se non è null e la sua lunghezza è maggiore di zero.”

Visto quanta cura si può impiegare utilmente per poche righe di codice? Il bravo Steve McConnell ha impiegato 900 pagine di dettagli sull’arte della codifica, nel suo Code Complete, seconda edizione.

7 Responses to “Predicati con stile”

  1. Renzo Says:

    Mmmh, personalmente obbietto. La riduzione delle righe di codice non rende, mediamente, piu’ parlante il codice. E questo qui sopra ne e’ un esempio: prova a postare semplicmente il primo step e l’ultimo in qualche ML e chiedi se secondo loro la chiarezza e’ migliorata. Per me l’ultimo step e’ semplicemente illeggibile: mi richiede un paio di minuti di concentrazione. Il primo potrebbe non essere un capolavoro (io preferisco quello qui sotto) ma e’ immediato. Quindi dal mio punto di vista il refactoring va semplicemente rovesciato :)

    public boolean isTitleValid() {
    boolean result = true;
    if((title==null) || “”.equals(title)) {
    result = false;
    }
    return result;
    }

  2. Fabio Says:

    Grazie Matteo,
    esempio tanto semplice quanto inconfutabile :)

  3. matteo Says:

    Renzo, siamo di fronte a una differenza fondamentale… per me usare if-then-else in questo caso è anatema. Vorresti dirmi che in generale, secondo te, è più chiaro

    if (A) {
    return true;
    } else {
    return false;
    }

    rispetto a

    return A;

    ???

    Sono esterrefatto. Ammetto che io ho passato molto tempo a ragionare su espressioni booleane. Ma non accetterei codice come quello. Mi dà semplicemente l’idea che l’autore non sa ragionare sulle espressioni booleane. Lo rifattorizzo senza neanche battere ciglio.

    In generale, bisogna cercare di togliere i cicli e le decisioni dal codice. L’ideale è codice privo di if e while, una semplice sequenza di operazioni (semplici). Usare un if quando è sufficiente una semplice espressione è per me impensabile.

  4. Enri Says:

    Non posso che essere d’accordo con Matteo.

    Il codice finale rispetto a quello iniziale è più comprensibile. Senza alcun rumore sintattico balza subito all’occhio qual è l’aspetto fondamentale dell’implementazione: “il titolo è valido se non è nullo e la sua lunghezza è maggiore di zero.”.

    L’intelligenza visiva è infatti la più istintiva (è la prima che si sviluppa nei bambini), al contrario dell’intelligenza logica, che è quella che si sviluppa più tardi di tutte e che richiede il maggiore esercizio ed allenamento.
    Avere un if-then-else crea (nell’esempio di sopra) un disturbo visivo da ciò che invece è fondamentale, annegando il cuore del concetto dentro dettagli ed orpelli sintattici che velano il reale significato dell’implementazione, anche solo visualmente. E’ un po’ quanto avviene con un solitario: per esaltare le caratteristiche del diamante, lo si fa svettare, da solo, su una striscia d’oro.

    Da qui si può prendere spunto per parlare, su altra scala, del paradigma ad oggetti, che ha tra i suoi punti di forza proprio lo spostare la complessità logico/procedurale verso una complessità strutturale che permette una rappresentazione per diagrammi più maneggevole e su cui si ragiona con molta più facilità.

  5. jussx Says:

    Non mi piace in tutte le sue forme… Preferisco i linguaggi di programmazione funzionale SML, OCAML. Anni luce avanti rispetto a sta merda

  6. matteo Says:

    Non è questo il punto. Il punto è prendere un programma e migliorarlo in maniera graduale e sicura. E’ senz’altro vero che Java è rimasto indietro rispetto a tante alternative, ma qualsiasi linguaggio tu usi ti ritroverai a guardare codice pasticciato, e avrai bisogno del refactoring.

  7. Matteo Vaccari » Blog Archive » Another look at the anti-IF campaign Says:

    […] first form, because they prefer operational reasoning over reasoning over boolean values (see the comments to a previous post on this subject). I much prefer the first, for one thing because it’s shorter. Concision is power. And I try […]

Leave a Reply