XPUG Marche – 2° Meeting




                           Workshop sul
                            Refactoring



          ...
“Refactoring is the process of changing a
software system in such a way that it does not
  alter the external behavior of ...
Principi del Refactoring

• Migliorare il design del codice

• Eliminare le duplicazioni

• Rendere il codice più leggibil...
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;
    ...
Classe CaloriesCalculator
                    Responsabilità                            Collaborazioni

       Validazione...
Magic Number
public string Result() {
  string str = "Diet Report for " + person.Name +":n";
  double cal = 0.0;
  for (in...
Uso parziale di costanti
public class Person
 {
     public const int MEDIUM_SIZE = 2;
     public const int FAT = 3;
    ...
Cicli
public string Result() {
  string str = "Diet Report for " + person.Name +":n";
  double cal = 0.0;
  for (int i = 0...
Nomi di variabili metodi e classi
public string Result() {
  string str = "Diet Report for " + person.Name +":n";
  double...
Information Hiding


 public class Food
 {
    public string Name;
    public double Kg;
    public Food(string name, doub...
Responsabilità:
                      Validazione
public string Result() {
  string str = "Diet Report for " + person.Name...
Responsabilità:
     Calcolo delle calorie e dei Km
public string Result() {
  string str = "Diet Report for " + person.Na...
Responsabilità:
              Costruzione del report
public string Result() {
  string str = "Diet Report for " + person.N...
Passi di Refactoring
Visione di alto livello
Primi Passi

• Effettuate le operazioni individuate in precedenza
  (Naming, Information Hiding….)

• Creata la classe Mea...
Validazione

     Assegnata alla classe Person la responsabilità
        della propria validazione



     Adottato l'util...
Calcolo delle Calorie

          Utilizzo del pattern strategy per il calcolo delle
              calorie:


             ...
Costruzione dei Report

           Utilizzo del pattern template per modellare le
               logiche di reporting:


 ...
Riferimenti

Martin Fowler -
Refactoring: Improving the Design of Existing Code




Michael Feathers -
Working Effectively...
Domande?
Upcoming SlideShare
Loading in …5
×

Workshop Su Refactoring

582
-1

Published on

Published in: Technology
0 Comments
0 Likes
Statistics
Notes
  • Be the first to comment

  • Be the first to like this

No Downloads
Views
Total Views
582
On Slideshare
0
From Embeds
0
Number of Embeds
6
Actions
Shares
0
Downloads
2
Comments
0
Likes
0
Embeds 0
No embeds

No notes for slide

Workshop Su Refactoring

  1. 1. XPUG Marche – 2° Meeting Workshop sul Refactoring Stefano Leli
  2. 2. “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
  3. 3. 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
  4. 4. Regole • Tempo a disposizione 25 minuti • I test devono restare verdi • I test non possono essere modificati
  5. 5. Analisi del problema
  6. 6. 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; } } }
  7. 7. 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
  8. 8. 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; }
  9. 9. 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; } } }
  10. 10. 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; }
  11. 11. 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; }
  12. 12. Information Hiding public class Food { public string Name; public double Kg; public Food(string name, double kg) { this.Name = name; this.Kg = kg; } }
  13. 13. 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; }
  14. 14. 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; }
  15. 15. 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; }
  16. 16. Passi di Refactoring
  17. 17. Visione di alto livello
  18. 18. 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.)
  19. 19. 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
  20. 20. 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.
  21. 21. 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
  22. 22. Riferimenti Martin Fowler - Refactoring: Improving the Design of Existing Code Michael Feathers - Working Effectively with Legacy Code
  23. 23. Domande?

×