Code Smells

Far Refactoring, o migliorare il design del codice esistente, richiedere innanzitutto capire qual’è il codice da migliorare.

Quindi avere un elenco di ciò che è smell nel vostro codice è fondamentale:

  • Duplicato
  • Non chiaro
  • Complicato

Questi criteri possono certamente aiutarci a scoprire il codice da migliorare.

Questa lista, per alcuni, risulta troppo generica.
Per questo motivo, Martin Fowler e Kent Beck, hanno creato una libro per identificare i problemi di design (fate pure riferimento all’indirizzo:
http://foozle.berkeley.edu/projects/streek/agile/bad-smells-in-code.html#DuplicatedCode. L’autore ha fatto un riassunto del libro di MF e KB).

In questo post elencheremo solamente di 12 dei 22 smells possibili:

  1. Duplicated Code
    E’ lo smell più frequente nella realizzazione del software.
    Solitamente troviamo o il codice duplicato al 100%, dove migliaia di metodi fanno lo stesso lavoro ma vengono chiamati in casi differenti o abbiamo delle parti di codice duplicato in più punti dello stesso progetto.
    Quando si identificano queste porzioni di codice si può attuare un refactoring con vari patterns (dipende da cosa modificheremo).
    Così applicheremo il Form Template Method per rimuovere il codice totalmente o duplicato in parte, o Introduce Polymorphic Creation with Factory Method se il codice sarà lo stesso ma cambia solamente il codice di creazione dell’oggetto…
  2. Long Method
    Fowler
    e Beck nel loro libro danno svariate motivazioni sul perchè i metodi lunghi puzzano, una motivazioni su tutte è la possibilità di condivisione del codice. Tanti piccoli metodi possono essere usati in vari parti del codice per condividere delle logiche, aiutano alla spiegazione del codice, dividendo il codice in piccolo metodi, ben nominati, è pià facile individuare i smells, perchè è più facile leggerli e individuarne i duplicati.
    C’è chi dice che troppi piccoli metodi leniscono le performance del sistema a causa delle varie chiamate, ma le perdite di performance sono veramente esigue e, se mai dovessero essercene, si può sempre fare del refactoring e tornare indietro.
    Per effettuare refactoring su lunghi metodi i modi sono tanti, dipende sempre dal caso.
    Se, ad esempio, abbiamo un metodo con un enorme switch che si occupa di gestire eventi o dati, si potrà applicare Replace Conditional Dispatcher with Command, se invece si occupera di raccogliere i dati provenienti da varie classi con interfacce differenti potremmo applicare Move Accumulation to Visitor
  3. Conditional Complexity
    Finchè lo smell di questo tipo è piccolo è facile da sistemare. Se invece le condizioni iniziano a complicarsi ed a allungarsi, allora sarà sempre più complicato.
    Se le condizioni di controllo contengono molte varianti allora dovremo considerare l’applicazione Replace Conditional Logic with Strategy.
    Se invece ci sono varie condizioni con comportamenti speciali rispetto alla logica di base allora ci tornerà utile Move Embellishment to Decorator
  4. Primitive Obsession
    Per primitivi si intendono integer, string, double, arrays che tutti conoscono e possono usare, mentre le classi sono create per rispondere puntualmente a un nostro problema e raggruppano con una certa logica, il codice da noi creato.
    Spesso capita che, a causa di una mancata visione di alto livello di astrazione, si casca in questo smell. Fowler identifica svariate maniere per risolvere questo problema.
    Se un tipo primitivo controlla una logica in una classe e il valore assegnato non è typesafe dovremo applicare Replace Type Code with Class.
    Se lo stato dell’oggetto è controllato da una complessa logica che usa tipi primitivi, si potrà applicare Replace State-Altering Conditionals with State. Il risultato sarà numerose classi che rappresenteranno i stati dell’oggetto…
  5. Indecent Exposure
    Questo smell capita quando un metodo o una classe che dovrebbe non esser visibile ai clients, invece è visibile. Questo contribuisce alla complessità del design.
    Il refactoring Encapsulate Classes with Factory sistema il problema.
    Ricordiamoci che non tutte le classi e i metodi sono utili al client che istanzierà la classe o dovrà usare un metodo.
  6. Solution Sprawl
    Quando il codice e/o i dati usati sono divisi in numerose classi ecco che nasce lo smell.
    Solitamente questo avviene a causa della velocità con la quale si aggiungono competenze al sistema senza spendere abbastanza tempo per semplificare e consolidare il design per migliorare l’aggiunta della feature.
    Questo smell è già presente quando, all’aggiunta o all’aggiornamento di una feature, dovremo modificare varie classi e pezzi di codice.
    In questo caso Move Creation Knowledge to Factory è quello che farà per noi.
  7. Alternative Classes with Different Interfaces
    Questo smell capita quando le interfacce di, almeno, due classi sono differenti ma le classi sono simili.
    In questo caso Unify Interfaces with Adapter fa a caso nostro.
  8. Lazy Class
    Quando una classe non fa molto per tenerla nel progetto, conviene eliminarla. Non è difficile trovare delle classe con dei Singleton che non vengono usati o che non hanno senso. L’uso del Singleton crea un design troppo dipendente dall’ammontare dei dati creati dal Singleton.
    Inline Singleton spiega come eliminarlo.
  9. Large Class
    Di solito una classe che ha svariati compiti casca in questo smell.
    Extract Class e Extract Subclass sono alcuni dei tanti refactoring applicabili.
    Il refactoring to pattern che vedremo invece sarà Replace Conditional Dispatcher with Command per estrarre i comportamenti in una classe Command e ridurne così i controlli all’interno della classe stessa o Replace State-Altering Conditionals with State per ridurne la complessità data dalla gestione dello stato dell’oggetto o Replace Implicit Language with Interpreter per ridurre la complessità di una grande classe in una piccola traformando l’abbondante codice che emula un linguangio in un interprete.
  10. Switch Statements
    Uno switch o l’insieme di if…elseif…elseif…elseif diventa uno smell quando il design viene complicato o si irrigidisce.
    In questo caso sarebbe bene fare del refactoring togliendo questi switch statements e inserendo una solutione più orientata agli oggetti e polimorfica.
    Replace Conditional Dispatcher with Command tornerà di nuovo utile in questo caso.
    Move Accumulation to Visitor ci aiuta ad ottenere un oggetto da una classe con molte interfacce, senza inserire svariate logiche necessarie all’ottenimento dell’oggetto e rendendo il design del nostro applicativo più flessibile.
  11. Combinatorial Explosion
    Questo smell è un sottoinsieme della duplicazione di codice. Esiste quando abbiamo numerosi pezzi di codice che fanno la stessa cosa usando differenti oggetti o quantità di dati.
    Esempio, quando abbiamo molti metodi nella stessa classe che usiamo per fare delle query.
    Più query specializzate ci serviranno, più metodi dovremo creare. Presto avremo un elenco infinito di metodi.
    Si potranno eliminare tutti questi metodi e creare una classe per generare le query in maniera dinamica tramite Replace Implicit Language with Interpreter.
  12. Oddball Solution
    Quando un problema è risolto in una maniera e un’altro problema simile è risolto in un’altra maniera nello stesso sistema, una delle due soluzioni è inconsistente e si genera uno smell.
    Per eliminarlo, prima bisognerà identificare la soluzione che preferiamo e poi potremmo applicare un Substitute Algorithm per creare una buona soluzione per l’intero sistema.
    Fatto questo se avremo un modo per comunicare la soluzione alle classi in una maniera e in un’altra maniera per comunicare con le interfacce,  allora potremo applicare Unify Interfaces with Adapter.
    Fatto questo dovremmo ripassare il codice per trovare se ci sono altri pezzi di codice duplicato.

Le soluzioni elencate come Refactoring To Patterns non sono tutte quelle applicabili.

Nel corso dei post esploderemo i punti di cui sopra e verranno descritte le varie solutioni.

Per questi post sto prendendo, molto, spunto da libro Refactoring To Patterns di Joshua Kerievsky.