Sei sulla pagina 1di 27

Migliorare il design di codice già scritto

Refactoring
Cosa è il refactoring?
 Una modifica alla struttura interna di un software al
fine di renderlo più facile da capire e meno costoso
da modificare, senza alterare il suo comportamento
osservabile.

 Il refactoring è la ristrutturazione del software


attraverso l’applicazione di una serie di semplici
metodologie, che vedremo nella presentazione (e
che, per inciso, sono chiamate anche esse
“refactoring”).

refactoring 2
Perché il refactoring?

 Perché dovrei fare  In che modo il refactoring mi


aiuta?
refactoring?
 Migliora il design del  Programmi difficili da
software capire sono anche
 Rende più difficili da modificare
comprensibile il  Programmi con logica
software duplicata sono difficili
 Aiuta a trovare i bachi da modificare

 Aiuta a programmare  Programmi con logica


più in fretta condizionale
refactoring 3
Quando fare refactoring?

quando si aggiunge una funzione

quando si deve risolvere un baco

quando si fa del code-review

Regole di massima

quando si incontra del codice duplicato

quando si trovano funzioni / procedure / metodi lunghi

quando una classe diventa troppo grande

quando si incontrano metodi con tanti parametri nella firma

quando ci si accorge che una classe dovrebbe subire evoluzioni divergenti

quando si incontrano problemi con i tipi primitivi (es. BAS di S.I.M.-G.)

quando ci sono istruzioni “switch”.

gerarchie di classi parallele (es. catasto urbano / catasto rurale)

gerarchie prolisse (troppe classi)

quando si trovano troppi commenti
refactoring 4
Categorie di interventi


Refactoring a livello di metodo

Spostamento di funzionalità tra oggetti

Organizzazione dei dati

Semplificazione delle espressioni condizionali

Semplificazione delle chiamate ai metodi

Generalizzazione

Grossi interventi (BIG REFACTORING)

refactoring 5
Refactoring a livello di
metodo
 Extract method
 Metodi troppo lunghi, codice duplicato: occorre
raccogliere una parte di codice in un metodo proprio.

void printOwing() {

printBanner();

//print details

System.out.println ("name: " + _name);

System.out.println ("amount " + getOutstanding());

refactoring
void printOwing() { 6
Refactoring a livello di
metodo
 Introduce explaining variable
 Se si ha un’espressione complessa e ricorrente, inserire il
risultato dell’espressione (o di parti di essa) in una
variabile temporanea che ne spieghi il significato.
if ((platform.toUpperCase().indexOf("MAC") > -1) &&
(browser.toUpperCase().indexOf("IE") > -1) &&

wasInitialized() && resize > 0 ) {

// do something

final boolean isMacOs = platform.toUpperCase().indexOf("MAC") > -1;

final boolean isIEBrowser = browser.toUpperCase().indexOf("IE") > -1;

final boolean wasResized = resize > 0;


refactoring 7
Refactoring a livello di
metodo
 Replace method with Method object
 Si ha un metodo lungo su cui non si può operare con extract
method perché fa uso di tante variabili locali: si trasforma il
metodo in un oggetto, le variabili locali diventano attributi
dell’oggetto. A questo punto si può operare una
decomposizione internamente all’oggetto.

class Order...

double price() {

double primaryBasePrice;

double secondaryBasePrice;

double tertiaryBasePrice;

refactoring
// long computation; ... 8
Spostamento di funzionalità tra
oggetti
 Move method
 Un metodo usa (o userebbe volentieri) funzioni o attributi
di una classe che non è la sua: si crei un metodo nella
seconda classe, si renda il metodo di partenza una
chiamata al nuovo metodo o lo si elimini.

refactoring 9
Spostamento di funzionalità tra
oggetti
 Extract Class
 Si ha una classe che fa il lavoro che dovrebbero fare due
classi diverse: si crei una nuova classe e si spostino gli
attributi e i metodi rilevanti.

refactoring 10
Spostamento di funzionalità tra
oggetti
 Hide delegate
 Un utilizzatore chiama una classe delegata di un oggetto: si
crei un metodo nell’oggetto in modo da nascondere la
classe delegata.

refactoring 11
Organizzazione dei dati
 Replace data value with Object
 Si ha un dato che ha (o potrebbe avere) dati o
comportamenti addizionali: si trasformi il dato in un
oggetto proprio.

refactoring 12
Organizzazione dei dati
 Replace array with Object
 Si ha un array in cui elementi diversi possono avere
significati diversi: sostituite l’array con un oggetto che
abbia un attributo per ogni elemento dell’array.

String[] row = new String[3];

row [0] = "Liverpool";

row [1] = "15";

Performance row = new Performance();

row.setName("Liverpool");
refactoring 13
Organizzazione dei dati
 Replace type code with Subclasses
 Si ha un “type code” immutabile che influenza che
influenza il comportamento di una classe: si sostituisca il
“type code” con delle sottoclassi.

refactoring 14
Semplificazione delle espressioni
condizionali
 Decompose conditional
 Si hanno delle espressioni condizionali complicate: si
estraggano metodi dalla condizione e dalle parti “then” ed
“else”.

if (date.before (SUMMER_START) || date.after(SUMMER_END))

charge = quantity * _winterRate + _winterServiceCharge;

else

charge = quantity * _summerRate;

if (notSummer(date))

charge = winterCharge(quantity);
refactoring 15
Semplificazione delle espressioni
condizionali
 Replace nested conditional with guard clauses
 Un metodo presenta un comportamento condizionale che non rende
chiaro la sequenza di esecuzione: si usino guard clauses.
double getPayAmount() {

double result;

if (_isDead)

result = deadAmount();

else {

if (_isSeparated)

result = separatedAmount();

else {

if (_isRetired)

result = retiredAmount();

else

refactoring result = normalPayAmount(); 16


Semplificazione delle espressioni
condizionali
 Replace conditional with polymorphism
 Si ha un’espressione condizionale che discrimina diversi comportamenti
sul tipo di un oggetto: si creino sottoclassi e si sposti il comportamento
condizionale in ognuna delle classi derivate.
double getSpeed() {

switch (_type) {

case EUROPEAN: return getBaseSpeed();

case AFRICAN: return getBaseSpeed() - getLoadFactor() * _numberOfCoconuts;

case NORWEGIAN_BLUE: return (_isNailed) ? 0 : getBaseSpeed(_voltage);

throw new RuntimeException ("Should be unreachable");

refactoring 17
Semplificazione delle chiamate ai
metodi

 Rename method
 Cambiare il nome dei metodi in modo che il nome
sia esplicativo della funzione del metodo.

refactoring 18
Semplificazione delle chiamate ai
metodi
 Add parameter / Remove parameter
 Un metodo ha bisogno di più informazioni dal chiamante: si
aggiunga un parametro alla firma.
 Un parametro non è più usato all’interno di un metodo: lo si
rimuova dalla firma.

refactoring 19
Semplificazione delle chiamate ai
metodi

 Preserve whole object


 Si recuperano vari attributi da un oggetto e li si usa
come parametri per un metodo: si passi
direttamente l’oggetto come unico parametro.

refactoring 20
Generalizzazione
 Pull up field / Pull up method
 Due sottoclassi hanno lo stesso attributo: lo si sposti
nella classe padre
 Due sottoclassi hanno un metodo con lo stesso
comportamento: si sposti il metodo nella classe padre.

refactoring 21
Generalizzazione
 Push down field / Push down method
 Un attributo è usato solo da una delle sottoclassi: si
sposti l’attributo nella sottoclasse
 Un metodo è significativo solo per una delle sottoclassi:
si sposti il metodo nella sottoclasse.

refactoring 22
Generalizzazione
 Extract subclass
 Una classe ha delle funzionalità che sono usato solo
per alcune istanze della classe: si crei una sottoclasse
che incorpori queste funzionalità e le si rimuova dalla
classe iniziale.

refactoring 23
Grossi interventi
 Rimozione ereditarietà
 Si ha una gerarchia che esegue due compiti alla volta: si creino
due gerarchie e si usi la delega per i comportamenti voluti

 Conversione da procedurale a oggetti


 Si ha del codice scritto con un approccio procedurale: si
trasformino i dati in oggetti, si scompongano le procedure e si
spostino le parti nei metodi degli oggetti creati.

refactoring 24
Grossi interventi
 Separazione del modello dalla presentazione
 Si hanno delle classi GUI che contengono logica / algoritmi che
apparterrebbero al modello: si estragga la logica dall’interfaccia
in classi di dominio separate.

 Estrazione di una gerarchia


 Si ha una classe che sta eseguendo troppi compiti, almeno in
parte attraverso diverse istruzioni condizionali: si crei una
gerarchia di classi in cui ogni sottoclasse rappresenta un caso
specifico.

refactoring 25
Concetti chiave
 Piccoli passi (a meno dei “grossi interventi”)
 Uso estensivo dello unit-testing
 Separazione netta tra refactoring e sviluppo
di funzionalità
 Lavoro di gruppo (code review ufficioso e
frequente / Pair programming)
 Coraggio e fiducia + buone abitudini

refactoring 26
zio ne !
l ’atten
azie per
Gr

refactoring 27