Workshop Su Refactoring
Upcoming SlideShare
Loading in...5
×
 

Workshop Su Refactoring

on

  • 457 views

 

Statistics

Views

Total Views
457
Views on SlideShare
364
Embed Views
93

Actions

Likes
0
Downloads
1
Comments
0

3 Embeds 93

http://xpugmarche.blogspot.it 91
http://www.linkedin.com 1
http://xpugmarche.blogspot.ie 1

Accessibility

Categories

Upload Details

Uploaded via as Adobe PDF

Usage Rights

© All Rights Reserved

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Processing…
Post Comment
Edit your comment

Workshop Su Refactoring Workshop Su Refactoring Presentation Transcript

  • XPUG Marche – 2° Meeting Workshop sul Refactoring Stefano Leli
  • “Refactoring is the process of changing a software system in such a way that it does not alter the external behavior of the code yet improves its internal structure.” Martin Fowler
  • Principi del Refactoring • Migliorare il design del codice • Eliminare le duplicazioni • Rendere il codice più leggibile e facile da modificare Single Responsibility Principle (SRP) Una classe dovrebbe avere una sola ragione per cambiare
  • Regole • Tempo a disposizione 25 minuti • I test devono restare verdi • I test non possono essere modificati
  • Analisi del problema
  • Classe CaloriesCalculator namespace Kata { public class CaloriesCalculator { private readonly List<Food> foods; private readonly Person person; public CaloriesCalculator(Person person, List<Food> foods) { this.person = person; this.foods = foods; } public string Result() { string str = "Diet Report for " + person.Name +":n"; double cal = 0.0; for (int i = 0; i < foods.Count; i++) { Food food = foods[i]; str += food.Name + " - " + food.Kg + "n"; if ("".Equals(food.Name)) throw new FirstException(); if ("apple".Equals(food.Name)) cal += food.Kg * 15 * 10; if ("magicPill".Equals(food.Name)) cal -= 10; if ("candy".Equals(food.Name)) cal += food.Kg; } str += "Total: " + (double)cal + " kcaln"; str += "kilometers to be run: " + 90 /* calories in one kilometer */ * person.Size / cal; foreach (Food type in foods) { if ("".Equals(type.Name)) throw new FirstException(); if (person.Kg > 1000) throw new SecondException(); } return str; } } }
  • Classe CaloriesCalculator Responsabilità Collaborazioni Validazione delle componenti Classe Food Costruzione del report di stampa Classe Person Calcolo delle calorie di una lista di cibi Classe FirstException Calcolo dei Km da percorrere Classe SecondException CRC Card Classe CaloriesCalculator Il refactoring verterà sulla: suddivisione di responsabilità (aumentare la coesione) diminuzione delle collaborazioni con le classi applicative (diminuire l'accoppiamento) Favorendo in questo modo un: maggiore riuso del codice maggiore robustezza del programma
  • Magic Number public string Result() { string str = "Diet Report for " + person.Name +":n"; double cal = 0.0; for (int i = 0; i < foods.Count; i++) { Food food = foods[i]; str += food.Name + " - " + food.Kg + "n"; if ("".Equals(food.Name)) throw new FirstException(); if ("apple".Equals(food.Name)) cal += food.Kg * 15 * 10; if ("magicPill".Equals(food.Name)) cal -= 10; if ("candy".Equals(food.Name)) cal += food.Kg; } str += "Total: " + (double)cal + " kcaln"; str += "kilometers to be run: " + 90 * person.Size / cal; foreach (Food type in foods) { if ("".Equals(type.Name)) throw new FirstException(); if (person.Kg > 1000) throw new SecondException(); } return str; }
  • Uso parziale di costanti public class Person { public const int MEDIUM_SIZE = 2; public const int FAT = 3; public const int SLIM = 1; public Person(string name, int kg) { this._name = name; this.kg = kg; } private string _name; public string Name { get { return _name; } set { _name = value; } } private int kg; public int Kg { get { return kg; } set { kg = value; } } public int Size { get { if (kg > 130) return 3; if (kg < 50) return 1; return MEDIUM_SIZE; } } }
  • Cicli public string Result() { string str = "Diet Report for " + person.Name +":n"; double cal = 0.0; for (int i = 0; i < foods.Count; i++) { Food food = foods[i]; str += food.Name + " - " + food.Kg + "n"; if ("".Equals(food.Name)) throw new FirstException(); if ("apple".Equals(food.Name)) cal += food.Kg * 15 * 10; if ("magicPill".Equals(food.Name)) cal -= 10; if ("candy".Equals(food.Name)) cal += food.Kg; } str += "Total: " + (double)cal + " kcaln"; str += "kilometers to be run: " + 90 * person.Size / cal; foreach (Food type in foods) { if ("".Equals(type.Name)) throw new FirstException(); if (person.Kg > 1000) throw new SecondException(); } return str; }
  • Nomi di variabili metodi e classi public string Result() { string str = "Diet Report for " + person.Name +":n"; double cal = 0.0; for (int i = 0; i < foods.Count; i++) { Food food = foods[i]; str += food.Name + " - " + food.Kg + "n"; if ("".Equals(food.Name)) throw new FirstException(); if ("apple".Equals(food.Name)) cal += food.Kg * 15 * 10; if ("magicPill".Equals(food.Name)) cal -= 10; if ("candy".Equals(food.Name)) cal += food.Kg; } str += "Total: " + (double)cal + " kcaln"; str += "kilometers to be run: " + 90 * person.Size / cal; foreach (Food type in foods) { if ("".Equals(type.Name)) throw new FirstException(); if (person.Kg > 1000) throw new SecondException(); } return str; }
  • Information Hiding public class Food { public string Name; public double Kg; public Food(string name, double kg) { this.Name = name; this.Kg = kg; } }
  • Responsabilità: Validazione public string Result() { string str = "Diet Report for " + person.Name +":n"; double cal = 0.0; for (int i = 0; i < foods.Count; i++) { Food food = foods[i]; str += food.Name + " - " + food.Kg + "n"; if ("".Equals(food.Name)) throw new FirstException(); if ("apple".Equals(food.Name)) cal += food.Kg * 15 * 10; if ("magicPill".Equals(food.Name)) cal -= 10; if ("candy".Equals(food.Name)) cal += food.Kg; } str += "Total: " + (double)cal + " kcaln"; str += "kilometers to be run: " + 90 * person.Size / cal; foreach (Food type in foods) { if ("".Equals(type.Name)) throw new FirstException(); if (person.Kg > 1000) throw new SecondException(); } return str; }
  • Responsabilità: Calcolo delle calorie e dei Km public string Result() { string str = "Diet Report for " + person.Name +":n"; double cal = 0.0; for (int i = 0; i < foods.Count; i++) { Food food = foods[i]; str += food.Name + " - " + food.Kg + "n"; if ("".Equals(food.Name)) throw new FirstException(); if ("apple".Equals(food.Name)) cal += food.Kg * 15 * 10; if ("magicPill".Equals(food.Name)) cal -= 10; if ("candy".Equals(food.Name)) cal += food.Kg; } str += "Total: " + (double)cal + " kcaln"; str += "kilometers to be run: " + 90 * person.Size / cal; foreach (Food type in foods) { if ("".Equals(type.Name)) throw new FirstException(); if (person.Kg > 1000) throw new SecondException(); } return str; }
  • Responsabilità: Costruzione del report public string Result() { string str = "Diet Report for " + person.Name +":n"; double cal = 0.0; for (int i = 0; i < foods.Count; i++) { Food food = foods[i]; str += food.Name + " - " + food.Kg + "n"; if ("".Equals(food.Name)) throw new FirstException(); if ("apple".Equals(food.Name)) cal += food.Kg * 15 * 10; if ("magicPill".Equals(food.Name)) cal -= 10; if ("candy".Equals(food.Name)) cal += food.Kg; } str += "Total: " + (double)cal + " kcaln"; str += "kilometers to be run: " + 90 * person.Size / cal; foreach (Food type in foods) { if ("".Equals(type.Name)) throw new FirstException(); if (person.Kg > 1000) throw new SecondException(); } return str; }
  • Passi di Refactoring
  • Visione di alto livello
  • Primi Passi • Effettuate le operazioni individuate in precedenza (Naming, Information Hiding….) • Creata la classe Meal • Responsabile della validazione di una lista di Food • Aumenta la coesione tra le classi • Creata la classe Dietist • Funge da “Mediator” • Lascia aperti scenari ad estensioni future (DI, etc.)
  • Validazione Assegnata alla classe Person la responsabilità della propria validazione Adottato l'utilizzo del pattern Visitor per la validazione dei Food: Permette di aggiungere nuovi comportamenti indipendenti dalla struttura dati Diminuisce la complessità della struttura dati
  • Calcolo delle Calorie Utilizzo del pattern strategy per il calcolo delle calorie: Maggior grado di disaccoppiamento tra l'implementazione dell'algoritmo e la sua esecuzione Possibilità di incapsulare più strategie o algoritmi in classi separate semplicemente implementando le apposite interfacce.
  • Costruzione dei Report Utilizzo del pattern template per modellare le logiche di reporting: Permette di separe le parti invarianti da quelle varianti di un algoritmo. Rende facile l'aggiunta di un nuovo report. Basta implementare il template di base e definire le parti varianti Per favorire l'information hiding è stata aggiunta l'interfaccia IDietReport
  • Riferimenti Martin Fowler - Refactoring: Improving the Design of Existing Code Michael Feathers - Working Effectively with Legacy Code
  • Domande?