Viste le richieste che mi sono state fatte nei commenti
al mio precedente post, ho deciso di dare qualche dettaglio in più sulle
tecniche di refactoring che ho utilizzato nella realizzazione di IMHO.
Occorre innanzitutto tenere presente che nelle fasi iniziali di sviluppo ho
installato il Resharper. Questo tool, prodotto dalla stessa azienda che ha
realizzato uno degli IDE più famosi per Java (IntelliJ IDEA), fornisce un bel
po' di strumenti utili per rendere più agevole la scrittura del codice in VS.NET
2003 e per fare del vero e proprio refactoring. Quella che preferisco in
assoluto è la possibilità di aggiungere gli using automaticamente quando si
inseriscono delle classi che non sono mai state utilizzate. Tuttavia dopo pochi
giorni di lavoro mi sono visto costretto a disinstallare il tutto. A quanto pare
Resharper ha la brutta abitudine di fagocitare quanto più RAM
possibile e rende instabile e inutilizzabile Visual Studio. Questo probabilmente
perchè ha la pretesa di sostituire totalmente l'intellisense di VS, invece che
semplicemente aggiungere le funzionalità mancanti.
Quindi in breve mi sono trovato nudo. Nessuno strumento per poter fare del
refactoring assistito, e la necessità come si suol dire ha aguzzato l'ingegno.
La chiave di tutto si chiama CTRL+SHIFT+B. Per i due che non sanno di
cosa parlo, questa è la combinazione di tasti che compila la solution. Tutta la
tecnica, che nel titolo ho sintetizzato con un pomposo Error Driven
Refactoring, si basa sul provocare errori di compilazione. Facciamo qualche
esempio:
Cambiare il nome ad una variabile, ad un tipo, oppure a un
metodo, è il caso più banale. Si va sul membro che si desidera cambiare, lo si
cambia e si compila. A questo punto, nel Task Panel si presenteranno un certo
numero di errori, talvolta qualche centinaio. Non sempre serve risolverli tutti,
perchè se avete mai fatto caso il compilatore più di qualche volta genera due o
tre avvisi per lo stesso errore. La mia tecnica prevede di risolvere al
massimo la prima decina e poi ricompilare. E avanti così finche il codice non da
più errori. Sembra una attività ingrata, ma una volta che si è presa confidenza
è più veloce di quello che si possa immaginare. Non è detto che a questo punto
il codice compilato funzioni. Ad esempio se usate la reflection per istanziare
un tipo è probabile che in fase di compilazione non ci sia alcun errore, mentre
quando lo eseguite ovviamente solleva una eccezione. Una bella ricerca testuale
non guasta.
Cambiare la firma di un metodo è un'altra cosa abbastanza
facile. Analogamente al caso precedente si provoca l'errore cambiando la firma.
Talvolta conviene dapprima cambiare il nome del metodo e completare il primo
passaggio. Poi si cambierà il tipo di ritorno oppure i parametri e si procede
nuovamente alla compilazione. In questi casi occorre avere la cautela di
accorgersi quando si cambia il tipo di un parametro con uno che sia compatibile,
ad esempio con una classe padre. Il compilatore in questi casi non ci viene in
aiuto, ma se contestualmente create una errore fittizio inserendo un carattere
estraneo nel nome del metodo è più facile che si ritrovino tutte le chiamate.
Inoltre bisognerà avere la cautela di capire che cosa succede nel corpo del
metodo. Anche qui un carattere estraneo nel nome del parametro che occorre
modificare aiuterà a trovare tutti gli usi che sono stati fatti e a verificare
che non vi siano anche errori logici oltre che sintattici. In questo caso non
occorre nemmeno ricompilare perchè sarà l'intellisense a indicarci l'errore con
una simpatica sottolineatura.
Accomunare alcune classi con un'unica classe padre.
Tipicamente in questi casi, si parte dapprima con la realizzazione della classe
base vuota e immediatamente la si sostituisce a object nelle classi che dovranno
estenderla. Nessun errore dovrebbe presentarsi. Però se si accomunano pià classi
significa che si intende spostare uno o più metodi e proprietà ad un livello più
basso. Perciò mano amano si fà cut & paste e si trasportano tali metodi
nella nuova classe. Ad ogni spostamento si compila e così si individuano ad
esempio i membri privati che sono referenziati da tali metodi e si trasportano
anch'essi. In breve la classe dovrebbe cominciare ad indicare che alcuni metodi
sono sovrascritti e che occorre l'uso dell'operatore new. Questi sono i metodi
che sono rimasti nelle altre classi e vanno del tutto cancellati assieme ai
membri privati che sono i più difficili da scovare, perchè non danno errore. Ad
accomunare spesso è un'interfaccia o una classe astratta. Ne pimo case non c'è
alcun problema perchè quando l'interfaccia è finita la si fa implementare alle
classi e nel digitare Visual Studio autonomamente creerà i metodi e ad
accorgersi se esistono già. Con le classi astratte è un po' più complesso. Si
aggiungono i metodi astrtti e quindi si dovranno aggiungere gli override dove
mancano oppure creare i metodi vuoi facendosi aiutare dagli errori e
dall'intellisense.
Estrapolare delle classi da un progetto per crearne uno
nuovo. Questa è la forma di refactoring che mi piace di più. Occorre tenere
presente sempre che alcune classi possono essere usate da altri assembly, e che
talvolta il codice che si scrive diventa un buon candidato al riutilizzo. Perciò
trasportarlo in un altro assembly è vitale. Quindi si crea il nuovo progetto. Io
ho l'abitudine di dare al progetto il medesimo nome del namespace che contiene.
Questo è di enorme aiuto ad orientarsi nel trovare quello che si cerca. Tornando
al problema a questo punto usando il Drag & Drop si trascinano le classi da
un progetto all'altro e contestualmente si aggiunge la nuova reference. I
progetto dovrebbe compilare immediatamente perchè nelle classi spostate è
rimasto il namespace originale. Quindi occorre un bel replace. Si evidenzia il
namespace da cambiare e si premo CTRL+H. Quindi ci si assicura di avere lo scope
di progetto e si sostituisce con il namespace nuovo. Finalmente il compilatore
comincia a dare errori. Questi potranno essere causati dalla mancanza di una
reference oppure da uno using sbagliato. Non resta che aggiungere quello che
serve e la solution tornerà a ricompilare.
Quelli che ho indicato sono solo alcuni dei casi da gestire. Indicarli tutti
mi sembrava improponibile. Quello che mi interessa far capire è che non serve
avere dei tool molto evoluti per potersi dedicare alla tecnica del refactoring.
A mio parere nessun tool potrà mai arrivare a fare tutto ciò che ci serve, ma
con un po' di fantasia si arriva a trovare una soluzione efficace.
Ora non avete più scuse. Refactor your life.
powered by IMHO