Refactoring is making changes to a body of code in order to improve its internal structure, without changing its external behaviour
Così M. Fowler definisce l’operazione di refactoring nel suo libro e nei suoi interventi in quest’ambito.
“Refactoring è il processo per modificare un sistema software in modo tale da migliorare la struttura interna del codice senza alterarne il comportamento esterno” .
Ma la domanda che ci si pone spesso è: “ma vale davvero la pena di perder tempo a fare refactoring, dal momento che non si modificano le performance dell’applicazione?”.
Domanda forse legittima…per chi scrive codice col solo intento di vederlo “girare” una o due volte e basta più. Diversamente la risposta non può che essere ASSOLUTAMENTE SI!
E molto spesso non è neppure vero che il comportamento resta totalmente invariato; spesso, infatti, una buona operazione di refactoring comporta un miglioramento del programma dovuto ad una revisione di codice scritto (e capita spesso) in maniera poco ottimizzata o con sporcizie varie rimaste nello specifico metodo inutilmente.
Fare refactoring quindi è utile ed è buona norma nello sviluppo di una qualsiasi tipologia di applicativo software (ancor più se si lavora in team): rende più comprensibile e manutenibile il software migliorandone, e allungandone, in tal maniera, il proprio ciclo di vita.
Altro elemento, inoltre, che gioca ancora a favore del refactoring è il supporto che oramai un po’ tutti gli IDE danno a questo processo.
Vediamone un esempio in Visual Studio prendendo, come esempio, la classe Program.cs della solution HelloNHibernate discussa nell’articolo precedente Il primo progetto con Hibernate.
Ricordo che la classe contiene un metodo statico Main() che si occupa di leggere da un database l’elenco dei fornitori e dei prodotti archiviati; successivamente inserisce un nuovo fornitore ed un nuovo prodotto, quindi effettua nuovamente la lettura dei dati dal db per verificare il corretto inserimento degli stessi.
Il codice della classe è:
class Program
{
static void Main(string[] args)
{
//Istanzio due variabili locali per l’accesso al DAO
SupplierDAO suppDao = new SupplierDAO();
ProductDAO prodDao = new ProductDAO();
//Leggo i Suppliers memorizzati nel database
IList suppliers = suppDao.GetSupplier();
//Li stampo in console
Console.WriteLine(“***** Elenco Fornitori : ***** “);
foreach (Supplier supplier in suppliers)
{
Console.WriteLine(“LastName= “ + supplier.LastName + ” |
FirstName= “ + supplier.FirstName + ” | BusinessName= “
+ supplier.BusinessName);
Console.WriteLine(“Address= “ + supplier.Address +
” | Phone= ” + supplier.Phone + ” | E-mail= “
+ supplier.Mail);
Console.WriteLine(“”);
}
//Leggo i Product memorizzati nel database
IList products = prodDao.GetProducts();
//Li stampo in console
Console.WriteLine***** Elenco Prodotti : *****
foreach (Product product in products)
{
Console.WriteLine(“Name= “+product.Name+” | Category= “
+ product.Category + ” | Pieces= “ + product.PiecesInStock
+ ” | Price= “ + product.Price);
Console.WriteLine(“Produttore= “+product.Supplier.BusinessName);
Console.WriteLine();
}
Console.ReadKey();
//Creo un nuovo Supplier
Supplier newsupplier = new Supplier();
newsupplier.FirstName = “Giovanni”;
newsupplier.LastName = “Girino”;
newsupplier.BusinessName = “Il miglior pollo”;
newsupplier.CreatedOn = DateTime.Now;
newsupplier.Address = “Via dell’Aia, 23″;
//E lo salvo nel database
suppDao.SaveSupplier(newsupplier);
//Creo un nuovo prodotto
Product newproduct = new Product();
newproduct.Category = “Food”;
newproduct.Name = “Pollo”;
newproduct.PiecesInStock = 8;
newproduct.Price = new decimal(2.35);
newproduct.Supplier = newsupplier;
//E lo salvo nel database
prodDao.SaveProduct(newproduct);
//Adesso rileggo i Suppliers memorizzati nel database
suppliers = suppDao.GetSupplier();
//Li stampo in console
Console.WriteLine***** Elenco Fornitori Aggiornato: *****
foreach (Supplier supplier in suppliers)
{
Console.WriteLine(“LastName= “ + supplier.LastName + ” |
FirstName= “+supplier.FirstName+” | BusinessName= “ +
supplier.BusinessName );
Console.WriteLine(“Address= “ + supplier.Address+ ” | Phone= “
+ supplier.Phone + ” | E-mail= “ + supplier.Mail);
Console.WriteLine(“”);
}
//Leggo i Product memorizzati nel database
products = prodDao.GetProducts();
//Li stampo in console
Console.WriteLine***** Elenco Prodotti Aggiornato: *****
foreach (Product product in products)
{
Console.WriteLine(“Name= “+product.Name+” | Category= “
+ product.Category + ” | Pieces= “ +product.PiecesInStock
+ ” | Price= “ + product.Price + ” | Supplier = “ +
product.Supplier.BusinessName);
Console.WriteLine(“”);
}
Console.ReadKey();
}
Come si vede il metodo è molto lungo, il che lo rende molto poco leggibile, e vi è pure codice ripetuto.
Proviamo quindi a migliorare le cose: per prima cosa selezioniamo la parte relativa alla lettura dei forniti dal database ed alla stampa della lista in Console; ciccando col tasto destro del mouse scegliendo: “Extract Method” si aprirà una finestra nella quale si deve inserire solamente il nome del metodo (i parametri vengono generati implicitamente), scegliendo, quindi, di chiamare il nuovo metodo readAndViewSupplier il risultato sarà:
private static readAndViewSuppliers(SupplierDAO suppDao)
{
//Leggo i Suppliers memorizzati nel database
IList suppliers = suppDao.GetSupplier();
//Li stampo in console
Console.WriteLine(“***** Elenco Fornitori : *****”);
foreach (Supplier supplier in suppliers)
{
Console.WriteLine(“LastName= “ + supplier.LastName +
” | FirstName= “+supplier.FirstName+” | BusinessName= “
+ supplier.BusinessName);
Console.WriteLine(“Address= “+supplier.Address+” | Phone= “
+ supplier.Phone + ” | E-mail= “ + supplier.Mail);
Console.WriteLine(“”);
}
}
OSS: Per convenzione i nomi dei metodi privati, si scrivono in minuscolo, mentre quelli pubblici in maiuscolo.
Stesso procedimento operiamo per la lettura dei prodotti:
private static readAndViewProduct(ProductDAO prodDao)
{
//Leggo i Product memorizzati nel database
IList products = prodDao.GetProducts();
//Li stampo in console
Console.WriteLine(“***** Elenco Prodotti : *****”);
foreach (Product product in products)
{
Console.WriteLine(“Name= “+product.Name+” | Category= “ +
product.Category + ” | Pieces= “ + product.PiecesInStock +
” | Price= ” + product.Price);
Console.WriteLine(“Produttore = “ + product.Supplier.BusinessName);
Console.WriteLine();
}
}
Quindi estraiamo un metodo per l’inserimento del nuovo fornitore al quale, per comodità, passiamo i valori dei campi come parametri:
private static Supplier createNewSupplier(string name, string lastname, string businessname, string address)
{
//Creo un nuovo Supplier
Supplier newsupplier = new Supplier();
newsupplier.FirstName = name;
newsupplier.LastName = lastname;
newsupplier.BusinessName = businessname;
newsupplier.CreatedOn = DateTime.Now;
newsupplier.Address = address;
return newsupplier;
}
ed analogamente operiamo l’inserimento del nuovo prodotto:
private static Product createNewProduct(string category,
string name,int pieces,decimal price,Supplier newsupplier)
{
Product newproduct = new Product();
newproduct.Category = category;
newproduct.Name = name;
newproduct.PiecesInStock = pieces;
newproduct.Price = price;
newproduct.Supplier = newsupplier;
return newproduct;
}
Con queste semplici e brevi operazioni effettuate sul metodo abbiamo ridotto il codice della classe a:
class Program
{
static void Main(string[] args)
{
//Istanzio due variabili locali per l’accesso al DAO
SupplierDAO suppDao = new SupplierDAO();
ProductDAO prodDao = new ProductDAO();
readAndViewSuppliers(suppDao);
readAndViewProduct(prodDao);
//Creo un nuovo Supplier
Supplier newsupplier = createNewSupplier(“Giovanni”,
“Girino”, “Il miglior pollo”, “Via dell’Aia, 23″);
//E lo salvo nel database
suppDao.SaveSupplier(newsupplier);
//Creo un nuovo prodotto
Product newproduct = createNewProduct(“Food”,“Pollo”,8,2.35,newsupplier);
//E lo salvo nel database
prodDao.SaveProduct(newproduct);
//Adesso rileggo i Suppliers memorizzati nel database
readAndViewSuppliers(suppDao);
//Leggo i Product memorizzati nel database
readAndViewProduct(prodDao);
Console.ReadKey();
}
che indubbiamente risulta più semplice da leggere e da manutenere in una revisione futura.
Refactoring it was easy doing …
Postato in: Codice C#, Informatica | Messo il tag: code, Refactoring; c#
Complimenti, ottimo articolo chiaro e ben scritto; ottima l’idea di evidenziare il passaggio dalla teoria alla pratica