SlideShare a Scribd company logo
1 of 63
Download to read offline
Codice Legacy,
                         usciamo dal pantano!
                           Antonio Carpentieri (@acarpe)
                                Stefano Leli (@sleli)



giovedì 30 giugno 2011
Regole
                    • Tempo a disposizione: 50 minuti
                    • Il codice va rifattorizzato per
                         essere conforme ai principi
                         S.O.L.I.D.

                    • I test possono essere modificati
giovedì 30 giugno 2011
S.O.L.I.D. Principles



giovedì 30 giugno 2011
giovedì 30 giugno 2011
Single Responsibility
                               Principle
             “There should never be more than one reason
                        for a class to change”




giovedì 30 giugno 2011
giovedì 30 giugno 2011
Interface Segregation
                                Principle
   “Clients should not be forced to depend upon interfaces
                    that they do not use”
                public    interface MobileDevice
                {
                  void    Call(string phoneNumber);
                  void    PlayAudio(Uri uri); void PlayVideo(Uri uri);
                  void    TakePicture();
                  void    StartRecordingAudio();
                  void    StopRecordingAudio();
                  void    StartRecordingVideo();
                  void    StopRecordingVideo();
                }


giovedì 30 giugno 2011
giovedì 30 giugno 2011
giovedì 30 giugno 2011
giovedì 30 giugno 2011
Liskov Substitution
                              Principle

       “Functions that use pointers or references to base
         classes must be able to use objects of derived
                  classes without knowing it.”




giovedì 30 giugno 2011
Bird Watching Game
                           http://github.com/sleli/BirdWatching




giovedì 30 giugno 2011
Il Gioco
                    • Simulatore di Bird Watching
                    • Una sorta di “battaglia navale”...
                         ma qui gli assi sono 3 (gli uccelli
                         volano)




giovedì 30 giugno 2011
Le Classi




giovedì 30 giugno 2011
Analisi del problema



giovedì 30 giugno 2011
Classe GameField
                         Responsabilità            Collaborazioni

         Gestisce la collezione di Birds
         Dispone il campo da gioco
         Valida il campo da gioco          Classe Bird
         Inizializza il campo (start)
         Gestisce le logiche degli shot

    Il refactoring verterà sulla suddivizione di responsabilità (aumentare
    la coesione, diminuire l’accoppiamento)
        •Maggiore riuso del codice
        •Maggiore robusteza del programma
        •Minor costo del cambiamento
giovedì 30 giugno 2011
Passi di refactoring



giovedì 30 giugno 2011
Duplicazione



giovedì 30 giugno 2011
Duplicazione (semplice)

            @Before
            	 public void Setup() {
                    field = new GameField(10,5,3, new FieldSize(10,5,3));
            	 }




giovedì 30 giugno 2011
Duplicazione (semplice)
            public GameField(int width, int height, int depth,
            FieldSize fieldSize) {
            	 	 this.width = width;
            	 	 this.height = height;
            	 	 this.depth = depth;
            	 	 this.fieldSize = fieldSize;
            	 	 birds = new ArrayList<Bird>();
            	 }




giovedì 30 giugno 2011
Duplicazione (semplice)

   //Place the birds on the fields
   	 private void placeBirds(PlacingMode type) throws Exception {
         ...
   	      Location location = new Location(new Random().nextInt(this.width),
                                           new Random().nextInt(this.height));
   	 	    bird.setLocation(location);
   	 	    if (!(bird instanceof Chicken))
   	 	        bird.setHeight(new Random().nextInt(this.depth));
   	 	 ...
   	 }




giovedì 30 giugno 2011
Eliminiamola!




giovedì 30 giugno 2011
Eliminiamola!
                         @Before
                         	 public void Setup() {
                                 field = new GameField(new FieldSize(10,5,3));
                         	 }




giovedì 30 giugno 2011
Eliminiamola!
                         @Before
                         	 public void Setup() {
                                 field = new GameField(new FieldSize(10,5,3));
                         	 }


                         public GameField(FieldSize fieldSize) {
                         	 	 this.fieldSize = fieldSize;
                         	 	 birds = new ArrayList<Bird>();
                         	 }




giovedì 30 giugno 2011
Eliminiamola!
                         @Before
                         	 public void Setup() {
                                 field = new GameField(new FieldSize(10,5,3));
                         	 }


                         public GameField(FieldSize fieldSize) {
                         	 	 this.fieldSize = fieldSize;
                         	 	 birds = new ArrayList<Bird>();
                         	 }

          //Place the birds on the fields
          	   private void placeBirds(PlacingMode type) throws Exception {
          ...
          	   	   	   	  Location location = new Location(new Random().nextInt(fieldSize.width()),
                           new Random().nextInt(fieldSize.height()));
          	   	   	   	  bird.setLocation(location);
          	   	   	   	  if (!(bird instanceof Chicken))
          	   	   	   	  	   bird.setHeight(new Random().nextInt(fieldSize.depth()));
          	   	   ...
          	   }



giovedì 30 giugno 2011
Diamo a Cesare
                         ciò che è di Cesare


giovedì 30 giugno 2011
Diamo a Cesare ciò che è di Cesare
                         public class Location {
                         	 int x = 0;
                         	 int y = 0;
                         	
                         	 public Location (int x, int y) {
                         	 	 this.x = x;
                         	 	 this.y = y;
                         	 }

                         }




giovedì 30 giugno 2011
Diamo a Cesare ciò che è di Cesare




giovedì 30 giugno 2011
Diamo a Cesare ciò che è di Cesare
                         bird.setLocation(location);
                         if (!(bird instanceof Chicken))
                         	 bird.setHeight(new Random().nextInt(this.depth));




giovedì 30 giugno 2011
Diamo a Cesare ciò che è di Cesare
                         bird.setLocation(location);
                         if (!(bird instanceof Chicken))
                         	 bird.setHeight(new Random().nextInt(this.depth));

                              Bird duck = new Duck();
                              duck.setLocation(new Location(10,5));
                              duck.setHeight(3);




giovedì 30 giugno 2011
Diamo a Cesare ciò che è di Cesare
                         bird.setLocation(location);
                         if (!(bird instanceof Chicken))
                         	 bird.setHeight(new Random().nextInt(this.depth));

                              Bird duck = new Duck();
                              duck.setLocation(new Location(10,5));
                              duck.setHeight(3);

                            int h = bird.getHeight();
                            Location location = bird.getLocation();
                            int x = location.x;
                            int y = location.y;
                            isValid = fieldSize.isWithinField(h, x, y);




giovedì 30 giugno 2011
Diamo a Cesare ciò che è di Cesare
                         public class Location {
                         	 int x = 0;
                         	 int y = 0;
                           int h = 0;

                           public Location (int x, int y) {
                             this(x, y, 0);
                         	 }

                         	   public Location (int x, int y, int z) {
                         	   	 this.x = x;
                         	   	 this.y = y;
                         	   	 this.h = z;
                         	   }

                         }


giovedì 30 giugno 2011
Diamo a Cesare ciò che è di Cesare


  Location location = new Location(new Random().nextInt(fieldSize.width()),
                                   new Random().nextInt(fieldSize.height()),
                                   new Random().nextInt(fieldSize.depth()));




giovedì 30 giugno 2011
Diamo a Cesare ciò che è di Cesare
                         public abstract class Bird {
                         	 Location location;
                         	 int height;
                         	
                         	 public void setHeight(int height) throws Exception{
                         	 	 this.location.h = height;	
                         	 }
                         	
                         	 public int getHeight() {
                         	 	 return location.h;
                         	 }
                         	
                         	 public void setLocation(Location location) {
                         	 	 this.location = location;
                         	 	
                         	 }
                         	
                         	 public Location getLocation() {
                         	 	 return location;
                         	 }
                         	
                         	 public abstract void sing();
                         }
giovedì 30 giugno 2011
Diamo a Cesare ciò che è di Cesare
                         private boolean isGameFieldValid()
                         {
                         	 boolean isValid = true;
                         	 for(Bird bird : birds) {
                         	 	 int h = bird.getHeight();
                         	 	 Location location = bird.getLocation();
                         	 	 int x = location.x;
                         	 	 int y = location.y;
                         	 	 isValid = fieldSize.isWithinField(h, x, y);
                         	 	 if (!isValid)
                         	 	 	 break;
                         	 }
                         	 return isValid;
                         }




giovedì 30 giugno 2011
Diamo a Cesare ciò che è di Cesare
                         private boolean isGameFieldValid()
                         {
                         	 boolean isValid = true;
                         	 for(Bird bird : birds) {
                         	 	 Location location = bird.getLocation();
                         	 	 int h = location.h;
                         	 	 int x = location.x;
                         	 	 int y = location.y;
                         	 	 isValid = fieldSize.isWithinField(h, x, y);
                         	 	 if (!isValid)
                         	 	 	 break;
                         	 }
                         	 return isValid;
                         }




giovedì 30 giugno 2011
Diamo a Cesare ciò che è di Cesare
            public boolean shot(int x, int y, int h) {
            	 boolean hit = false;
            	 if (gameStarted)
            	 {
            	 	 for(Bird bird : birds) {
            	 	 	 int height = bird.getHeight();
            	 	 	 Location location = bird.getLocation();
            	 	 	 hit = location.x == x && location.y == y && height == h;
            	 	 	 if (hit)
            	 	 	 {
            	 	 	 	 bird.sing();
            	 	 	 	 break;
            	 	 	 }
            	 	 }
            	 }
                return hit;
            }



giovedì 30 giugno 2011
Diamo a Cesare ciò che è di Cesare
        public boolean shot(int x, int y, int h) {
        	 boolean hit = false;
        	 if (gameStarted)
        	 {
        	 	 for(Bird bird : birds) {
        	 	 	 Location location = bird.getLocation();
        	 	 	 hit = location.x == x && location.y == y && location.h == h;
        	 	 	 if (hit)
        	 	 	 {
        	 	 	 	 bird.sing();
        	 	 	 	 break;
        	 	 	 }
        	 	 }
        	 }
            return hit;
        }



giovedì 30 giugno 2011
Quindi ora?
                         public abstract class Bird {
                         	 Location location;
                         	 int height;
                         	
                         	 public void setHeight(int height) throws Exception{
                         	 	 this.height = height;	
                         	 }
                         	
                         	 public int getHeight() {
                         	 	 return height;
                         	 }
                         	
                         	 public void setLocation(Location location) {
                         	 	 this.location = location;
                         	 	
                         	 }
                         	
                         	 public Location getLocation() {
                         	 	 return location;
                         	 }
                         	
                         	 public abstract void sing();
                         }
giovedì 30 giugno 2011
Tell, don’t Ask
        public boolean shot(int x, int y, int h) {
        	 boolean hit = false;
        	 if (gameStarted)
        	 {
        	 	 for(Bird bird : birds) {
        	 	 	 Location location = bird.getLocation();
        	 	 	 hit = location.x == x && location.y == y && location.h == h;
        	 	 	 if (hit)
        	 	 	 {
        	 	 	 	 bird.sing();
        	 	 	 	 break;
        	 	 	 }
        	 	 }
        	 }
            return hit;
        }



giovedì 30 giugno 2011
Applied
        public boolean shot(Location shotLocation) {
        	 boolean hit = false;
        	 if (gameStarted)
        	 {
        	 	 for(Bird bird : birds) {
        	 	 	 hit = shotLocation.equals(bird.getLocation());
        	 	 	 if (hit)
        	 	 	 {
        	 	 	 	 bird.sing();
        	 	 	 	 break;
        	 	 	 }
        	 	 }
        	 }
            return hit;
        }


giovedì 30 giugno 2011
Let’s apply it another time
        public boolean shot(Location shotLocation) {
        	 boolean hit = false;
        	 if (gameStarted)
        	 {
        	 	 for(Bird bird : birds) {
                hit = bird.wasHit(shotLocation)
        	 	 	 if (hit)
        	 	 	 {
        	 	 	 	 bird.sing();
        	 	 	 	 break;
        	 	 	 }
        	 	 }
        	 }
            return hit;
        }


giovedì 30 giugno 2011
Another time too
        public boolean shot(Location shotLocation) {
        	 boolean hit = false;
        	 if (gameStarted)
        	 {
        	 	 for(Bird bird : birds) {
                hit = bird.wasHit(shotLocation)
        	 	 	 if (hit)
        	 	 	 {
        	 	 	 	 break;
        	 	 	 }
        	 	 }
        	 }
            return hit;
        }



giovedì 30 giugno 2011
Programmiamo ad oggetti o
           a tipi primitivi?
                         private boolean isGameFieldValid()
                         {
                         	 boolean isValid = true;
                         	 for(Bird bird : birds) {
                         	 	 Location location = bird.getLocation();
                         	 	 int h = location.h;
                         	 	 int x = location.x;
                         	 	 int y = location.y;
                         	 	 isValid = fieldSize.isWithinField(h, x, y);
                         	 	 if (!isValid)
                         	 	 	 break;
                         	 }
                         	 return isValid;
                         }



giovedì 30 giugno 2011
e allora si fa!

                 private boolean isGameFieldValid()
                 {
                 	 boolean isValid = true;
                 	 for(Bird bird : birds) {
                 	 	 isValid = fieldSize.isWithinField(bird.getLocation());
                 	 	 if (!isValid)
                 	 	 	 break;
                 	 }
                 	 return isValid;
                 }




giovedì 30 giugno 2011
Serve ancora?
  private void placeBirds(PlacingMode type) throws Exception {
  	 	 	
  	 	 //Random Distribution
  	 	 if (type == PlacingMode.Random) {
  	 	 	 for(Bird bird : birds) {
  	 	 	 	 Location location = new Location(new Random().nextInt(fieldSize.width()),
                                                new Random().nextInt(fieldSize.eighth()),
                                                new Random().nextInt(fieldSize.depth()));
  	 	 	 	 bird.setLocation(location);
  	 	 	 	 if (!(bird instanceof Chicken))
  	 	 	 	 	 bird.setHeight(new Random().nextInt(this.depth));
  	 	 	 }
  	 	 }
  	 	 //Custom Distribution
  	 	 else if (type == PlacingMode.Custom) {
  	 	 	
  	 	 }
  	 }



giovedì 30 giugno 2011
E allora rimuoviamolo
  private void placeBirds(PlacingMode type) throws Exception {
  	 	 	
  	 	 //Random Distribution
  	 	 if (type == PlacingMode.Random) {
  	 	 	 for(Bird bird : birds) {
  	 	 	 	 Location location = new Location(new Random().nextInt(fieldSize.width()),
                                                new Random().nextInt(fieldSize.eighth()),
                                                new Random().nextInt(fieldSize.depth()));
  	 	 	 	 bird.setLocation(location);
  	 	 	 }
  	 	 }
  	 	 //Custom Distribution
  	 	 else if (type == PlacingMode.Custom) {
  	 	 	
  	 	 }
  	 }




giovedì 30 giugno 2011
Anche il metodo
                         public abstract class Bird {
                         	 ...
                         	
                         	 public void setHeight(int height) throws Exception{
                         	 	 this.height = height;	
                         	 }

                         	 ...
                         }




giovedì 30 giugno 2011
Gli IF proprio non ci
                               piacciono!


giovedì 30 giugno 2011
Come procediamo?
  private void placeBirds(PlacingMode type) throws Exception {
  	 	 	
  	 	 //Random Distribution
  	 	 if (type == PlacingMode.Random) {
  	 	 	 for(Bird bird : birds) {
  	 	 	 	 Location location = new Location(new Random().nextInt(fieldSize.width()),
                                                new Random().nextInt(fieldSize.eighth()),
                                                new Random().nextInt(fieldSize.depth()));
  	 	 	 	 bird.setLocation(location);
  	 	 	 }
  	 	 }
  	 	 //Custom Distribution
  	 	 else if (type == PlacingMode.Custom) {
  	 	 	
  	 	 }
  	 }




giovedì 30 giugno 2011
I Passi di refactoring
                    •    Estratta responsabilità di “Random placing strategy” in
                         una classe

                    •    estratta interfaccia IPlacingStrategy

                    •    creata class NullPlacingStrategy

                    •    creata Factory per Placing strategy

                    •    “inlainato” metodo placeBirds

                    •    trasformata la factory in un field ed estratto come
                         parametro del costruttore

giovedì 30 giugno 2011
Il risultato
  public class PlacingStrategyFactory {                                                          public interface IPlacingStrategy {

  	     public IPlacingStrategy create(PlacingMode type,                                         	     void place(List<Bird> birds);
                                       FieldSize fieldSize) {
  	     	   if (type == PlacingMode.Random) {                                                    }
  	     	   	    return new RandomPlacingStrategy(fieldSize);
  	     	   }
                                                                          public class NullPlacingStrategy implements IPlacingStrategy {
  	     	   return new NullPlacingStrategy();
  	     }                                                                 	     @Override
                                                                          	     public void place(List<Bird> birds) {
  }                                                                       	     	    // Do nothing
                                                                          	     }

                                                                          }


                                            public class RandomPlacingStrategy implements IPlacingStrategy {
                                            	    private FieldSize fieldSize;

                                            	    public RandomPlacingStrategy(FieldSize fieldSize) {
                                            	    	    this.fieldSize = fieldSize;
                                            	    }

                                            	    @Override
                                            	    public void place(List<Bird> birds) {
                                            	    	    for(Bird bird : birds) {
                                            	    	    	     Location location = new Location(new Random().nextInt(fieldSize.width()),
                                            	    	    	     	    	     	    	     	     	    	       new Random().nextInt(fieldSize.height()),
                                            	    	    	     	    	     	    	     	     	    	       new Random().nextInt(fieldSize.depth()));
                                            	    	    	     bird.setLocation(location);
                                            	    	    }
                                            	    }

                                            }

giovedì 30 giugno 2011
Il risultato
               public class GameField {
                  ...
               	 public boolean startGame(PlacingMode pm) {
               	 	 placingStrategyFactory.create(pm, fieldSize).place(birds);
               	 	 gameStarted = isGameStarted();
               	 	 return gameStarted;
               	 }
                  ...
               }




giovedì 30 giugno 2011
Altri IF che non ci
                             piacciono
                 private boolean isGameFieldValid()
                 {
                 	 boolean isValid = true;
                 	 for(Bird bird : birds) {
                 	 	 isValid = fieldSize.isWithinField(bird.getLocation());
                 	 	 if (!isValid)
                 	 	 	 break;
                 	 }
                 	 return isValid;
                 }




giovedì 30 giugno 2011
Così è meglio

        private boolean isGameFieldValid()
        {
        	 boolean isValid = true;
        	 for(Bird bird : birds) {
        	 	 isValid = isValid && fieldSize.isWithinField(bird.getLocation());
        	 }
        	 return isValid;
        }




giovedì 30 giugno 2011
Stesso discorso
        public boolean shot(Location shotLocation) {
        	 boolean hit = false;
        	 if (gameStarted)
        	 {
        	 	 for(Bird bird : birds) {
                hit = bird.wasHit(shotLocation)
        	 	 	 if (hit)
        	 	 	 {
        	 	 	 	 break;
        	 	 	 }
        	 	 }
        	 }
            return hit;
        }



giovedì 30 giugno 2011
Diventa

        public boolean shot(Location shotLocation) {
        	 boolean hit = false;
        	 if (gameStarted)
        	 {
        	 	 for(Bird bird : birds) {
                hit = hit || bird.wasHit(shotLocation)
        	 	 }
        	 }
            return hit;
        }




giovedì 30 giugno 2011
Di nuovo sulle
                         responsabilità


giovedì 30 giugno 2011
Notate qualcosa?
    private boolean isGameFieldValid()
    {
    	 boolean isValid = true;
    	 for(Bird bird : birds) {
    	 	 isValid = isValid && fieldSize.isWithinField(bird.getLocation());
    	 }
    	 return isValid;
    }

        public boolean shot(Location shotLocation) {
        	 boolean hit = false;
        	 if (gameStarted)
        	 {
        	 	 for(Bird bird : birds) {
                hit = hit || bird.wasHit(shotLocation)
        	 	 }
        	 }
            return hit;
        }

giovedì 30 giugno 2011
BirdList
                public class BirdList extends ArrayList<Bird> {
                	 private static final long serialVersionUID = -3323859086260693300L;
                	
                	 public boolean areAllBirdsPlacedWithinField(FieldSize fieldSize) {
                	 	 boolean isValid = true;
                	 	 for(Bird bird : this) {
                	 	 	 isValid = isValid && fieldSize.isWithinField(bird.getLocation());
                	 	 }
                	 	 return size() > 0 && isValid;

                	        }

                	        public boolean anyBirdWasHit(Location shotLocation) {
                	        	 boolean hit=false;
                	        	 for(Bird bird : this) {
                	        	 	 hit = hit || bird.wasHit(shotLocation);
                	        	 }
                	        	 return hit;
                	        }
                }




giovedì 30 giugno 2011
ed ecco i chiamanti

             private boolean isGameStarted() {
             	 return birds.areAllBirdsPlacedWithinField(fieldSize);
             }
             	
             public boolean shot(Location shotLocation) {
             	 return birds.anyBirdWasHit(shotLocation) && gameStarted;
             }




giovedì 30 giugno 2011
I Repository


                         http://github.com/sleli/BirdWatching




giovedì 30 giugno 2011
GRAZIE
                         Antonio Carpentieri (@acarpe)
                              Stefano Leli (@sleli)



giovedì 30 giugno 2011

More Related Content

More from Stefano Leli

Agile quackery a brief history of the worst ways to cure everything
Agile quackery   a brief history of the worst ways to cure everythingAgile quackery   a brief history of the worst ways to cure everything
Agile quackery a brief history of the worst ways to cure everythingStefano Leli
 
Agile goes Hollywood - Un approccio empirico alle trasformazioni agili
Agile goes Hollywood - Un approccio empirico alle trasformazioni agiliAgile goes Hollywood - Un approccio empirico alle trasformazioni agili
Agile goes Hollywood - Un approccio empirico alle trasformazioni agiliStefano Leli
 
Succeding with feature teams
Succeding with feature teamsSucceding with feature teams
Succeding with feature teamsStefano Leli
 
User Story Mapping
User Story MappingUser Story Mapping
User Story MappingStefano Leli
 
La tua prima kanban board
La tua prima kanban boardLa tua prima kanban board
La tua prima kanban boardStefano Leli
 
Dinosaur Carpaccio - How to implement valuable micro-requirements
Dinosaur Carpaccio - How to implement valuable micro-requirementsDinosaur Carpaccio - How to implement valuable micro-requirements
Dinosaur Carpaccio - How to implement valuable micro-requirementsStefano Leli
 
From Vision To Product
From Vision To ProductFrom Vision To Product
From Vision To ProductStefano Leli
 
Agile retrospective,an example
Agile retrospective,an exampleAgile retrospective,an example
Agile retrospective,an exampleStefano Leli
 
User stories writing - Codemotion 2013
User stories writing   - Codemotion 2013User stories writing   - Codemotion 2013
User stories writing - Codemotion 2013Stefano Leli
 
Codice legacy, usciamo dal pantano! @iad11
Codice legacy, usciamo dal pantano! @iad11Codice legacy, usciamo dal pantano! @iad11
Codice legacy, usciamo dal pantano! @iad11Stefano Leli
 
Il project manager e lo sviluppo agile. Separati in casa?
Il project manager e lo sviluppo agile. Separati in casa?Il project manager e lo sviluppo agile. Separati in casa?
Il project manager e lo sviluppo agile. Separati in casa?Stefano Leli
 
Manage software dependencies with ioc and aop
Manage software dependencies with ioc and aopManage software dependencies with ioc and aop
Manage software dependencies with ioc and aopStefano Leli
 
Design Pattern In Pratica
Design Pattern In PraticaDesign Pattern In Pratica
Design Pattern In PraticaStefano Leli
 
Workshop Su Refactoring
Workshop Su RefactoringWorkshop Su Refactoring
Workshop Su RefactoringStefano Leli
 
Intoduzione Alle Metodologie Agili
Intoduzione Alle Metodologie AgiliIntoduzione Alle Metodologie Agili
Intoduzione Alle Metodologie AgiliStefano Leli
 

More from Stefano Leli (16)

Agile quackery a brief history of the worst ways to cure everything
Agile quackery   a brief history of the worst ways to cure everythingAgile quackery   a brief history of the worst ways to cure everything
Agile quackery a brief history of the worst ways to cure everything
 
Agile goes Hollywood - Un approccio empirico alle trasformazioni agili
Agile goes Hollywood - Un approccio empirico alle trasformazioni agiliAgile goes Hollywood - Un approccio empirico alle trasformazioni agili
Agile goes Hollywood - Un approccio empirico alle trasformazioni agili
 
Succeding with feature teams
Succeding with feature teamsSucceding with feature teams
Succeding with feature teams
 
User Story Mapping
User Story MappingUser Story Mapping
User Story Mapping
 
La tua prima kanban board
La tua prima kanban boardLa tua prima kanban board
La tua prima kanban board
 
Dinosaur Carpaccio - How to implement valuable micro-requirements
Dinosaur Carpaccio - How to implement valuable micro-requirementsDinosaur Carpaccio - How to implement valuable micro-requirements
Dinosaur Carpaccio - How to implement valuable micro-requirements
 
From Vision To Product
From Vision To ProductFrom Vision To Product
From Vision To Product
 
Agile retrospective,an example
Agile retrospective,an exampleAgile retrospective,an example
Agile retrospective,an example
 
User stories writing - Codemotion 2013
User stories writing   - Codemotion 2013User stories writing   - Codemotion 2013
User stories writing - Codemotion 2013
 
Codice legacy, usciamo dal pantano! @iad11
Codice legacy, usciamo dal pantano! @iad11Codice legacy, usciamo dal pantano! @iad11
Codice legacy, usciamo dal pantano! @iad11
 
XP Game
XP GameXP Game
XP Game
 
Il project manager e lo sviluppo agile. Separati in casa?
Il project manager e lo sviluppo agile. Separati in casa?Il project manager e lo sviluppo agile. Separati in casa?
Il project manager e lo sviluppo agile. Separati in casa?
 
Manage software dependencies with ioc and aop
Manage software dependencies with ioc and aopManage software dependencies with ioc and aop
Manage software dependencies with ioc and aop
 
Design Pattern In Pratica
Design Pattern In PraticaDesign Pattern In Pratica
Design Pattern In Pratica
 
Workshop Su Refactoring
Workshop Su RefactoringWorkshop Su Refactoring
Workshop Su Refactoring
 
Intoduzione Alle Metodologie Agili
Intoduzione Alle Metodologie AgiliIntoduzione Alle Metodologie Agili
Intoduzione Alle Metodologie Agili
 

Codice legacy, usciamo dal pantano!

  • 1. Codice Legacy, usciamo dal pantano! Antonio Carpentieri (@acarpe) Stefano Leli (@sleli) giovedì 30 giugno 2011
  • 2. Regole • Tempo a disposizione: 50 minuti • Il codice va rifattorizzato per essere conforme ai principi S.O.L.I.D. • I test possono essere modificati giovedì 30 giugno 2011
  • 5. Single Responsibility Principle “There should never be more than one reason for a class to change” giovedì 30 giugno 2011
  • 7. Interface Segregation Principle “Clients should not be forced to depend upon interfaces that they do not use” public interface MobileDevice { void Call(string phoneNumber); void PlayAudio(Uri uri); void PlayVideo(Uri uri); void TakePicture(); void StartRecordingAudio(); void StopRecordingAudio(); void StartRecordingVideo(); void StopRecordingVideo(); } giovedì 30 giugno 2011
  • 11. Liskov Substitution Principle “Functions that use pointers or references to base classes must be able to use objects of derived classes without knowing it.” giovedì 30 giugno 2011
  • 12. Bird Watching Game http://github.com/sleli/BirdWatching giovedì 30 giugno 2011
  • 13. Il Gioco • Simulatore di Bird Watching • Una sorta di “battaglia navale”... ma qui gli assi sono 3 (gli uccelli volano) giovedì 30 giugno 2011
  • 14. Le Classi giovedì 30 giugno 2011
  • 16. Classe GameField Responsabilità Collaborazioni Gestisce la collezione di Birds Dispone il campo da gioco Valida il campo da gioco Classe Bird Inizializza il campo (start) Gestisce le logiche degli shot Il refactoring verterà sulla suddivizione di responsabilità (aumentare la coesione, diminuire l’accoppiamento) •Maggiore riuso del codice •Maggiore robusteza del programma •Minor costo del cambiamento giovedì 30 giugno 2011
  • 19. Duplicazione (semplice) @Before public void Setup() { field = new GameField(10,5,3, new FieldSize(10,5,3)); } giovedì 30 giugno 2011
  • 20. Duplicazione (semplice) public GameField(int width, int height, int depth, FieldSize fieldSize) { this.width = width; this.height = height; this.depth = depth; this.fieldSize = fieldSize; birds = new ArrayList<Bird>(); } giovedì 30 giugno 2011
  • 21. Duplicazione (semplice) //Place the birds on the fields private void placeBirds(PlacingMode type) throws Exception { ... Location location = new Location(new Random().nextInt(this.width), new Random().nextInt(this.height)); bird.setLocation(location); if (!(bird instanceof Chicken)) bird.setHeight(new Random().nextInt(this.depth)); ... } giovedì 30 giugno 2011
  • 23. Eliminiamola! @Before public void Setup() { field = new GameField(new FieldSize(10,5,3)); } giovedì 30 giugno 2011
  • 24. Eliminiamola! @Before public void Setup() { field = new GameField(new FieldSize(10,5,3)); } public GameField(FieldSize fieldSize) { this.fieldSize = fieldSize; birds = new ArrayList<Bird>(); } giovedì 30 giugno 2011
  • 25. Eliminiamola! @Before public void Setup() { field = new GameField(new FieldSize(10,5,3)); } public GameField(FieldSize fieldSize) { this.fieldSize = fieldSize; birds = new ArrayList<Bird>(); } //Place the birds on the fields private void placeBirds(PlacingMode type) throws Exception { ... Location location = new Location(new Random().nextInt(fieldSize.width()), new Random().nextInt(fieldSize.height())); bird.setLocation(location); if (!(bird instanceof Chicken)) bird.setHeight(new Random().nextInt(fieldSize.depth())); ... } giovedì 30 giugno 2011
  • 26. Diamo a Cesare ciò che è di Cesare giovedì 30 giugno 2011
  • 27. Diamo a Cesare ciò che è di Cesare public class Location { int x = 0; int y = 0; public Location (int x, int y) { this.x = x; this.y = y; } } giovedì 30 giugno 2011
  • 28. Diamo a Cesare ciò che è di Cesare giovedì 30 giugno 2011
  • 29. Diamo a Cesare ciò che è di Cesare bird.setLocation(location); if (!(bird instanceof Chicken)) bird.setHeight(new Random().nextInt(this.depth)); giovedì 30 giugno 2011
  • 30. Diamo a Cesare ciò che è di Cesare bird.setLocation(location); if (!(bird instanceof Chicken)) bird.setHeight(new Random().nextInt(this.depth)); Bird duck = new Duck(); duck.setLocation(new Location(10,5)); duck.setHeight(3); giovedì 30 giugno 2011
  • 31. Diamo a Cesare ciò che è di Cesare bird.setLocation(location); if (!(bird instanceof Chicken)) bird.setHeight(new Random().nextInt(this.depth)); Bird duck = new Duck(); duck.setLocation(new Location(10,5)); duck.setHeight(3); int h = bird.getHeight(); Location location = bird.getLocation(); int x = location.x; int y = location.y; isValid = fieldSize.isWithinField(h, x, y); giovedì 30 giugno 2011
  • 32. Diamo a Cesare ciò che è di Cesare public class Location { int x = 0; int y = 0; int h = 0; public Location (int x, int y) { this(x, y, 0); } public Location (int x, int y, int z) { this.x = x; this.y = y; this.h = z; } } giovedì 30 giugno 2011
  • 33. Diamo a Cesare ciò che è di Cesare Location location = new Location(new Random().nextInt(fieldSize.width()), new Random().nextInt(fieldSize.height()), new Random().nextInt(fieldSize.depth())); giovedì 30 giugno 2011
  • 34. Diamo a Cesare ciò che è di Cesare public abstract class Bird { Location location; int height; public void setHeight(int height) throws Exception{ this.location.h = height; } public int getHeight() { return location.h; } public void setLocation(Location location) { this.location = location; } public Location getLocation() { return location; } public abstract void sing(); } giovedì 30 giugno 2011
  • 35. Diamo a Cesare ciò che è di Cesare private boolean isGameFieldValid() { boolean isValid = true; for(Bird bird : birds) { int h = bird.getHeight(); Location location = bird.getLocation(); int x = location.x; int y = location.y; isValid = fieldSize.isWithinField(h, x, y); if (!isValid) break; } return isValid; } giovedì 30 giugno 2011
  • 36. Diamo a Cesare ciò che è di Cesare private boolean isGameFieldValid() { boolean isValid = true; for(Bird bird : birds) { Location location = bird.getLocation(); int h = location.h; int x = location.x; int y = location.y; isValid = fieldSize.isWithinField(h, x, y); if (!isValid) break; } return isValid; } giovedì 30 giugno 2011
  • 37. Diamo a Cesare ciò che è di Cesare public boolean shot(int x, int y, int h) { boolean hit = false; if (gameStarted) { for(Bird bird : birds) { int height = bird.getHeight(); Location location = bird.getLocation(); hit = location.x == x && location.y == y && height == h; if (hit) { bird.sing(); break; } } } return hit; } giovedì 30 giugno 2011
  • 38. Diamo a Cesare ciò che è di Cesare public boolean shot(int x, int y, int h) { boolean hit = false; if (gameStarted) { for(Bird bird : birds) { Location location = bird.getLocation(); hit = location.x == x && location.y == y && location.h == h; if (hit) { bird.sing(); break; } } } return hit; } giovedì 30 giugno 2011
  • 39. Quindi ora? public abstract class Bird { Location location; int height; public void setHeight(int height) throws Exception{ this.height = height; } public int getHeight() { return height; } public void setLocation(Location location) { this.location = location; } public Location getLocation() { return location; } public abstract void sing(); } giovedì 30 giugno 2011
  • 40. Tell, don’t Ask public boolean shot(int x, int y, int h) { boolean hit = false; if (gameStarted) { for(Bird bird : birds) { Location location = bird.getLocation(); hit = location.x == x && location.y == y && location.h == h; if (hit) { bird.sing(); break; } } } return hit; } giovedì 30 giugno 2011
  • 41. Applied public boolean shot(Location shotLocation) { boolean hit = false; if (gameStarted) { for(Bird bird : birds) { hit = shotLocation.equals(bird.getLocation()); if (hit) { bird.sing(); break; } } } return hit; } giovedì 30 giugno 2011
  • 42. Let’s apply it another time public boolean shot(Location shotLocation) { boolean hit = false; if (gameStarted) { for(Bird bird : birds) { hit = bird.wasHit(shotLocation) if (hit) { bird.sing(); break; } } } return hit; } giovedì 30 giugno 2011
  • 43. Another time too public boolean shot(Location shotLocation) { boolean hit = false; if (gameStarted) { for(Bird bird : birds) { hit = bird.wasHit(shotLocation) if (hit) { break; } } } return hit; } giovedì 30 giugno 2011
  • 44. Programmiamo ad oggetti o a tipi primitivi? private boolean isGameFieldValid() { boolean isValid = true; for(Bird bird : birds) { Location location = bird.getLocation(); int h = location.h; int x = location.x; int y = location.y; isValid = fieldSize.isWithinField(h, x, y); if (!isValid) break; } return isValid; } giovedì 30 giugno 2011
  • 45. e allora si fa! private boolean isGameFieldValid() { boolean isValid = true; for(Bird bird : birds) { isValid = fieldSize.isWithinField(bird.getLocation()); if (!isValid) break; } return isValid; } giovedì 30 giugno 2011
  • 46. Serve ancora? private void placeBirds(PlacingMode type) throws Exception { //Random Distribution if (type == PlacingMode.Random) { for(Bird bird : birds) { Location location = new Location(new Random().nextInt(fieldSize.width()), new Random().nextInt(fieldSize.eighth()), new Random().nextInt(fieldSize.depth())); bird.setLocation(location); if (!(bird instanceof Chicken)) bird.setHeight(new Random().nextInt(this.depth)); } } //Custom Distribution else if (type == PlacingMode.Custom) { } } giovedì 30 giugno 2011
  • 47. E allora rimuoviamolo private void placeBirds(PlacingMode type) throws Exception { //Random Distribution if (type == PlacingMode.Random) { for(Bird bird : birds) { Location location = new Location(new Random().nextInt(fieldSize.width()), new Random().nextInt(fieldSize.eighth()), new Random().nextInt(fieldSize.depth())); bird.setLocation(location); } } //Custom Distribution else if (type == PlacingMode.Custom) { } } giovedì 30 giugno 2011
  • 48. Anche il metodo public abstract class Bird { ... public void setHeight(int height) throws Exception{ this.height = height; } ... } giovedì 30 giugno 2011
  • 49. Gli IF proprio non ci piacciono! giovedì 30 giugno 2011
  • 50. Come procediamo? private void placeBirds(PlacingMode type) throws Exception { //Random Distribution if (type == PlacingMode.Random) { for(Bird bird : birds) { Location location = new Location(new Random().nextInt(fieldSize.width()), new Random().nextInt(fieldSize.eighth()), new Random().nextInt(fieldSize.depth())); bird.setLocation(location); } } //Custom Distribution else if (type == PlacingMode.Custom) { } } giovedì 30 giugno 2011
  • 51. I Passi di refactoring • Estratta responsabilità di “Random placing strategy” in una classe • estratta interfaccia IPlacingStrategy • creata class NullPlacingStrategy • creata Factory per Placing strategy • “inlainato” metodo placeBirds • trasformata la factory in un field ed estratto come parametro del costruttore giovedì 30 giugno 2011
  • 52. Il risultato public class PlacingStrategyFactory { public interface IPlacingStrategy { public IPlacingStrategy create(PlacingMode type, void place(List<Bird> birds); FieldSize fieldSize) { if (type == PlacingMode.Random) { } return new RandomPlacingStrategy(fieldSize); } public class NullPlacingStrategy implements IPlacingStrategy { return new NullPlacingStrategy(); } @Override public void place(List<Bird> birds) { } // Do nothing } } public class RandomPlacingStrategy implements IPlacingStrategy { private FieldSize fieldSize; public RandomPlacingStrategy(FieldSize fieldSize) { this.fieldSize = fieldSize; } @Override public void place(List<Bird> birds) { for(Bird bird : birds) { Location location = new Location(new Random().nextInt(fieldSize.width()), new Random().nextInt(fieldSize.height()), new Random().nextInt(fieldSize.depth())); bird.setLocation(location); } } } giovedì 30 giugno 2011
  • 53. Il risultato public class GameField { ... public boolean startGame(PlacingMode pm) { placingStrategyFactory.create(pm, fieldSize).place(birds); gameStarted = isGameStarted(); return gameStarted; } ... } giovedì 30 giugno 2011
  • 54. Altri IF che non ci piacciono private boolean isGameFieldValid() { boolean isValid = true; for(Bird bird : birds) { isValid = fieldSize.isWithinField(bird.getLocation()); if (!isValid) break; } return isValid; } giovedì 30 giugno 2011
  • 55. Così è meglio private boolean isGameFieldValid() { boolean isValid = true; for(Bird bird : birds) { isValid = isValid && fieldSize.isWithinField(bird.getLocation()); } return isValid; } giovedì 30 giugno 2011
  • 56. Stesso discorso public boolean shot(Location shotLocation) { boolean hit = false; if (gameStarted) { for(Bird bird : birds) { hit = bird.wasHit(shotLocation) if (hit) { break; } } } return hit; } giovedì 30 giugno 2011
  • 57. Diventa public boolean shot(Location shotLocation) { boolean hit = false; if (gameStarted) { for(Bird bird : birds) { hit = hit || bird.wasHit(shotLocation) } } return hit; } giovedì 30 giugno 2011
  • 58. Di nuovo sulle responsabilità giovedì 30 giugno 2011
  • 59. Notate qualcosa? private boolean isGameFieldValid() { boolean isValid = true; for(Bird bird : birds) { isValid = isValid && fieldSize.isWithinField(bird.getLocation()); } return isValid; } public boolean shot(Location shotLocation) { boolean hit = false; if (gameStarted) { for(Bird bird : birds) { hit = hit || bird.wasHit(shotLocation) } } return hit; } giovedì 30 giugno 2011
  • 60. BirdList public class BirdList extends ArrayList<Bird> { private static final long serialVersionUID = -3323859086260693300L; public boolean areAllBirdsPlacedWithinField(FieldSize fieldSize) { boolean isValid = true; for(Bird bird : this) { isValid = isValid && fieldSize.isWithinField(bird.getLocation()); } return size() > 0 && isValid; } public boolean anyBirdWasHit(Location shotLocation) { boolean hit=false; for(Bird bird : this) { hit = hit || bird.wasHit(shotLocation); } return hit; } } giovedì 30 giugno 2011
  • 61. ed ecco i chiamanti private boolean isGameStarted() { return birds.areAllBirdsPlacedWithinField(fieldSize); } public boolean shot(Location shotLocation) { return birds.anyBirdWasHit(shotLocation) && gameStarted; } giovedì 30 giugno 2011
  • 62. I Repository http://github.com/sleli/BirdWatching giovedì 30 giugno 2011
  • 63. GRAZIE Antonio Carpentieri (@acarpe) Stefano Leli (@sleli) giovedì 30 giugno 2011