SlideShare uma empresa Scribd logo
1 de 186
Die Kunst des Software-Design
oder was Software-Entwickler von der Tierwelt lernen können

PHP World Kongress 2009
Holger Rüprich und Stephan Schmidt
Holger Rüprich

• Head of Sales Processes Consumer
  bei der 1&1 Internet AG


• Clean Code Enthusiast


• Gast-Dozent an der Berufs-
  Akademie Mosbach


• Autor für die Zeitschrift T3N
Stephan Schmidt

• Head of Web Sales Development
  bei der 1&1 Internet AG


• Design Patterns Enthusiast


• Autor von PHP Design Patterns
  sowie anderen Büchern und über
  30 Fachartikeln


• Redner auf internationalen
  Konferenzen
Software Design




 „Software Design is a process of problem solving
 and planning for a software solution.“
 Wikipedia
Kunst



 „Das Wort Kunst bezeichnet im weitesten Sinne
 jede entwickelte Tätigkeit, die auf Wissen, Übung,
 Wahrnehmung, Vorstellung und Intuition
 gegründet ist.“
 Wikipedia
Ziele von Software Design
Ziele von Software Design




             Software soll stabil sein.
Ziele von Software Design
Ziele von Software Design




             Software soll sicher sein.
Ziele von Software Design
Ziele von Software Design




            Software soll flexibel sein.
Ziele von Software Design
Ziele von Software Design




           Software soll performant sein.
Ziele von Software Design
Das Eichhörnchen
Das Eichhörnchen

Kapsle Daten und Algorithmen.
Von der realen Welt ...

                          • Bob hat eine Autovermietung


                          • Er muss Autos einkaufen


                          • Er vermietet unterschiedliche
                            Modelle


                          • Er vermietet Autos zu verschiedenen
                            Preisen
... zur programmierten Welt

• Klassen übertragen Dinge aus der realen Welt in die programmierte Welt

 class Car {

     protected   $manufacturer;
     protected   $color;
     protected   $milage;
     protected   $engineStarted = false;

     public   function   startEngine() {}
     public   function   driveForward($miles) {}
     public   function   stopEngine() {}
     public   function   getManufacturer() {}
     public   function   getColor() {}
     public   function   getMilage() {}
 }
Kapsle den Zugriff auf Daten

 Kapsle den Zugriff auf Daten immer innerhalb
 einer Klasse und biete Methoden an, um diese
 Daten abzufragen.
         class Car {

             ... Eigenschaften und Methoden ...

             public function getDailyRate($days = 1) {
               return 75.5;
             }
         }
Kapsle den Zugriff auf Daten

 Kapsle den Zugriff auf Daten immer innerhalb
 einer Klasse und biete Methoden an, um diese
 Daten abzufragen.
         class Car {

             ... Eigenschaften und Methoden ...

             public function getDailyRate($days = 1) {
               if ($days >= 7) {
                 return 65.9;
               }
               return 75.5;
             }
         }
Bobs Kunden


              class Customer {
                protected $id;
                protected $name;

                  public function __construct($id, $name) {
                    $this->id = $id;
                    $this->name = $name;
                  }

                  public function getId() {
                    return $this->id;
                  }

                  public function getName() {
                    return $this->name;
                  }
              }
Bobs Firma



 class RentalCompany {

     protected $fleet = array();

     public function addToFleet($id, Car $car) {
       $this->fleet[$id] = $vehicle;
     }

     public function rentCar(Car $car,
                             Customer $customer) {}

     public function returnCar(Car $car) {}

 }
Bobs Geschäft

• Klassen übertragen nicht nur physikalische Dinge, sondern auch Abläufe

  class RentalAction {
      ... Eigenschaften ...

      public function __construct(Car $car, Customer $customer,
                                  $date = null) {
        if ($date === null) {
         $date = date('Y-m-d H:i:s');
        }
        $this->car      = $car;
        $this->customer = $customer;
        $this->rentDate = $date;
      }

      ... Getter ...
  }
Bobs Geschäft

• Klassen übertragen nicht nur physikalische Dinge, sondern auch Abläufe

  class RentalAction {
    ...

      public function markCarReturned($date = null) {
        if ($date === null) {
          $date = date('Y-m-d H:i:s');
        }
        $this->returnDate = $date;
      }

      public function isReturned() {
        return $this->returnDate !== null;
      }
  }
Kapsle auch Algorithmen



 Kapsle nicht nur Daten sondern auch Algorithmen
 in den Methoden deiner Klassen, um komplexe
 Operationen zentral an einer Stelle zu
 implementieren.
Bobs Firma

      class RentalCompany {

          ...

          public function rentCar(Car $car, Customer $customer) {
            $carId = array_search($car, $this->fleet);
            if ($carId === false) {
              throw new UnknownCarException();
            }
            if (!$this->isCarAvailable($car)) {
              throw new CarNotAvailableException();
            }
            $rentalAction = new RentalAction($car, $customer);
            $this->rentalActions[] = $rentalAction;

              return $rentalAction;
          }


      }
Bobs Firma

       class RentalCompany {

           ...

           public function isCarAvailable(Car $car) {
             foreach ($this->rentalActions as $rentalAction) {
               if ($rentalAction->getCar() !== $car) {
                 continue;
               }
               if ($rentalAction->isReturned()) {
                 continue;
               }
               return false;
             }
             return true;
           }

       }
Bobs Firma

      class RentalCompany {

          ...

          public function returnCar(Car $car) {
            foreach ($this->rentalActions as $rentalAction) {
              if ($rentalAction->getCar() !== $car) {
                continue;
              }
              if ($rentalAction->isReturned()) {
                continue;
              }
              $rentalAction->markCarReturned();
              return true;
            }
            return false;
          }

      }
Die Weisheit des Eichhörnchens



                 Schütze deine Daten.
Verberge Implementierungsdetails und unterbinde den Zugriff auf
interne Datenstrukturen.
Wähle Klassen- und Methodennamen sinnvoll
und achte darauf, dass der resultierende Code
sich wie ein Satz lesen lässt.
Das Krokodil
Das Krokodil

Achte das Single-Reponsibility-Prinzip.
Das Single-Responsibility-Prinzip




 „There should never be more than one reason for
 a class to change“
 Robert C. Martin
Bob will wissen was los ist
 class RentalCompany {
   public function addToFleet($id, Vehicle $vehicle) {
     $this->fleet[$id] = $vehicle;
     print "Neues Auto im Fuhrpark: " . $vehicle->getManufacturer() . "n";
   }

     public function rentVehicle(Vehicle $vehicle, Customer $customer) {
       ...
       print "Neuer Mietvorgang: " . $customer->getName() . " leiht " .
             $vehicle->getManufacturer() . "n";
       return $rentalAction;
     }

     ...
 }


 >   Neues Auto im Fuhrpark: BMW
 >   Neuer Mietvorgang: Stephan Schmidt leiht BMW
 >   Rückgabe: Stephan Schmidt gibt BMW zurück
 >   Neuer Mietvorgang: Gerd Schaufelberger leiht BMW
Bob will wissen was los ist
 class RentalCompany {
   public function addToFleet($id, Vehicle $vehicle) {
     $this->fleet[$id] = $vehicle;
     print "Neues Auto im Fuhrpark: " . $vehicle->getManufacturer() . "n";
   }

             Was ist mit Problemen im Produktivbetrieb?
     public function rentVehicle(Vehicle $vehicle, Customer $customer) {
       ...
       print "Neuer Mietvorgang: " . $customer->getName() . " leiht " .
             $vehicle->getManufacturer() . "n";
       return $rentalAction;
     }

     ...
 }


 >   Neues Auto im Fuhrpark: BMW
 >   Neuer Mietvorgang: Stephan Schmidt leiht BMW
 >   Rückgabe: Stephan Schmidt gibt BMW zurück
 >   Neuer Mietvorgang: Gerd Schaufelberger leiht BMW
Debugging im Produktivbetrieb
class RentalCompany {
  public function addToFleet($id, Vehicle $vehicle) {
    $this->fleet[$id] = $vehicle;
    switch (DEBUG_MODE) {
      case 'echo':
        print "Neues Auto im Fuhrpark: " . $vehicle->getManufacturer() . "n";
        break;
      case 'log':
        error_log("Neues Auto im Fuhrpark: " . $vehicle->getManufacturer() . "n",
          3, '.RentalCompany.log');
        break;
    }
  }

 public function rentVehicle(Vehicle $vehicle, Customer $customer) {
   ...
   switch (DEBUG_MODE) {
     case 'echo':
       print "Neuer Mietvorgang: " . $customer->getName() . " leiht " .
         $vehicle->getManufacturer() . "n";
       break;
     ...
   return $rentalAction;
 }
Debugging im Produktivbetrieb
class RentalCompany {
  public function addToFleet($id, Vehicle $vehicle) {
    $this->fleet[$id] = $vehicle;
    switch (DEBUG_MODE) {
      case 'echo':
        print "Neues Auto im Fuhrpark: " . $vehicle->getManufacturer() . "n";
        break;
      case 'log':
        error_log("Neues Auto im Fuhrpark: " . $vehicle->getManufacturer() . "n",

             Code Duplizierung macht die Anwendung
          3, '.RentalCompany.log');
        break;

               langsamer und schwerer zu warten
    }
  }

 public function rentVehicle(Vehicle $vehicle, Customer $customer) {
   ...
   switch (DEBUG_MODE) {
     case 'echo':
       print "Neuer Mietvorgang: " . $customer->getName() . " leiht " .
         $vehicle->getManufacturer() . "n";
       break;
     ...
   return $rentalAction;
 }
Wiederverwendbarkeit statt Copy-and-Paste

class RentalCompany {
  public function addToFleet($id, Vehicle $vehicle) {
    $this->fleet[$id] = $vehicle;
    $this->debug("Neues Auto im Fuhrpark: " . $vehicle->getManufacturer());
  }

    public function rentVehicle(Vehicle $vehicle, Customer $customer) {
      ...
      $this->debug("Neuer Mietvorgang: " . $customer->getName() . " leiht " .
            $vehicle->getManufacturer());
      return $rentalAction;
    }

    ...
}
Wiederverwendbarkeit statt Copy-and-Paste

class RentalCompany {
  ...

    protected function debug($message) {
      switch (DEBUG_MODE) {
        case 'echo':
          print "{$message}n";
          break;
        case 'log':
          error_log("{$message}n", 3, './RentalCompany.log');
          break;
      }
    }
}
Wiederverwendbarkeit statt Copy-and-Paste

class RentalCompany {
  ...

        Weitere Debugging-Ziele, wie E-Mails oder SMS,
    protected function debug($message) {
      switch (DEBUG_MODE) {
           machen die debug()-Methode komplexer
        case 'echo':
          print "{$message}n";
          break;
        case 'log':und somit fehleranfälliger.
          error_log("{$message}n", 3, './RentalCompany.log');
          break;
      }
    }
}
Atomare Probleme lösen

abstract class RentalCompany {
  ... Eigenschaften und Methoden der Klasse ...

    abstract protected function debug($message);
}


class EchoingRentalCompany extends RentalCompany {
  protected function debug($message) {
    echo "{$message}n";
  }
}


class LoggingRentalCompany extends RentalCompany {
  protected function debug($message) {
    error_log("{$message}n", 3, './RentalCompany.log');
  }
}
Atomare Probleme lösen

switch (DEBUG_MODE) {
  case 'echo':
    $company = new EchoingRentalCompany();
    break;
  case 'log':
    $company = new LoggingRentalCompany();
    break;
}

$bmw = new Car('BMW', 'blau');
$stephan = new Customer(1, 'Stephan Schmidt');
$gerd = new Customer(2, 'Gerd Schaufelberger');

$company->addToFleet('bmw1', $bmw);
$company->rentVehicle($bmw, $stephan);
$company->returnVehicle($bmw);
Atomare Probleme lösen

switch (DEBUG_MODE) {
  case 'echo':
    $company = new EchoingRentalCompany();
    break;
  case 'log':

       Die debug()-Methode steht nur Unterklassen von
    $company = new LoggingRentalCompany();
    break;
}
               RentalCompany zur Verfügung.
$bmw = new Car('BMW', 'blau');
$stephan = new Customer(1, 'Stephan Schmidt');
$gerd = new Customer(2, 'Gerd Schaufelberger');

$company->addToFleet('bmw1', $bmw);
$company->rentVehicle($bmw, $stephan);
$company->returnVehicle($bmw);
Komposition statt Vererbung

interface Debugger {
  public function debug($message);
}

class DebuggerEcho {
  public function debug($message) {
    echo "{$message}n";
  }
}

class DebuggerLog {
  public function debug($message) {
    error_log("{$message}n", 3, './RentalCompany.log');
  }
}
Komposition statt Vererbung

class RentalCompany {
  ... Eigenschaften der Klasse ...

    protected $debugger;

    public function __construct() {
      switch (DEBUG_MODE) {
        case 'echo':
          $this->debugger = new DebuggerEcho();
          break;
        case 'log':
          $this->debugger = new DebuggerLog();
          break;
      }
    }

    public function debug($message) {
      $this->debugger->debug($message);
    }
}
Die Weisheit des Krokodils



                 Teile und herrsche.
Jedes Modul soll genau eine Verantwortung übernehmen, und jede
Verantwortung soll genau einem Modul zugeordnet werden.
Die Schildkröte
Die Schildkröte

Achte das Open-Closed-Prinzip.
Das Open-Closed-Prinzip




 „Software entities (classes, modules, functions,
 etc.) should be open for extension, but closed for
 modification.“
 Bertrand Meyer
Komposition statt Vererbung

class RentalCompany {
  ... Eigenschaften der Klasse ...

    protected $debugger;

    public function __construct() {
      switch (DEBUG_MODE) {
        case 'echo':
          $this->debugger = new DebuggerEcho();
          break;
        case 'log':
          $this->debugger = new DebuggerLog();
          break;
      }
    }

    public function debug($message) {
      $this->debugger->debug($message);
    }
}
Komposition statt Vererbung

class RentalCompany {
  ... Eigenschaften der Klasse ...

    protected $debugger;

    public function __construct() {
      switch (DEBUG_MODE) {

                  Die RentalCompany Klassen ist von
        case 'echo':
          $this->debugger = new DebuggerEcho();
          break;
        case 'log':   anderen Klassen abhängig
          $this->debugger = new DebuggerLog();
          break;
      }
    }

    public function debug($message) {
      $this->debugger->debug($message);
    }
}
Einsatz von Interfaces

 class RentalCompany {
   ... Eigenschaften der Klasse ...

     public function __construct(Debugger $debugger) {
       $this->debugger = $debugger;
     }

     ... weitere Methoden der Klasse ...
 }




 $debugger = new DebuggerEcho();
 $company = new RentalCompany($debugger);
Die Weisheit der Schildkröte



                Schütze deinen Code.
Programmiere immer gegen Schnittstellen, nie gegen eine konkrete
Implementierung.
Vermeide feste Abhängigkeiten zwischen einzelnen Klassen deiner
Anwendungen und ziehe immer lose Kopplung der Klassen vor.
Der Erpel
Der Erpel

Achte das Hollywood-Prinzip.
Das Hollywood Prinzip




 „Rufen Sie uns nicht an, wir werden Sie anrufen.“
 Das Hollywood Prinzip
Das Hollywood Prinzip

                        • Auch bekannt als „Inversion of
                          Control“


                        • Objekte sollen sich ihre
                          Abhängigkeiten nicht selbst holen
                          oder erzeugen


                        • Objekte sollen unabhängig von ihrer
                          Umgebung sein
Dependency Injection

• Objekte erstellen abhängige Objekte nicht selbst


• Abhängige Objekte werden von außen über den Konstruktor (Constructor
  Injection) oder über Setter-Methoden (Setter Injection) injiziert


• Abhängige Objekte sind dadurch sehr leicht austauschbar
Dependency Injection
 $debugger = new DebuggerEcho();
 $company = new RentalCompany($debugger);   Constructor Injection
 $logger = new DateTimeLogger();
 $company->setLogger($logger);              Setter Injection


• RentalCompany weiß weder, welche Implementierung des Debugger-Interface
  noch welche Implementierung des Logger-Interface sie verwendet


• RentalCompany steuert nicht, wie sie an ihre Abhängigkeiten kommt, der
  Kontrollfluss wird von außerhalb gesteuert


• Aber: Sehr viel zusätzlicher Client Code, durch Instanziieren und Injizieren der
  Objekte nötig
Inversion-of-Control-Container

• In der Java-Welt schon weit verbreitet


   • Spring, Google Guice, Tapestry IoC, ...


• In PHP noch nicht weit verbreitet


   • Stubbles, Garden, XJConf for PHP
Stubbles IoC Container

• Portierung von Google Guice (Java)


• Entwickelt als Teil des Stubble Frameworks


• Kann auch außerhalb der Frameworks verwendet werden


• Basiert auf Type Hints und Annotations


  • Keine native Unterstützung durch PHP


  • Annotations als Teil der PHP-Doc-Kommentare
Rufen Sie Bob nicht an, Bob ruft sie an.

 class RentalCompany {
   ... Eigenschaften der Klasse ...

     /**
       * @Inject                                        Constructor Injection
       */
     public function __construc(Debugger $debugger) {
        $this->debugger = $debugger;
     }

     /**
       * @Inject                                        Setter Injection
       */
     public function setLogger(Logger $logger) {
        $this->logger = $logger;
     }

     ...

 }
Interfaces binden

• Typen werden durch Binder an konkrete Implementierungen gebunden:

 $binder = new stubBinder();
 $binder->bind('Debugger')->to('DebuggerEcho');
 $binder->bind('Logger')->to('DateTimeLogger');



• Binder kann Injector liefern, der Instanzen erzeugt:

 $injector = $binder->getInjector();
 $company = $injector->getInstance('RentalCompany');
Fortgeschrittene Techniken

• Verwenden einer Standardimplementierung
 /**
  * @ImplementedBy(DateTimeLogger.class)
  */
 interface Logger {



• Mehrere Implementierungen für ein Interface
 /**
  * @Inject
  * @Named("Debugger")
 public function setLogger(Logger $logger)

 $binder = new stubBinder();
 $binder->bind('Logger')->to('DateTimeLogger');
 $binder->bind('Logger')->named('Debugger')->to('SimpleLogger');
Die Weisheit des Erpel



          Verwende ein DI Framework.
Erleichtere dir das Verwalten von komplexen Objektstrukturen
durch den Einsatz eines Dependency Injection Frameworks.
Die Biene
Die Biene

Nutze Design Patterns.
Konkretes Problem




 „Ich möchte Debug-Meldungen auf verschiedene
 Arten verarbeiten und diese auswechseln können,
 ohne den Code der RentalCompany Klasse
 anpassen zu müssen.“
 Bob
Abstraktes Problem


 „Ich möchte eine Aufgabe mit verschiedenen
 Algorithmen lösen können. Jede der Lösungen soll
 gekapselt sein und nichts von den anderen wissen.
 Die einzelnen Lösungen sollen gegeneinander
 austauschbar sein, ohne den nutzenden Client
 anzupassen.“
 Abstract Bob
Konkret vs Abstrakt


          Abstrakt            Konkret

                       Verarbeiten von Debug-
          Aufgabe
                             Meldungen

                        Ausgeben per print(),
         Algorithmen
                       Schreiben eines Logfiles

                            Die Klasse
           Client
                          RentalCompany
Konkret vs Abstrakt


          Abstrakt            Konkret

                          Persistieren von
          Aufgabe
                         Gästebucheinträgen

                       Speichern in Datenbank,
         Algorithmen
                       Speichern in XML-Datei

           Client       Die Klasse Guestbook
Bobs erstes Design Pattern




          Strategy-Pattern
Design Patterns

• Lösungsmuster für häufig auftretende Entwurfsaufgaben in der Software-
  Entwicklung


• Keine Code-Bibliothek


• Organisiert in Pattern-Katalogen (z.B. Gang-of-Four Buch)


• Verschiedene Kategorien: Erzeugungsmuster, Strukturmuster,
  Verhaltensmuster, Enterprise-Patterns
Erzeugungsmuster

• Erzeugungsmuster werden verwendet, um Objekte zu konstruieren.


• Zu den Erzeugungsmustern gehöhren unter anderem


  • Singleton-Pattern


  • Factory-Method-Pattern


  • Prototype-Pattern


  • Abstract-Factory-Pattern
Factory-Method-Pattern

• Definiert eine Schnittstelle zur Erzeugung von Objekten


• Verlagert die eigentliche Instanziierung in Unterklassen


• Lässt Unterklassen entscheiden, welche konkrete Implementierung
  verwendet wird
Factory-Method-Pattern

 abstract class AbstractManufacturer {

     protected $name;

     public function __construct($name) {
       $this->name = $name;
     }

     public function sellVehicle() {
       $vehicle = $this->manufactureVehicle();
       // weitere Operationen möglich
       return $vehicle;
     }

     public abstract function manufactureVehicle();

 }
Factory-Method-Pattern



 class CarManufacturer extends AbstractManufacturer {

     public function manufactureVehicle() {
       return new Car($this->name);
     }

 }

 $bmwManufacturer = new CarManufacturer('BMW');
 $bmw = $bmwManufacturer->sellVehicle();
Factory-Method-Pattern



 Das Factory-Method-Pattern definiert eine
 Schnittstelle zur Erzeugung von Objekten. Es
 verlagert aber die eigentliche Instanziierung in
 Unterklassen; es lässt die Unterklassen
 entscheiden, welche konkreten
 Implementierungen verwendet werden.
der abstrak
                                                                           lichen Objekte zu
     4. Verwenden Sie nun diese konk   reten Unterklassen, um die tatsäch
                                                                            ementierungen zu
        instanziieren und Ihren Applik ationscode von den konkreten Impl
        lösen.
                                                                               fach darauf, die
                                           verwenden möchten, achten Sie ein
Factory-Method-Pattern
    Wann immer Sie eine Fabrikmetho
                                       de
    hier gezeigten Schritte durchzuführe
                                         n, und dem Erfolg Ihres Vorhabens
                                                                             steht nichts mehr
                                                                             teiligten des Fac-
                                       n die Beziehungen zwischen den Be
    im Weg. Abbildung 4-2 zeigt Ihne                                      f die Erzeugung der
    tory-Method-Patterns und illustri ert noch einmal, wie das Pattern au
         cle-Implementierungen angewa
                                         ndt wurde.
    Vehi

                                                              sell Vehicle-Methode, ruft
          Vehicle-Interface                                   Fabrikmethode auf
                                                              Creator
                         Product


                                                 +FactoryMethod() : Product
                                                 +MethodA()

                                    AbstractManufacturer-                     CarManufacturer und
                                    Klasse                                    ConvertibleManufacturer

                                                          ConcreteCreator
                      ConcreteProduct


                                                     +FactoryMethod() : Product



             Implementierungen des Vehicle-               Fabrikmethode manufactureVehicle
                                                                                             anzen
             Interfaces wie Car, Convertible et
                                                c.        erzeugt Car- bzw. Convertible-Inst

                                     s Factory-Method-Patterns
      Abbildung 4-2: UML-Diagramm de




                                                                                  Das Factory-Method-Pattern | 177
Prototype-Pattern

• Das Prototype-Pattern erzeugt Objekte durch das Kopieren eines
  prototypischen Exemplars


• Es ermöglicht das Hinzufügen neuer "Klassen" zur Laufzeit ohne
  Programmierung


• Es hält die Anzahl der benötigten Klassen klein
Prototype-Pattern

 class SpecialEditionManufacturer {

     protected $prototypes = array();

     public function addSpecialEdition($edition, Vehicle $prototype) {
       $this->prototypes[$edition] = $prototype;
     }

     public function manufactureVehicle($edition) {
       if (!isset($this->prototypes[$edition])) {
         throw new UnknownSpecialEditionException(
           'No prototype for special edition ' . $edition . ' registered');
       }
       return clone $this->prototypes[$edition];
     }

 }
Prototype-Pattern

 class Car implements Vehicle { ... }
 class Convertible implements Vehicle { ... }

 $manufacturer = new SpecialEditionManufacturer();

 $GolfElvis = new Car('VW', 'silber');
 $GolfElvis->setAirConditioned(true);
 $GolfElvis->setGraphics('Gitarre');
 $manufacturer->addSpecialEdition('Golf Elvis Presley Edition', $GolfElvis);

 $GolfStones = new Convertible('VW', 'rot');
 $GolfStones->setAirConditioned(false);
 $GolfStones->setGraphics('Zunge');
 $manufacturer->addSpecialEdition('Golf Rolling Stones Edition', $GolfStones);

 $golf1 = $manufacturer->manufactureVehicle('Golf Elvis Presley Edition');
 $golf2 = $manufacturer->manufactureVehicle('Golf Rolling Stones Edition');
Prototype-Pattern




 Das Prototyp-Muster bestimmt die Arten der zu
 erzeugenden Objekte durch die Verwendung eines
 prototypischen Exemplars, das zur Erzeugung
 neuer Instanzen kopiert wird.
Prototype-Pattern
!!"""#$#"%&'()*+,,-../0120.)!!..3
                                    4012567.8*.95:;54.)!!8..<<='&.<<




                                                                       Vehicle-Interface




                        SpecialEditionManufacturer                                         __clone()-Methode
                        kennt alle verfügbaren                                             in PHP nicht immer nötig
                        Prototypen




                                                                                              rface wie
                                                            Implementierungen des Vehicle-Inte
                                                                       Car, Convertible etc.

                                                       e-Patterns
              Abbildu ng 4-6: UML-Diagramm des Prototyp
                                                                                               plikation
                                                 reduziert die Anzahl der Klassen, die Ihre Ap
              Der Einsatz des Prototype-Patterns                                                ukte zu
                                                  sen bilden müssen, um die einzelnen Prod
              benötigt, da Sie weniger Unterklas                                   en von einer Klasse
              erzeugen. Stattdessen werden al le Produkte auf Basis der Prototyp
Strukturmuster

• Strukturmuster befassen sich mit der Komposition von Objekten


• Zu den Strukturmustern gehöhren unter anderem


  • Composite-Pattern


  • Proxy-Pattern


  • Adapter-Pattern


  • Facade-Pattern
Composite-Pattern

• Lässt mehrere Instanzen eines Typs nach außen wie eine Instanz aussehen


• Implementieren einer neuen Klasse, die die einzelnen Instanzen aufnimmt


• Muss die selbe Schnittstelle implementieren wie die entsprechenden
  Instanzen
Composite-Pattern

 interface Debugger {
   public function debug($message);
 }

 // Implementierungen
 class DebuggerLog implements Debugger {
   public function debug($message) {
     error_log($mssage, 3, 'debug.log');
   }
 }

 class DebuggerMail implements Debugger {
   public function debug($message) {
     mail('schst@php.net', 'Error happened', $message);
   }
 }
Composite-Pattern

 class DebuggerComposite implements Debugger {

     protected $debuggers = array();

     public function addDebugger(Debugger $debugger) {
       $this->debuggers[] = $debugger;
     }

     public function debug($message) {
       foreach ($this->debuggers as $debugger) {
         $debugger->debug($message);
       }
     }

 }

 $debuggerComposite = new DebuggerComposite();
 $debuggerComposite->addDebugger(new DebuggerLog());
 $debuggerComposite->addDebugger(new DebuggerMail());
Composite-Pattern




 Das Composite-Pattern fügt mehrere Objekte zu
 einer Baumstruktur zusammen und ermöglicht es,
 diese von außen wie ein einzelnes zu verwenden.
Composite-Pattern
  !!"""#$#"%&'()*+,,-../0120.)3)..45
                                    012678.9*.:6;<65.)!!9..33='&.33




                                                                                            DebuggerComposite kann
                                           Debugger-Schnittstelle mit                       beliebig viele Debugger
                                           Methode debug()                                  speichern
                                                                      Component


                                                                  +methodA()
                                                                  +methodB()
                         Konkrete Debugger-
                         Implementierungen


                                                                                           Composite
                                        ConcreteComponent

                                                                               +addChild(child : Component)
                                       +methodA()
                                                                               +removeChild(child : Component)
                                       +methodB()
                                                                               +methodA()
                                                                               +methodB()


                                                  DebuggerComposite-Klasse               debug()-Methode delegiert
                                                                                         Aufruf an die anderen Debugger

                                                s Composite-Patterns
                 Abbildung 5-3: UML-Diagramm de


                 Weitere Anwendungen                                                     e Anwendung des
                                                   haben Sie bereits eine sehr beliebt
                  Mit der Debugging-Funktionalität                                                e ähnliche
                                                            etet das PEAR-Paket Log , das ein
                                                                                       2
                  Kompositum-Patterns kenn engelernt. So bi                                               si-
                                                                    llt, auch eine Klasse, die als Kompo
Adapter-Pattern

• Das Adapter-Pattern passt die Schnittstelle eines Objekts an die vom Client
  erwartete Schnittstelle.


• Es erleichtert die Nutzung von Fremdcode in eigenen Systemen.


• Das Adapter-Pattern arbeitet ähnlich wie ein Adapter für Steckdosen.
Adapter-Pattern

 class Automobile {

     const DIRECTION_FORWARD = 0;
     const DIRECTTION_BACKWARD = 1;

     ...

     public function drive($direction, $miles) {
       if ($this->ignited !== true) {
         throw new AutomobileException('Zündung ist nicht an.');
         $this->milesDriven = $this->milesDriven + $miles;
       }
     }

     ...

 }
Adapter-Pattern

 class AutomobileAdapter implements Vehicle {

     protected $automobile;

     public function __construct(Automobile $automobile) {
       $this->automobile = $automobile;
     }

     ...

     public function moveForward($miles) {
       try {
         $this->automobile->drive(Automobile::DIRECTION_FORWARD, $miles);
         return true;
       } catch (AutomobileException $e) {
         return false;
       }

 }
Adapter-Pattern



 Das Adapter-Muster passt die Schnittstelle einer
 Klasse an die vom Client erwartete Schnittstelle
 an. Es ermöglicht die Zusammenarbeit von
 Klassen, die eigentlich aufgrund inkompatibler
 Schnittstellen nicht zusammenarbeiten können.
Sie die Anf
                                                        von Fehlern.
    5. Beachten  Sie Unterschiede beim Signalisieren
                                                                               prungsobjekt zu
                                          ion das Adapter-Objekt, um das Urs
    6. Verwenden Sie in Ihrer Applikat
       ummanteln.
Adapter-Pattern
   Wenn Sie diese einfachen Schritte
                                         Ab
                                           befolgen, adaptieren Sie leicht die
                                                                               verschiedensten
                                             bildung 5-4 zeigt Ihnen noch einmal
                                                                                  die am Adap-
   Schnittstellen in Ihrer Applikation.                                              oblem der
                                          Interfaces und wie das Pattern auf das Pr
   ter-Pattern beteiligten Klassen und                        wandt wurde.
   abweichenden Schn    ittstelle der Automobile-Klasse ange

            Klassen, die das Vehicle-
            Interface nutzen, z.B.                 Vehicle-Interface
            RentalCompany
                    Client                         «interface»
                                                     Target
                                                 +methodA()
                                                                            Automobile-Klasse


                                                                                   Adaptee
                                                     Adapter


                                                                                +methodB()
                                                  +methodA()


                                        AutomobileAdapter
                                                                 Adapter ruft die entsprechenden
                                                                 Methoden auf dem Automobile-
                                                                 Objekt auf

                                    s Ad    apter-Patterns
     Abbildung 5-4: UML-Diagramm de
Verhaltensmuster

• Verhaltensmuster beschreiben die Interaktion zwischen Objekten.


• Zu den Verhaltensmuster gehöhren unter anderem


  • Subject/Observer-Pattern


  • Template-Method-Pattern


  • Command-Pattern


  • Iterator-Pattern
Template-Method-Pattern

• Definiert die Schritte eines Algorithmus in einer Methode


• Implementierung der einzelnen Schritte bleibt Unterklassen vorbehalten


• Gemeinsames Verhalten muss nur einmal implementiert werden: Änderungen
  am Algorithmus nur an einer Stelle notwendig


• Neue Unterklassen müssen nur die konkreten Schritte implementieren
Template-Method-Pattern

 abstract class AbstractCar implements Vehicle {
   ...

     final public function inspect() {
       print "Führe Inspektion durch";
       $this->replaceSparkPlugs();
       $this->checkTires();
       if ($this->isOilLevelLow()) {
         $this->refillOil();
       }
     }

     abstract protected function replaceSparkPlugs();
     abstract protected function checkTires();
     abstract protected function isOilLevelLow();

     protected function refillOil() {
       print "Fülle ". (300 - $this->oilLevel) . "ml Öl nach.n";
       $this->oilLevel = 300;
     }

 }
Template-Method-Pattern

 class Car extends AbstractCar {

     protected function replaceSparkPlugs() {
       print "Ersetze Zündkerzen durch Modell AF34.n";
     }

     protected function checkTires() {
       print "Überprüfe Reifendruck, muss 2,0 bar sein.n";
     }

     protected function isOilLevelLow() {
       if ($this->oilLevel < 200) {
         return true;
       }
       return false;
     }

 }
Template-Method-Pattern



 Das Template-Method-Pattern definiert die
 Schritte eines Algorithmus in einer Methode und
 überlässt die Implementierung der einzelnen
 Schritte den Unterklassen. Diese können somit
 Teile des Algorithmus modifizieren, ohne dessen
 Struktur zu verändern.
Template-Method-Pattern
 !!"""#$#"%&'()*+,,-../0120.)%)..34
                                   012567.8*.95:;54.)!!8..<<='&.<<




                                                                     AbstractCar-Klasse


                                         AbstractClass


                                     +templateMethod()
                                     #primitiveOperation()
                                                                     inspect()-Methode, ruft die
                                                                     abstrakten Methoden auf,
                                                                     die in Unterklassen implementiert
                                                                      werden
                                                                            Car- und Convertible-Klassen
                                          ConcreteClass
                                                                         Implementieren checkTires
                                       #primitiveOperation()             replaceSparkPlugs etc.


                                                        e-Method-Patterns
                Abbildu ng 6-2: UML-Diagramm des Templat
                                                                                 faktorieren und
                                                   es, gemeinsamen Code herauszu
                Schablonenmethoden ermöglichen                      n zu müssen.
                somit gemeinsames Verhalten nur einmal implementiere
Command-Pattern

• Kapselt einen Auftrag als Objekt.


• Aufträge (Objekte) sind parametrisierbar


• Aufträge können in einer Queue nacheinander abgearbeitet werden


• Aufträge können rückgängig gemacht werden.
Command-Pattern

 interface CarWashCommand {
   public function execute(Car $car);
 }

 class CarSimpleWashCommand implements CarWashCommand {
   public function execute(Car $car) {
     echo "Das Auto wird gewaschen";
   }
 }

 class CarDryingCommand implements CarWashCommand {
   public function execute(Car $car) {
     echo "Das Auto wird getrocknet";
   }
 }
Command-Pattern

 class CarWash {

     protected $programmes = array();

     public function addProgramme($name, array $commands) {
       $this->programmes[$name] = $commands;
     }

     public function wash($prog, Car $car) {
       foreach ($this->programmes[$prog] as $command) {
         $command->execute($car);
       }
     }

 }
Command-Pattern

 $wash = new CarWash();

 $wash->addProgramme('standard', array(
   new CarSimpleWashCommand(),
   new CarDryingCommand()
 ));

 $wash->addProgramme('komfort',
   array(
     new CarSimpleWashCommand(),
     new CarEngineWashCommand(),
     new CarDryingCommand(),
     new CarWaxingCommand()
 ));

 $wash->wash('standard', $bmw);
Command-Pattern



Das Command-Pattern kapselt einen Auftrag als
Objekt. Dadurch wird ermöglicht, andere Objekte
mit Aufträgen zu parametrisieren, Aufträge in
eine Queue zu stellen oder diese rückgängig zu
machen.
parametrisieren.
                                                                    t, also das Objekt, das die
     Mit Client ist im aktuell en Beispiel die Waschanlage gemein
                                                                         Warteschlange gestellt
     Befehle verwendet. Dabei müs   sen die Befehle nicht immer in eine
                                                                              denkbar, dass nur
                                           des Command-Patterns ist es auch
     werden. Bei anderen Anwendungen                                                  ausgeführt
                                          i Eint reten einer bestimmten Bedingung
     ein Befehl übergeben wird, der be
Command-Pattern
     wird. Es handelt sich trotzdem   um ein Command-Pattern, da der Au
                                           zeit ausgetauscht werden kann. Ab
                                                                            ftrag in einer Klasse
                                                                               bildung 6-3 zeigt
     gekapselt wird und somit zur Lauf                                 se miteinander in Verbin-
     Ihnen die im Command-Pa     ttern beteiligten Akteure und wie die
     dung stehen.

                                       CarWash, also                CarWashCommand-
                                       die Waschanlage              Interface



                                                                         «interface»
                      Client                  Invoker
                                                                         Command
                                                                     +execute()




                                       Car-Objekte, die gewaschen
                                       werden

                                              Receiver                ConcreteCommand
                                                                      -state
                                                                      +execute()
                                            +action()




                                                                Konkrete Implementierungen
                                                                der Wasch-Befehle, z.B.
                                                                CarMotorWashCommand

                                            Command-Patterns
        Abbildung 6-3: UML-Diagramm des



        290 | Kapitel 6: Verhaltensmuster
Enterprise Patterns

• Kommen aus der Java Welt


• Stark geprägt durch Martin Fowler


• Meistens komplexer als die Gang-of-Four Patterns


  • Deswegen ab hier keine Beispiele mehr


  • Mehr zu Enterprise Patterns in PHP im Buch "PHP Design Patterns"
    http://www.phpdesignpatterns.de
Die Weisheit der Biene



          Nutze bestehende Lösungen.
Abstrahiere Deine konkreten Probleme und wende Design Patterns
als Vorlage für Deine Lösung an.
Die Bulldogge
Die Bulldogge

Perfektionismus wird
P-A-R-A-L-Y-S-E buchstabiert
You Ain‘t Gonna Need It (YAGNI)




 „Always implement things when you actually
 need them, never when you just foresee that you
 need them“
 Ronald E Jeffries
You Ain‘t Gonna Need It (YAGNI)

• Anforderungen sind in der Software-Entwicklung notorisch ungenau oder
  wechselnd


• Ungenaue Anforderungen werden oft durch möglichst flexible und
  funktionsfähige Software kompensiert


• Es werden Features entwickelt die keine Anwendung finden


• Dinge die niemand braucht, haben keinen Wert.
Do the simplest thing that could possibly work.

• YAGNI kann als Ergänzung des XP-Prinzips "Do the simplest thing that could
  possibly work." verstanden werden


• Wann ist ein Design am einfachsten?


  • Es verkörpert die Absicht des Entwicklers und besteht alle Tests.


  • Es enthält kein Duplizierungen.


  • Es enthält das Minimum an Klassen und Methoden
Emergenz




„Emergenz ist die spontane Herausbildung von
komplexen Systemen und Strukturen durch eine
Vielzahl von relativ einfachen Interaktionen.“
Wikipedia
Saubere Software durch emergentes Design

• Alle Tests bestehen


  • Software muss in erster Linie den gewollten Zweck erfüllen.


     • Software, die nicht testbar ist, kann nicht verifiziert werden.


  • Klassen die dem Single Responsibility Prinzip folgen sind leichter zu
    testen.


     • Je mehr Tests wir schreiben, desto mehr bemühen wir uns Code zu
       schreiben, der einfacher zu testen ist.
Saubere Software durch emergentes Design

• Alle Tests bestehen


  • Eine starke Kopplung erschwert das Schreiben von Tests


     • Je mehr Tests wir schreiben, desto mehr bemühen wir uns, die
       Kopplung zu minimieren
Saubere Software durch emergentes Design

• Refactoring nach dem Bestehen eines Tests


  • Duplizierten Code eliminieren


  • Ausdrucksstärke des Codes verbessern


  • Anzahl der Klassen und Methoden minimieren


• Tests sichern das bisherige Ergebnis ab
Vorsicht: Perfekt ist der Feind von "Gut genug"

• Entwickler tendieren dazu Lösungen danach zu analysieren wie elegant und
  optimal sie für die Problemstellung sind.


• Software Entwicklung ist kein Schönheitswettbewerb


• Der Code ist klar, ausdrucksstark, gut dokumentiert und getestet. Geht es
  noch besser?


  • Klar. Aber es er ist gut genug.


  • Verschwende keine Zeit auf der Suche nach dem perfekten Design
Permature Optimization




 „Premature optimization is the root of all evil“
 Donald Knuth
Permature Optimization

• Premature Optimization beschreibt die Situation in der Design
  Entscheidungen aufgrund von Performance-Optimierungen getroffen werden


• Solche Optimierungen resultieren oft in unleserlicherem Code


• M. A. Jackson über Optimierung


  • Dont't do it.


  • (For experts only) - Don't do it yet
Premature Optimization

• Was wenn Performance-Optimierung unumgänglich ist?


   • Anwendung & Design entwickeln


   • Profiler / Benchmarks einsetzen


   • Flaschenhälse identifizieren


• Ein einfaches und elegantes Design ist oft leichter zu optimieren
Die Weisheit der Bulldogge



   Mit kleinen Schritten zum großen Ziel.
Mach es nicht perfekt, mach es gut genug.
Je länger Entscheidungen aufgeschoben werden,
desto mehr Wissen hat man darüber
Der Regenwurm
Der Regenwurm

Vermeide Accidential Complexity.
Vermeide Accidential Complexity




 „Simplify essential complexity; diminish
 accidental complexity“
 Neal Ford
Essential Complexity

• "Essential Complexity" ist die Komplexität, die dem eigentlichen Problem
  innewohnt


• Am besten mit "notwendige Komplexität" übersetzt


• Die Komplexität ist durch das Business getrieben und kann nicht ignoriert
  werden
Accidential Complexity

• "Accidential Complexity" ist die Komplexität. die durch die technische Lösung
  hinzugefügt wird, mit der Absicht, die notwendige Komplexität zu
  kontrollieren


• Häufiges Problem von eingekauften Lösungen und generischen Frameworks


• Entwickler werden von Komplexität angezogen


• Entwickler wollen komplexe Probleme lösen und lösen damit oft Probleme,
  die die Lösung erst eingeführt hat
Accidential Complexity
Accidential Complexity

• JPA


• Rules Engine


 Stateful Webservices
 Java Persistence API
Aspect Oriented Programming
• Aspect Oriented Programming


   MultiRules Engine
        Module Build
• komplexes Build System


• Stateful Webservices
Vermeide Accidential Complexity

• Verwende Frameworks, die aus
  produktivem Code entstanden sind.


• Extrahiere Frameworks aus
  bestehendem Code.


• Prüfe, wie viel Prozent des Codes das
  tatsächlich vorhandene Problem
  adressiert


• Triff keine Entscheidungen aus dem
  Elfenbeinturm.
Die Weisheit des Regenwurms



       Fokussiere Dich auf das Problem.
Implementiere Lösungen, die Probleme der Domäne lösen, ohne
unnötige Komplexität einzuführen.
Der Kugelfisch
Der Kugelfisch

Teste, teste, teste.
Unit Tests




 „Im Unit Test werden kleinere Programmteile in
 Isolation von anderen Programmteilen getestet.“
 Frank Westphal
Unit Tests

• Testen eine einzelne Codeeinheit isoliert.


   • Die Granularität der Codeeinheit kann von Methoden über Klassen bis hin
     zu Komponenten reichen.


• Unit Test-Frameworks für PHP


   • PHPUnit - JUnit Portierung für PHP von Sebastian Bergmann


   • SimpleTest - von Marcus Baker
Unit Tests

 require_once 'RentalCompany.php';

 class RentalCompanyTest extends PHPUnit_Framework_TestCase {

     protected $rentalCompany;

     protected function setUp() {
       $this->rentalCompany = new RentalCompany();
     }

     public function testAddToFleet() {
       $this->rentalCompany->addToFleet(new Car('VW', 'silber'));
       $carCount = $this->rentalCompany->countCarsInFleet();
       $this->assertEquals(1, $carCount);
     }

 }
Unit Tests



 $ phpunit RentalCompanyTest
 PHPUnit 3.4.2 by Sebastian Bergmann.

 .

 Time: 0 seconds

 OK (1 test, 1 assertion)
Integrationstests


 „There is a vast gulf between the process mappers
 who model business systems pictorially, and the
 programmers who grind out the C++ or Java
 or .Net services that support those business
 systems. Between the two camps lies a fertile land
 of opportunity. It's time to jointly explore it.“
 Ward Cunningham
FIT - Framework for Integrated Tests

• Framework für Integrations- und Akzeptanz-Tests


• Der Kunde schreibt die Testfälle in HTML, Word oder Excel


• Bezieht den Kunden in den Entwicklungsprozess ein und fördert agiles
  Vorgehen


• Mittlerweile für sehr viele Sprachen verfügbar, für PHP innerhalb von PEAR
Funktionsweise

• Kunde erstellt eine Tabelle mit Eingabe-Parametern und erwarteten
  Rückgabe-Werten


• FIT parst die HTML-Tabelle und interpretiert diese als Testfälle


• FIT reicht die Eingabeparameter an den Testcode (Fixture) weiter


• Der Testcode führt den zu testenden Code aus


• FIT holt die das Ergebnis aus dem Testcode


• FIT markiert Abweichungen in der HTML-Tabelle
Funktionsweise
Webtests mit Selenium

• Dem Kunden sind Unit-Tests egal, wenn die Website nicht funktioniert


• Selenium prüft die Anwendung auf der Ebene, die der Kunde sieht


• Steuert den Browser fern und prüft gegen das erwartete Verhalten


• Funktioniert in allen großen Browsern, auch im IE6


• Tests können über Firefox-Extension aufgezeichnet werden


• Selenium RC ermöglicht Fernsteuerung aus PHPUnit Tests
Selenium in Bildern
Selenium in Bildern
Continuous Integration

• Beschreibt den Prozess des regelmäßigen, vollständigen Builds und Testens
  einer Anwendung


• Vorteile durch den Einsatz von CI


   • Integrations-Probleme werden frühzeitig entdeckt


   • Fehler werden nicht verschleppt


   • Code Qualität ist über den gesamten Entwicklungsprozess sichtbar
Continuous Integration

      SVN Repository     CI Server
phpUnderControl
Mehr Tools
Die Weisheit des Kugelfischs



                Better safe than sorry.
Schaffe dir Sicherheitsnetze durch automatisierte Tests auf
verschiedenen Ebenen deiner Applikation.
Integriere regelmäßig und stelle Fehler
frühzeitig fest.
Der Waschbär
Der Waschbär

Halte deinen Code sauber.
Coding Standards

• Legen fest, wie lang eine Zeile sein darf, wie eingerückt wird, wo geklammert
  wird, wo Leerzeichen stehen, wann Großbuchstaben oder Kleinbuchstaben
  verwendet werden, wie eine Funktionsdefinition aussehen soll, wie eine
  Klassendefinition aussehen soll, wie eine Methodendefinition aussehen soll,
  wie und wo Includes verwendet werden sollen, und, und, und, …


• Haben religiöse Sprengkraft


• Sorgen dafür, dass der Code für alle Entwickler lesbar bleibt


• Entwickler haben dadurch Zeit, sich auf das Wesentliche zu fokussieren
Coding Standards in PHP

• PHP_CodeSniffer kann Code gegen verschiedene Regeln prüfen


• Liefert bereits Regelsets mit, ist jedoch erweiterbar (hört auf die Schildkröte)

 $ phpcs --standard=pear badClass.php
 FILE: /var/www/phpcodesniffer/badClass.php
 --------------------------------------------------------------------------------
 FOUND 5 ERROR(S) AND 0 WARNING(S) AFFECTING 3 LINE(S)
 --------------------------------------------------------------------------------
  2 | ERROR | Missing file doc comment
  3 | ERROR | Class name must begin with a capital letter
  5 | ERROR | Line indented incorrectly; expected at least 4 spaces, found 1
  5 | ERROR | Spaces must be used to indent lines; tabs are not allowed
  5 | ERROR | Class constants must be uppercase; expected MYCONSTANT but found
    |       | MyConstant
 --------------------------------------------------------------------------------
Verwende Name die ihre Absicht aufdecken

• Namen von Variablen, Funktionen oder Klassen, sollten folgende Fragen
  beantworten:


  • Warum existiert die Variable (Funktion oder Klasse)?


  • Was macht sie?


  • Wie wird sie verwendet?


  • $d = 1; // elapsed time in days
    $elapsedTimeInDays = 1;
Benennung

• Verwende aussprechbare Namen


• Verwende ein Wort pro Konzept (z.B. fetch, retrieve oder get)


• Vermeide "Nerd Names" in Klassennamen


   • ...Helper, ...Manager oder ...Util


   • http://www.classnamer.com/
Benennung
Benennung
Benennung
Kommentare

• Gute Kommentare                    • Schlechte Kommentare


  • @todo-Kommentare                    • Redundante Kommentare


  • Informative Kommentare              • Postionsmarkierungen


  • PHPDocs in öffentlichen APIs        • Auskommentierter Code




        Kommentare sind keine Ausrede für schlechten Code.
DRY - Don‘t Repeat Yourself




 „Every piece of knowlege must have a single,
 unambiguous, authoritative representation
 within a system“
 Andrew Hunt and Dave Thomas
DRY - Don‘t Repeat Yourself

• Nichts ist einfacher als Copy & Paste


• „Nummer Eins der Gestanksparade“ in Refactoring von Martin Fowler


• Jede Doppelung von Code leistet Inkonsistenzen und Fehlern Vorschub.
Fehlerhandling

• Verwende Exceptions


• Reichere deine Exceptions mit sinnvollen Informationen an.


• Definieren Exception-Klassen nach den Bedürfnissen der aufrufenden
  Systeme.


• Verwende Exceptions nicht als billige Alternative für goto.


• Gib niemals null zurück.
Die Pfadfinder-Regel




 „Leave the campground cleaner than you found it“
 Robert C. Martin (Clean Code)
Die Pfadfinder-Regel

• „Don‘t live with Broken Windows“


  • Fixe schlechte Designs, falsche Entscheidungen und schlechten Code
    sobald du ihn siehst


• Es muss nichts großes sein


  • Ändere den Namen einer Variable in einen besseren
    Breche eine Funktion auf, die zu groß ist
    Eliminiere ein kleine Duplizierung


• Software muss dauerhaft sauber gehalten werden
Die Weisheit des Waschbärs



Dreckiger Code führt zu dreckigem Design.
Lass auch bei Detail-Fragen die gleiche Sorgfalt walten wie bei
großen Design-Entscheidungen.
Die Ente
Die Ente
Das Ende.
Die Leseratte
Die Leseratte
Die Leseratte
Die Leseratte
Die Leseratte
Die Leseratte
Die Leseratte
Die Leseratte
Die Leseratte
Die Leseratte
Die Leseratte
Die Leseratte
Die Leseratte
Die Leseratte
Die Leseratte
Fragen?
Fragen?
Vielen Dank für die Aufmerksamkeit.
Fragen?
Vielen Dank für die Aufmerksamkeit.




Bildquellen © iStockphoto.com

Kontakt
holger.rueprich@1und1.de
stephan.schmidt@1und1.de

Mais conteúdo relacionado

Semelhante a Die Kunst Des Software Design

PHP-SEO Vortrag SEOCampixx 2013 von Sebastian Blum
PHP-SEO Vortrag SEOCampixx 2013 von Sebastian BlumPHP-SEO Vortrag SEOCampixx 2013 von Sebastian Blum
PHP-SEO Vortrag SEOCampixx 2013 von Sebastian BlumSebastian Blum
 
Shortcodes erstellen mit WordPress
Shortcodes erstellen mit WordPressShortcodes erstellen mit WordPress
Shortcodes erstellen mit WordPressTorsten Landsiedel
 
IPC 2015 Zend Framework 3 Reloaded
IPC 2015 Zend Framework 3 ReloadedIPC 2015 Zend Framework 3 Reloaded
IPC 2015 Zend Framework 3 ReloadedRalf Eggert
 
Modern angular 02_angular_mit_type_script
Modern angular 02_angular_mit_type_scriptModern angular 02_angular_mit_type_script
Modern angular 02_angular_mit_type_scriptManfred Steyer
 
Praesentation TYPO3Camp Berlin Speed mit Extbase
Praesentation TYPO3Camp Berlin Speed mit ExtbasePraesentation TYPO3Camp Berlin Speed mit Extbase
Praesentation TYPO3Camp Berlin Speed mit ExtbaseStefan Frömken
 
Prototype 1.7
Prototype 1.7Prototype 1.7
Prototype 1.7msebel
 
Migrationspfade für Angular 2
Migrationspfade für Angular 2Migrationspfade für Angular 2
Migrationspfade für Angular 2Manfred Steyer
 
Datenbankoptimierung für Ruby on Rails
Datenbankoptimierung für Ruby on RailsDatenbankoptimierung für Ruby on Rails
Datenbankoptimierung für Ruby on RailsKarsten Meier
 
WordPress Plugins und Themes übersetzbar machen - WP Camp 2012 Berlin
WordPress Plugins und Themes übersetzbar machen - WP Camp 2012 BerlinWordPress Plugins und Themes übersetzbar machen - WP Camp 2012 Berlin
WordPress Plugins und Themes übersetzbar machen - WP Camp 2012 BerlinDavid Decker
 
Grails 0.3-SNAPSHOT Presentation WJAX 2006
Grails 0.3-SNAPSHOT Presentation WJAX 2006Grails 0.3-SNAPSHOT Presentation WJAX 2006
Grails 0.3-SNAPSHOT Presentation WJAX 2006Sven Haiges
 
Apache CouchDB at PHPUG Karlsruhe, Germany (Jan 27th 2009)
Apache CouchDB at PHPUG Karlsruhe, Germany (Jan 27th 2009)Apache CouchDB at PHPUG Karlsruhe, Germany (Jan 27th 2009)
Apache CouchDB at PHPUG Karlsruhe, Germany (Jan 27th 2009)Nils Adermann
 
Powerful mostly unknown Javascript-Features
Powerful mostly unknown Javascript-FeaturesPowerful mostly unknown Javascript-Features
Powerful mostly unknown Javascript-FeaturesSascha Hameister
 
Ist Gradle auch für die APEX-Projekte?
Ist Gradle auch für die APEX-Projekte?Ist Gradle auch für die APEX-Projekte?
Ist Gradle auch für die APEX-Projekte?MT AG
 
Request Lifecycle im Zend Framework
Request Lifecycle im Zend FrameworkRequest Lifecycle im Zend Framework
Request Lifecycle im Zend FrameworkMayflower GmbH
 
SOLID Prinzipien, Designgrundlagen objektorientierter Systeme
SOLID Prinzipien, Designgrundlagen objektorientierter SystemeSOLID Prinzipien, Designgrundlagen objektorientierter Systeme
SOLID Prinzipien, Designgrundlagen objektorientierter SystemeMario Rodler
 

Semelhante a Die Kunst Des Software Design (20)

PHP-SEO Vortrag SEOCampixx 2013 von Sebastian Blum
PHP-SEO Vortrag SEOCampixx 2013 von Sebastian BlumPHP-SEO Vortrag SEOCampixx 2013 von Sebastian Blum
PHP-SEO Vortrag SEOCampixx 2013 von Sebastian Blum
 
Shortcodes erstellen mit WordPress
Shortcodes erstellen mit WordPressShortcodes erstellen mit WordPress
Shortcodes erstellen mit WordPress
 
T3ak12 extbase
T3ak12 extbaseT3ak12 extbase
T3ak12 extbase
 
IPC 2015 Zend Framework 3 Reloaded
IPC 2015 Zend Framework 3 ReloadedIPC 2015 Zend Framework 3 Reloaded
IPC 2015 Zend Framework 3 Reloaded
 
Modern angular 02_angular_mit_type_script
Modern angular 02_angular_mit_type_scriptModern angular 02_angular_mit_type_script
Modern angular 02_angular_mit_type_script
 
Praesentation TYPO3Camp Berlin Speed mit Extbase
Praesentation TYPO3Camp Berlin Speed mit ExtbasePraesentation TYPO3Camp Berlin Speed mit Extbase
Praesentation TYPO3Camp Berlin Speed mit Extbase
 
Prototype 1.7
Prototype 1.7Prototype 1.7
Prototype 1.7
 
Migrationspfade für Angular 2
Migrationspfade für Angular 2Migrationspfade für Angular 2
Migrationspfade für Angular 2
 
Datenbankoptimierung für Ruby on Rails
Datenbankoptimierung für Ruby on RailsDatenbankoptimierung für Ruby on Rails
Datenbankoptimierung für Ruby on Rails
 
WordPress Plugins und Themes übersetzbar machen - WP Camp 2012 Berlin
WordPress Plugins und Themes übersetzbar machen - WP Camp 2012 BerlinWordPress Plugins und Themes übersetzbar machen - WP Camp 2012 Berlin
WordPress Plugins und Themes übersetzbar machen - WP Camp 2012 Berlin
 
Ruby on Rails SS09 03
Ruby on Rails SS09 03Ruby on Rails SS09 03
Ruby on Rails SS09 03
 
Grails 0.3-SNAPSHOT Presentation WJAX 2006
Grails 0.3-SNAPSHOT Presentation WJAX 2006Grails 0.3-SNAPSHOT Presentation WJAX 2006
Grails 0.3-SNAPSHOT Presentation WJAX 2006
 
Apache CouchDB at PHPUG Karlsruhe, Germany (Jan 27th 2009)
Apache CouchDB at PHPUG Karlsruhe, Germany (Jan 27th 2009)Apache CouchDB at PHPUG Karlsruhe, Germany (Jan 27th 2009)
Apache CouchDB at PHPUG Karlsruhe, Germany (Jan 27th 2009)
 
Mut zur Fachlichkeit
Mut zur FachlichkeitMut zur Fachlichkeit
Mut zur Fachlichkeit
 
FLOW3-Workshop F3X12
FLOW3-Workshop F3X12FLOW3-Workshop F3X12
FLOW3-Workshop F3X12
 
Powerful mostly unknown Javascript-Features
Powerful mostly unknown Javascript-FeaturesPowerful mostly unknown Javascript-Features
Powerful mostly unknown Javascript-Features
 
GWT: Eintauchen in MVP und Internationalisierung
GWT: Eintauchen in MVP und InternationalisierungGWT: Eintauchen in MVP und Internationalisierung
GWT: Eintauchen in MVP und Internationalisierung
 
Ist Gradle auch für die APEX-Projekte?
Ist Gradle auch für die APEX-Projekte?Ist Gradle auch für die APEX-Projekte?
Ist Gradle auch für die APEX-Projekte?
 
Request Lifecycle im Zend Framework
Request Lifecycle im Zend FrameworkRequest Lifecycle im Zend Framework
Request Lifecycle im Zend Framework
 
SOLID Prinzipien, Designgrundlagen objektorientierter Systeme
SOLID Prinzipien, Designgrundlagen objektorientierter SystemeSOLID Prinzipien, Designgrundlagen objektorientierter Systeme
SOLID Prinzipien, Designgrundlagen objektorientierter Systeme
 

Mais de Stephan Schmidt

Das Web Wird Mobil - Geolocation und Location Based Services
Das Web Wird Mobil - Geolocation und Location Based ServicesDas Web Wird Mobil - Geolocation und Location Based Services
Das Web Wird Mobil - Geolocation und Location Based ServicesStephan Schmidt
 
23 Dinge, die Sie über Software Entwicklung in Teams wissen sollten
23 Dinge, die Sie über Software Entwicklung in Teams wissen sollten23 Dinge, die Sie über Software Entwicklung in Teams wissen sollten
23 Dinge, die Sie über Software Entwicklung in Teams wissen solltenStephan Schmidt
 
23 Dinge, die Sie über Software-Entwicklung in Teams wissen sollten
23 Dinge, die Sie über Software-Entwicklung in Teams wissen sollten23 Dinge, die Sie über Software-Entwicklung in Teams wissen sollten
23 Dinge, die Sie über Software-Entwicklung in Teams wissen solltenStephan Schmidt
 
Continuous Integration mit Jenkins
Continuous Integration mit JenkinsContinuous Integration mit Jenkins
Continuous Integration mit JenkinsStephan Schmidt
 
Der Erfolgreiche Programmierer
Der Erfolgreiche ProgrammiererDer Erfolgreiche Programmierer
Der Erfolgreiche ProgrammiererStephan Schmidt
 
23 Dinge, die Sie über Software-Entwicklung in Teams wissen sollten.
23 Dinge, die Sie über Software-Entwicklung in Teams wissen sollten.23 Dinge, die Sie über Software-Entwicklung in Teams wissen sollten.
23 Dinge, die Sie über Software-Entwicklung in Teams wissen sollten.Stephan Schmidt
 
Software-Entwicklung Im Team
Software-Entwicklung Im TeamSoftware-Entwicklung Im Team
Software-Entwicklung Im TeamStephan Schmidt
 
JSON-RPC Proxy Generation with PHP 5
JSON-RPC Proxy Generation with PHP 5JSON-RPC Proxy Generation with PHP 5
JSON-RPC Proxy Generation with PHP 5Stephan Schmidt
 
Declarative Development Using Annotations In PHP
Declarative Development Using Annotations In PHPDeclarative Development Using Annotations In PHP
Declarative Development Using Annotations In PHPStephan Schmidt
 
XML and Web Services with PHP5 and PEAR
XML and Web Services with PHP5 and PEARXML and Web Services with PHP5 and PEAR
XML and Web Services with PHP5 and PEARStephan Schmidt
 
The Big Documentation Extravaganza
The Big Documentation ExtravaganzaThe Big Documentation Extravaganza
The Big Documentation ExtravaganzaStephan Schmidt
 
Go OO! - Real-life Design Patterns in PHP 5
Go OO! - Real-life Design Patterns in PHP 5Go OO! - Real-life Design Patterns in PHP 5
Go OO! - Real-life Design Patterns in PHP 5Stephan Schmidt
 
Component and Event-Driven Architectures in PHP
Component and Event-Driven Architectures in PHPComponent and Event-Driven Architectures in PHP
Component and Event-Driven Architectures in PHPStephan Schmidt
 
Session Server - Maintaing State between several Servers
Session Server - Maintaing State between several ServersSession Server - Maintaing State between several Servers
Session Server - Maintaing State between several ServersStephan Schmidt
 
XML Transformations With PHP
XML Transformations With PHPXML Transformations With PHP
XML Transformations With PHPStephan Schmidt
 
Inroduction to XSLT with PHP4
Inroduction to XSLT with PHP4Inroduction to XSLT with PHP4
Inroduction to XSLT with PHP4Stephan Schmidt
 
XML-Socket-Server zur Kommunikation mit Flash
XML-Socket-Server zur Kommunikation mit FlashXML-Socket-Server zur Kommunikation mit Flash
XML-Socket-Server zur Kommunikation mit FlashStephan Schmidt
 
Interprozesskommunikation mit PHP
Interprozesskommunikation mit PHPInterprozesskommunikation mit PHP
Interprozesskommunikation mit PHPStephan Schmidt
 

Mais de Stephan Schmidt (20)

Das Web Wird Mobil - Geolocation und Location Based Services
Das Web Wird Mobil - Geolocation und Location Based ServicesDas Web Wird Mobil - Geolocation und Location Based Services
Das Web Wird Mobil - Geolocation und Location Based Services
 
23 Dinge, die Sie über Software Entwicklung in Teams wissen sollten
23 Dinge, die Sie über Software Entwicklung in Teams wissen sollten23 Dinge, die Sie über Software Entwicklung in Teams wissen sollten
23 Dinge, die Sie über Software Entwicklung in Teams wissen sollten
 
23 Dinge, die Sie über Software-Entwicklung in Teams wissen sollten
23 Dinge, die Sie über Software-Entwicklung in Teams wissen sollten23 Dinge, die Sie über Software-Entwicklung in Teams wissen sollten
23 Dinge, die Sie über Software-Entwicklung in Teams wissen sollten
 
Continuous Integration mit Jenkins
Continuous Integration mit JenkinsContinuous Integration mit Jenkins
Continuous Integration mit Jenkins
 
Der Erfolgreiche Programmierer
Der Erfolgreiche ProgrammiererDer Erfolgreiche Programmierer
Der Erfolgreiche Programmierer
 
23 Dinge, die Sie über Software-Entwicklung in Teams wissen sollten.
23 Dinge, die Sie über Software-Entwicklung in Teams wissen sollten.23 Dinge, die Sie über Software-Entwicklung in Teams wissen sollten.
23 Dinge, die Sie über Software-Entwicklung in Teams wissen sollten.
 
Software-Entwicklung Im Team
Software-Entwicklung Im TeamSoftware-Entwicklung Im Team
Software-Entwicklung Im Team
 
JSON-RPC Proxy Generation with PHP 5
JSON-RPC Proxy Generation with PHP 5JSON-RPC Proxy Generation with PHP 5
JSON-RPC Proxy Generation with PHP 5
 
Declarative Development Using Annotations In PHP
Declarative Development Using Annotations In PHPDeclarative Development Using Annotations In PHP
Declarative Development Using Annotations In PHP
 
XML and Web Services with PHP5 and PEAR
XML and Web Services with PHP5 and PEARXML and Web Services with PHP5 and PEAR
XML and Web Services with PHP5 and PEAR
 
The Big Documentation Extravaganza
The Big Documentation ExtravaganzaThe Big Documentation Extravaganza
The Big Documentation Extravaganza
 
Go OO! - Real-life Design Patterns in PHP 5
Go OO! - Real-life Design Patterns in PHP 5Go OO! - Real-life Design Patterns in PHP 5
Go OO! - Real-life Design Patterns in PHP 5
 
Component and Event-Driven Architectures in PHP
Component and Event-Driven Architectures in PHPComponent and Event-Driven Architectures in PHP
Component and Event-Driven Architectures in PHP
 
Session Server - Maintaing State between several Servers
Session Server - Maintaing State between several ServersSession Server - Maintaing State between several Servers
Session Server - Maintaing State between several Servers
 
XML Transformations With PHP
XML Transformations With PHPXML Transformations With PHP
XML Transformations With PHP
 
PEAR For The Masses
PEAR For The MassesPEAR For The Masses
PEAR For The Masses
 
Inroduction to XSLT with PHP4
Inroduction to XSLT with PHP4Inroduction to XSLT with PHP4
Inroduction to XSLT with PHP4
 
XML-Socket-Server zur Kommunikation mit Flash
XML-Socket-Server zur Kommunikation mit FlashXML-Socket-Server zur Kommunikation mit Flash
XML-Socket-Server zur Kommunikation mit Flash
 
Interprozesskommunikation mit PHP
Interprozesskommunikation mit PHPInterprozesskommunikation mit PHP
Interprozesskommunikation mit PHP
 
PHP im High End
PHP im High EndPHP im High End
PHP im High End
 

Die Kunst Des Software Design

  • 1.
  • 2. Die Kunst des Software-Design oder was Software-Entwickler von der Tierwelt lernen können PHP World Kongress 2009 Holger Rüprich und Stephan Schmidt
  • 3. Holger Rüprich • Head of Sales Processes Consumer bei der 1&1 Internet AG • Clean Code Enthusiast • Gast-Dozent an der Berufs- Akademie Mosbach • Autor für die Zeitschrift T3N
  • 4. Stephan Schmidt • Head of Web Sales Development bei der 1&1 Internet AG • Design Patterns Enthusiast • Autor von PHP Design Patterns sowie anderen Büchern und über 30 Fachartikeln • Redner auf internationalen Konferenzen
  • 5. Software Design „Software Design is a process of problem solving and planning for a software solution.“ Wikipedia
  • 6. Kunst „Das Wort Kunst bezeichnet im weitesten Sinne jede entwickelte Tätigkeit, die auf Wissen, Übung, Wahrnehmung, Vorstellung und Intuition gegründet ist.“ Wikipedia
  • 8. Ziele von Software Design Software soll stabil sein.
  • 10. Ziele von Software Design Software soll sicher sein.
  • 12. Ziele von Software Design Software soll flexibel sein.
  • 14. Ziele von Software Design Software soll performant sein.
  • 17. Das Eichhörnchen Kapsle Daten und Algorithmen.
  • 18. Von der realen Welt ... • Bob hat eine Autovermietung • Er muss Autos einkaufen • Er vermietet unterschiedliche Modelle • Er vermietet Autos zu verschiedenen Preisen
  • 19. ... zur programmierten Welt • Klassen übertragen Dinge aus der realen Welt in die programmierte Welt class Car { protected $manufacturer; protected $color; protected $milage; protected $engineStarted = false; public function startEngine() {} public function driveForward($miles) {} public function stopEngine() {} public function getManufacturer() {} public function getColor() {} public function getMilage() {} }
  • 20. Kapsle den Zugriff auf Daten Kapsle den Zugriff auf Daten immer innerhalb einer Klasse und biete Methoden an, um diese Daten abzufragen. class Car { ... Eigenschaften und Methoden ... public function getDailyRate($days = 1) { return 75.5; } }
  • 21. Kapsle den Zugriff auf Daten Kapsle den Zugriff auf Daten immer innerhalb einer Klasse und biete Methoden an, um diese Daten abzufragen. class Car { ... Eigenschaften und Methoden ... public function getDailyRate($days = 1) { if ($days >= 7) { return 65.9; } return 75.5; } }
  • 22. Bobs Kunden class Customer { protected $id; protected $name; public function __construct($id, $name) { $this->id = $id; $this->name = $name; } public function getId() { return $this->id; } public function getName() { return $this->name; } }
  • 23. Bobs Firma class RentalCompany { protected $fleet = array(); public function addToFleet($id, Car $car) { $this->fleet[$id] = $vehicle; } public function rentCar(Car $car, Customer $customer) {} public function returnCar(Car $car) {} }
  • 24. Bobs Geschäft • Klassen übertragen nicht nur physikalische Dinge, sondern auch Abläufe class RentalAction { ... Eigenschaften ... public function __construct(Car $car, Customer $customer, $date = null) { if ($date === null) { $date = date('Y-m-d H:i:s'); } $this->car = $car; $this->customer = $customer; $this->rentDate = $date; } ... Getter ... }
  • 25. Bobs Geschäft • Klassen übertragen nicht nur physikalische Dinge, sondern auch Abläufe class RentalAction { ... public function markCarReturned($date = null) { if ($date === null) { $date = date('Y-m-d H:i:s'); } $this->returnDate = $date; } public function isReturned() { return $this->returnDate !== null; } }
  • 26. Kapsle auch Algorithmen Kapsle nicht nur Daten sondern auch Algorithmen in den Methoden deiner Klassen, um komplexe Operationen zentral an einer Stelle zu implementieren.
  • 27. Bobs Firma class RentalCompany { ... public function rentCar(Car $car, Customer $customer) { $carId = array_search($car, $this->fleet); if ($carId === false) { throw new UnknownCarException(); } if (!$this->isCarAvailable($car)) { throw new CarNotAvailableException(); } $rentalAction = new RentalAction($car, $customer); $this->rentalActions[] = $rentalAction; return $rentalAction; } }
  • 28. Bobs Firma class RentalCompany { ... public function isCarAvailable(Car $car) { foreach ($this->rentalActions as $rentalAction) { if ($rentalAction->getCar() !== $car) { continue; } if ($rentalAction->isReturned()) { continue; } return false; } return true; } }
  • 29. Bobs Firma class RentalCompany { ... public function returnCar(Car $car) { foreach ($this->rentalActions as $rentalAction) { if ($rentalAction->getCar() !== $car) { continue; } if ($rentalAction->isReturned()) { continue; } $rentalAction->markCarReturned(); return true; } return false; } }
  • 30. Die Weisheit des Eichhörnchens Schütze deine Daten. Verberge Implementierungsdetails und unterbinde den Zugriff auf interne Datenstrukturen. Wähle Klassen- und Methodennamen sinnvoll und achte darauf, dass der resultierende Code sich wie ein Satz lesen lässt.
  • 32. Das Krokodil Achte das Single-Reponsibility-Prinzip.
  • 33. Das Single-Responsibility-Prinzip „There should never be more than one reason for a class to change“ Robert C. Martin
  • 34. Bob will wissen was los ist class RentalCompany { public function addToFleet($id, Vehicle $vehicle) { $this->fleet[$id] = $vehicle; print "Neues Auto im Fuhrpark: " . $vehicle->getManufacturer() . "n"; } public function rentVehicle(Vehicle $vehicle, Customer $customer) { ... print "Neuer Mietvorgang: " . $customer->getName() . " leiht " . $vehicle->getManufacturer() . "n"; return $rentalAction; } ... } > Neues Auto im Fuhrpark: BMW > Neuer Mietvorgang: Stephan Schmidt leiht BMW > Rückgabe: Stephan Schmidt gibt BMW zurück > Neuer Mietvorgang: Gerd Schaufelberger leiht BMW
  • 35. Bob will wissen was los ist class RentalCompany { public function addToFleet($id, Vehicle $vehicle) { $this->fleet[$id] = $vehicle; print "Neues Auto im Fuhrpark: " . $vehicle->getManufacturer() . "n"; } Was ist mit Problemen im Produktivbetrieb? public function rentVehicle(Vehicle $vehicle, Customer $customer) { ... print "Neuer Mietvorgang: " . $customer->getName() . " leiht " . $vehicle->getManufacturer() . "n"; return $rentalAction; } ... } > Neues Auto im Fuhrpark: BMW > Neuer Mietvorgang: Stephan Schmidt leiht BMW > Rückgabe: Stephan Schmidt gibt BMW zurück > Neuer Mietvorgang: Gerd Schaufelberger leiht BMW
  • 36. Debugging im Produktivbetrieb class RentalCompany { public function addToFleet($id, Vehicle $vehicle) { $this->fleet[$id] = $vehicle; switch (DEBUG_MODE) { case 'echo': print "Neues Auto im Fuhrpark: " . $vehicle->getManufacturer() . "n"; break; case 'log': error_log("Neues Auto im Fuhrpark: " . $vehicle->getManufacturer() . "n", 3, '.RentalCompany.log'); break; } } public function rentVehicle(Vehicle $vehicle, Customer $customer) { ... switch (DEBUG_MODE) { case 'echo': print "Neuer Mietvorgang: " . $customer->getName() . " leiht " . $vehicle->getManufacturer() . "n"; break; ... return $rentalAction; }
  • 37. Debugging im Produktivbetrieb class RentalCompany { public function addToFleet($id, Vehicle $vehicle) { $this->fleet[$id] = $vehicle; switch (DEBUG_MODE) { case 'echo': print "Neues Auto im Fuhrpark: " . $vehicle->getManufacturer() . "n"; break; case 'log': error_log("Neues Auto im Fuhrpark: " . $vehicle->getManufacturer() . "n", Code Duplizierung macht die Anwendung 3, '.RentalCompany.log'); break; langsamer und schwerer zu warten } } public function rentVehicle(Vehicle $vehicle, Customer $customer) { ... switch (DEBUG_MODE) { case 'echo': print "Neuer Mietvorgang: " . $customer->getName() . " leiht " . $vehicle->getManufacturer() . "n"; break; ... return $rentalAction; }
  • 38. Wiederverwendbarkeit statt Copy-and-Paste class RentalCompany { public function addToFleet($id, Vehicle $vehicle) { $this->fleet[$id] = $vehicle; $this->debug("Neues Auto im Fuhrpark: " . $vehicle->getManufacturer()); } public function rentVehicle(Vehicle $vehicle, Customer $customer) { ... $this->debug("Neuer Mietvorgang: " . $customer->getName() . " leiht " . $vehicle->getManufacturer()); return $rentalAction; } ... }
  • 39. Wiederverwendbarkeit statt Copy-and-Paste class RentalCompany { ... protected function debug($message) { switch (DEBUG_MODE) { case 'echo': print "{$message}n"; break; case 'log': error_log("{$message}n", 3, './RentalCompany.log'); break; } } }
  • 40. Wiederverwendbarkeit statt Copy-and-Paste class RentalCompany { ... Weitere Debugging-Ziele, wie E-Mails oder SMS, protected function debug($message) { switch (DEBUG_MODE) { machen die debug()-Methode komplexer case 'echo': print "{$message}n"; break; case 'log':und somit fehleranfälliger. error_log("{$message}n", 3, './RentalCompany.log'); break; } } }
  • 41. Atomare Probleme lösen abstract class RentalCompany { ... Eigenschaften und Methoden der Klasse ... abstract protected function debug($message); } class EchoingRentalCompany extends RentalCompany { protected function debug($message) { echo "{$message}n"; } } class LoggingRentalCompany extends RentalCompany { protected function debug($message) { error_log("{$message}n", 3, './RentalCompany.log'); } }
  • 42. Atomare Probleme lösen switch (DEBUG_MODE) { case 'echo': $company = new EchoingRentalCompany(); break; case 'log': $company = new LoggingRentalCompany(); break; } $bmw = new Car('BMW', 'blau'); $stephan = new Customer(1, 'Stephan Schmidt'); $gerd = new Customer(2, 'Gerd Schaufelberger'); $company->addToFleet('bmw1', $bmw); $company->rentVehicle($bmw, $stephan); $company->returnVehicle($bmw);
  • 43. Atomare Probleme lösen switch (DEBUG_MODE) { case 'echo': $company = new EchoingRentalCompany(); break; case 'log': Die debug()-Methode steht nur Unterklassen von $company = new LoggingRentalCompany(); break; } RentalCompany zur Verfügung. $bmw = new Car('BMW', 'blau'); $stephan = new Customer(1, 'Stephan Schmidt'); $gerd = new Customer(2, 'Gerd Schaufelberger'); $company->addToFleet('bmw1', $bmw); $company->rentVehicle($bmw, $stephan); $company->returnVehicle($bmw);
  • 44. Komposition statt Vererbung interface Debugger { public function debug($message); } class DebuggerEcho { public function debug($message) { echo "{$message}n"; } } class DebuggerLog { public function debug($message) { error_log("{$message}n", 3, './RentalCompany.log'); } }
  • 45. Komposition statt Vererbung class RentalCompany { ... Eigenschaften der Klasse ... protected $debugger; public function __construct() { switch (DEBUG_MODE) { case 'echo': $this->debugger = new DebuggerEcho(); break; case 'log': $this->debugger = new DebuggerLog(); break; } } public function debug($message) { $this->debugger->debug($message); } }
  • 46. Die Weisheit des Krokodils Teile und herrsche. Jedes Modul soll genau eine Verantwortung übernehmen, und jede Verantwortung soll genau einem Modul zugeordnet werden.
  • 48. Die Schildkröte Achte das Open-Closed-Prinzip.
  • 49. Das Open-Closed-Prinzip „Software entities (classes, modules, functions, etc.) should be open for extension, but closed for modification.“ Bertrand Meyer
  • 50. Komposition statt Vererbung class RentalCompany { ... Eigenschaften der Klasse ... protected $debugger; public function __construct() { switch (DEBUG_MODE) { case 'echo': $this->debugger = new DebuggerEcho(); break; case 'log': $this->debugger = new DebuggerLog(); break; } } public function debug($message) { $this->debugger->debug($message); } }
  • 51. Komposition statt Vererbung class RentalCompany { ... Eigenschaften der Klasse ... protected $debugger; public function __construct() { switch (DEBUG_MODE) { Die RentalCompany Klassen ist von case 'echo': $this->debugger = new DebuggerEcho(); break; case 'log': anderen Klassen abhängig $this->debugger = new DebuggerLog(); break; } } public function debug($message) { $this->debugger->debug($message); } }
  • 52. Einsatz von Interfaces class RentalCompany { ... Eigenschaften der Klasse ... public function __construct(Debugger $debugger) { $this->debugger = $debugger; } ... weitere Methoden der Klasse ... } $debugger = new DebuggerEcho(); $company = new RentalCompany($debugger);
  • 53. Die Weisheit der Schildkröte Schütze deinen Code. Programmiere immer gegen Schnittstellen, nie gegen eine konkrete Implementierung. Vermeide feste Abhängigkeiten zwischen einzelnen Klassen deiner Anwendungen und ziehe immer lose Kopplung der Klassen vor.
  • 55. Der Erpel Achte das Hollywood-Prinzip.
  • 56. Das Hollywood Prinzip „Rufen Sie uns nicht an, wir werden Sie anrufen.“ Das Hollywood Prinzip
  • 57. Das Hollywood Prinzip • Auch bekannt als „Inversion of Control“ • Objekte sollen sich ihre Abhängigkeiten nicht selbst holen oder erzeugen • Objekte sollen unabhängig von ihrer Umgebung sein
  • 58. Dependency Injection • Objekte erstellen abhängige Objekte nicht selbst • Abhängige Objekte werden von außen über den Konstruktor (Constructor Injection) oder über Setter-Methoden (Setter Injection) injiziert • Abhängige Objekte sind dadurch sehr leicht austauschbar
  • 59. Dependency Injection $debugger = new DebuggerEcho(); $company = new RentalCompany($debugger); Constructor Injection $logger = new DateTimeLogger(); $company->setLogger($logger); Setter Injection • RentalCompany weiß weder, welche Implementierung des Debugger-Interface noch welche Implementierung des Logger-Interface sie verwendet • RentalCompany steuert nicht, wie sie an ihre Abhängigkeiten kommt, der Kontrollfluss wird von außerhalb gesteuert • Aber: Sehr viel zusätzlicher Client Code, durch Instanziieren und Injizieren der Objekte nötig
  • 60. Inversion-of-Control-Container • In der Java-Welt schon weit verbreitet • Spring, Google Guice, Tapestry IoC, ... • In PHP noch nicht weit verbreitet • Stubbles, Garden, XJConf for PHP
  • 61. Stubbles IoC Container • Portierung von Google Guice (Java) • Entwickelt als Teil des Stubble Frameworks • Kann auch außerhalb der Frameworks verwendet werden • Basiert auf Type Hints und Annotations • Keine native Unterstützung durch PHP • Annotations als Teil der PHP-Doc-Kommentare
  • 62. Rufen Sie Bob nicht an, Bob ruft sie an. class RentalCompany { ... Eigenschaften der Klasse ... /** * @Inject Constructor Injection */ public function __construc(Debugger $debugger) { $this->debugger = $debugger; } /** * @Inject Setter Injection */ public function setLogger(Logger $logger) { $this->logger = $logger; } ... }
  • 63. Interfaces binden • Typen werden durch Binder an konkrete Implementierungen gebunden: $binder = new stubBinder(); $binder->bind('Debugger')->to('DebuggerEcho'); $binder->bind('Logger')->to('DateTimeLogger'); • Binder kann Injector liefern, der Instanzen erzeugt: $injector = $binder->getInjector(); $company = $injector->getInstance('RentalCompany');
  • 64. Fortgeschrittene Techniken • Verwenden einer Standardimplementierung /** * @ImplementedBy(DateTimeLogger.class) */ interface Logger { • Mehrere Implementierungen für ein Interface /** * @Inject * @Named("Debugger") public function setLogger(Logger $logger) $binder = new stubBinder(); $binder->bind('Logger')->to('DateTimeLogger'); $binder->bind('Logger')->named('Debugger')->to('SimpleLogger');
  • 65. Die Weisheit des Erpel Verwende ein DI Framework. Erleichtere dir das Verwalten von komplexen Objektstrukturen durch den Einsatz eines Dependency Injection Frameworks.
  • 68. Konkretes Problem „Ich möchte Debug-Meldungen auf verschiedene Arten verarbeiten und diese auswechseln können, ohne den Code der RentalCompany Klasse anpassen zu müssen.“ Bob
  • 69. Abstraktes Problem „Ich möchte eine Aufgabe mit verschiedenen Algorithmen lösen können. Jede der Lösungen soll gekapselt sein und nichts von den anderen wissen. Die einzelnen Lösungen sollen gegeneinander austauschbar sein, ohne den nutzenden Client anzupassen.“ Abstract Bob
  • 70. Konkret vs Abstrakt Abstrakt Konkret Verarbeiten von Debug- Aufgabe Meldungen Ausgeben per print(), Algorithmen Schreiben eines Logfiles Die Klasse Client RentalCompany
  • 71. Konkret vs Abstrakt Abstrakt Konkret Persistieren von Aufgabe Gästebucheinträgen Speichern in Datenbank, Algorithmen Speichern in XML-Datei Client Die Klasse Guestbook
  • 72. Bobs erstes Design Pattern Strategy-Pattern
  • 73. Design Patterns • Lösungsmuster für häufig auftretende Entwurfsaufgaben in der Software- Entwicklung • Keine Code-Bibliothek • Organisiert in Pattern-Katalogen (z.B. Gang-of-Four Buch) • Verschiedene Kategorien: Erzeugungsmuster, Strukturmuster, Verhaltensmuster, Enterprise-Patterns
  • 74. Erzeugungsmuster • Erzeugungsmuster werden verwendet, um Objekte zu konstruieren. • Zu den Erzeugungsmustern gehöhren unter anderem • Singleton-Pattern • Factory-Method-Pattern • Prototype-Pattern • Abstract-Factory-Pattern
  • 75. Factory-Method-Pattern • Definiert eine Schnittstelle zur Erzeugung von Objekten • Verlagert die eigentliche Instanziierung in Unterklassen • Lässt Unterklassen entscheiden, welche konkrete Implementierung verwendet wird
  • 76. Factory-Method-Pattern abstract class AbstractManufacturer { protected $name; public function __construct($name) { $this->name = $name; } public function sellVehicle() { $vehicle = $this->manufactureVehicle(); // weitere Operationen möglich return $vehicle; } public abstract function manufactureVehicle(); }
  • 77. Factory-Method-Pattern class CarManufacturer extends AbstractManufacturer { public function manufactureVehicle() { return new Car($this->name); } } $bmwManufacturer = new CarManufacturer('BMW'); $bmw = $bmwManufacturer->sellVehicle();
  • 78. Factory-Method-Pattern Das Factory-Method-Pattern definiert eine Schnittstelle zur Erzeugung von Objekten. Es verlagert aber die eigentliche Instanziierung in Unterklassen; es lässt die Unterklassen entscheiden, welche konkreten Implementierungen verwendet werden.
  • 79. der abstrak lichen Objekte zu 4. Verwenden Sie nun diese konk reten Unterklassen, um die tatsäch ementierungen zu instanziieren und Ihren Applik ationscode von den konkreten Impl lösen. fach darauf, die verwenden möchten, achten Sie ein Factory-Method-Pattern Wann immer Sie eine Fabrikmetho de hier gezeigten Schritte durchzuführe n, und dem Erfolg Ihres Vorhabens steht nichts mehr teiligten des Fac- n die Beziehungen zwischen den Be im Weg. Abbildung 4-2 zeigt Ihne f die Erzeugung der tory-Method-Patterns und illustri ert noch einmal, wie das Pattern au cle-Implementierungen angewa ndt wurde. Vehi sell Vehicle-Methode, ruft Vehicle-Interface Fabrikmethode auf Creator Product +FactoryMethod() : Product +MethodA() AbstractManufacturer- CarManufacturer und Klasse ConvertibleManufacturer ConcreteCreator ConcreteProduct +FactoryMethod() : Product Implementierungen des Vehicle- Fabrikmethode manufactureVehicle anzen Interfaces wie Car, Convertible et c. erzeugt Car- bzw. Convertible-Inst s Factory-Method-Patterns Abbildung 4-2: UML-Diagramm de Das Factory-Method-Pattern | 177
  • 80. Prototype-Pattern • Das Prototype-Pattern erzeugt Objekte durch das Kopieren eines prototypischen Exemplars • Es ermöglicht das Hinzufügen neuer "Klassen" zur Laufzeit ohne Programmierung • Es hält die Anzahl der benötigten Klassen klein
  • 81. Prototype-Pattern class SpecialEditionManufacturer { protected $prototypes = array(); public function addSpecialEdition($edition, Vehicle $prototype) { $this->prototypes[$edition] = $prototype; } public function manufactureVehicle($edition) { if (!isset($this->prototypes[$edition])) { throw new UnknownSpecialEditionException( 'No prototype for special edition ' . $edition . ' registered'); } return clone $this->prototypes[$edition]; } }
  • 82. Prototype-Pattern class Car implements Vehicle { ... } class Convertible implements Vehicle { ... } $manufacturer = new SpecialEditionManufacturer(); $GolfElvis = new Car('VW', 'silber'); $GolfElvis->setAirConditioned(true); $GolfElvis->setGraphics('Gitarre'); $manufacturer->addSpecialEdition('Golf Elvis Presley Edition', $GolfElvis); $GolfStones = new Convertible('VW', 'rot'); $GolfStones->setAirConditioned(false); $GolfStones->setGraphics('Zunge'); $manufacturer->addSpecialEdition('Golf Rolling Stones Edition', $GolfStones); $golf1 = $manufacturer->manufactureVehicle('Golf Elvis Presley Edition'); $golf2 = $manufacturer->manufactureVehicle('Golf Rolling Stones Edition');
  • 83. Prototype-Pattern Das Prototyp-Muster bestimmt die Arten der zu erzeugenden Objekte durch die Verwendung eines prototypischen Exemplars, das zur Erzeugung neuer Instanzen kopiert wird.
  • 84. Prototype-Pattern !!"""#$#"%&'()*+,,-../0120.)!!..3 4012567.8*.95:;54.)!!8..<<='&.<< Vehicle-Interface SpecialEditionManufacturer __clone()-Methode kennt alle verfügbaren in PHP nicht immer nötig Prototypen rface wie Implementierungen des Vehicle-Inte Car, Convertible etc. e-Patterns Abbildu ng 4-6: UML-Diagramm des Prototyp plikation reduziert die Anzahl der Klassen, die Ihre Ap Der Einsatz des Prototype-Patterns ukte zu sen bilden müssen, um die einzelnen Prod benötigt, da Sie weniger Unterklas en von einer Klasse erzeugen. Stattdessen werden al le Produkte auf Basis der Prototyp
  • 85. Strukturmuster • Strukturmuster befassen sich mit der Komposition von Objekten • Zu den Strukturmustern gehöhren unter anderem • Composite-Pattern • Proxy-Pattern • Adapter-Pattern • Facade-Pattern
  • 86. Composite-Pattern • Lässt mehrere Instanzen eines Typs nach außen wie eine Instanz aussehen • Implementieren einer neuen Klasse, die die einzelnen Instanzen aufnimmt • Muss die selbe Schnittstelle implementieren wie die entsprechenden Instanzen
  • 87. Composite-Pattern interface Debugger { public function debug($message); } // Implementierungen class DebuggerLog implements Debugger { public function debug($message) { error_log($mssage, 3, 'debug.log'); } } class DebuggerMail implements Debugger { public function debug($message) { mail('schst@php.net', 'Error happened', $message); } }
  • 88. Composite-Pattern class DebuggerComposite implements Debugger { protected $debuggers = array(); public function addDebugger(Debugger $debugger) { $this->debuggers[] = $debugger; } public function debug($message) { foreach ($this->debuggers as $debugger) { $debugger->debug($message); } } } $debuggerComposite = new DebuggerComposite(); $debuggerComposite->addDebugger(new DebuggerLog()); $debuggerComposite->addDebugger(new DebuggerMail());
  • 89. Composite-Pattern Das Composite-Pattern fügt mehrere Objekte zu einer Baumstruktur zusammen und ermöglicht es, diese von außen wie ein einzelnes zu verwenden.
  • 90. Composite-Pattern !!"""#$#"%&'()*+,,-../0120.)3)..45 012678.9*.:6;<65.)!!9..33='&.33 DebuggerComposite kann Debugger-Schnittstelle mit beliebig viele Debugger Methode debug() speichern Component +methodA() +methodB() Konkrete Debugger- Implementierungen Composite ConcreteComponent +addChild(child : Component) +methodA() +removeChild(child : Component) +methodB() +methodA() +methodB() DebuggerComposite-Klasse debug()-Methode delegiert Aufruf an die anderen Debugger s Composite-Patterns Abbildung 5-3: UML-Diagramm de Weitere Anwendungen e Anwendung des haben Sie bereits eine sehr beliebt Mit der Debugging-Funktionalität e ähnliche etet das PEAR-Paket Log , das ein 2 Kompositum-Patterns kenn engelernt. So bi si- llt, auch eine Klasse, die als Kompo
  • 91. Adapter-Pattern • Das Adapter-Pattern passt die Schnittstelle eines Objekts an die vom Client erwartete Schnittstelle. • Es erleichtert die Nutzung von Fremdcode in eigenen Systemen. • Das Adapter-Pattern arbeitet ähnlich wie ein Adapter für Steckdosen.
  • 92. Adapter-Pattern class Automobile { const DIRECTION_FORWARD = 0; const DIRECTTION_BACKWARD = 1; ... public function drive($direction, $miles) { if ($this->ignited !== true) { throw new AutomobileException('Zündung ist nicht an.'); $this->milesDriven = $this->milesDriven + $miles; } } ... }
  • 93. Adapter-Pattern class AutomobileAdapter implements Vehicle { protected $automobile; public function __construct(Automobile $automobile) { $this->automobile = $automobile; } ... public function moveForward($miles) { try { $this->automobile->drive(Automobile::DIRECTION_FORWARD, $miles); return true; } catch (AutomobileException $e) { return false; } }
  • 94. Adapter-Pattern Das Adapter-Muster passt die Schnittstelle einer Klasse an die vom Client erwartete Schnittstelle an. Es ermöglicht die Zusammenarbeit von Klassen, die eigentlich aufgrund inkompatibler Schnittstellen nicht zusammenarbeiten können.
  • 95. Sie die Anf von Fehlern. 5. Beachten Sie Unterschiede beim Signalisieren prungsobjekt zu ion das Adapter-Objekt, um das Urs 6. Verwenden Sie in Ihrer Applikat ummanteln. Adapter-Pattern Wenn Sie diese einfachen Schritte Ab befolgen, adaptieren Sie leicht die verschiedensten bildung 5-4 zeigt Ihnen noch einmal die am Adap- Schnittstellen in Ihrer Applikation. oblem der Interfaces und wie das Pattern auf das Pr ter-Pattern beteiligten Klassen und wandt wurde. abweichenden Schn ittstelle der Automobile-Klasse ange Klassen, die das Vehicle- Interface nutzen, z.B. Vehicle-Interface RentalCompany Client «interface» Target +methodA() Automobile-Klasse Adaptee Adapter +methodB() +methodA() AutomobileAdapter Adapter ruft die entsprechenden Methoden auf dem Automobile- Objekt auf s Ad apter-Patterns Abbildung 5-4: UML-Diagramm de
  • 96. Verhaltensmuster • Verhaltensmuster beschreiben die Interaktion zwischen Objekten. • Zu den Verhaltensmuster gehöhren unter anderem • Subject/Observer-Pattern • Template-Method-Pattern • Command-Pattern • Iterator-Pattern
  • 97. Template-Method-Pattern • Definiert die Schritte eines Algorithmus in einer Methode • Implementierung der einzelnen Schritte bleibt Unterklassen vorbehalten • Gemeinsames Verhalten muss nur einmal implementiert werden: Änderungen am Algorithmus nur an einer Stelle notwendig • Neue Unterklassen müssen nur die konkreten Schritte implementieren
  • 98. Template-Method-Pattern abstract class AbstractCar implements Vehicle { ... final public function inspect() { print "Führe Inspektion durch"; $this->replaceSparkPlugs(); $this->checkTires(); if ($this->isOilLevelLow()) { $this->refillOil(); } } abstract protected function replaceSparkPlugs(); abstract protected function checkTires(); abstract protected function isOilLevelLow(); protected function refillOil() { print "Fülle ". (300 - $this->oilLevel) . "ml Öl nach.n"; $this->oilLevel = 300; } }
  • 99. Template-Method-Pattern class Car extends AbstractCar { protected function replaceSparkPlugs() { print "Ersetze Zündkerzen durch Modell AF34.n"; } protected function checkTires() { print "Überprüfe Reifendruck, muss 2,0 bar sein.n"; } protected function isOilLevelLow() { if ($this->oilLevel < 200) { return true; } return false; } }
  • 100. Template-Method-Pattern Das Template-Method-Pattern definiert die Schritte eines Algorithmus in einer Methode und überlässt die Implementierung der einzelnen Schritte den Unterklassen. Diese können somit Teile des Algorithmus modifizieren, ohne dessen Struktur zu verändern.
  • 101. Template-Method-Pattern !!"""#$#"%&'()*+,,-../0120.)%)..34 012567.8*.95:;54.)!!8..<<='&.<< AbstractCar-Klasse AbstractClass +templateMethod() #primitiveOperation() inspect()-Methode, ruft die abstrakten Methoden auf, die in Unterklassen implementiert werden Car- und Convertible-Klassen ConcreteClass Implementieren checkTires #primitiveOperation() replaceSparkPlugs etc. e-Method-Patterns Abbildu ng 6-2: UML-Diagramm des Templat faktorieren und es, gemeinsamen Code herauszu Schablonenmethoden ermöglichen n zu müssen. somit gemeinsames Verhalten nur einmal implementiere
  • 102. Command-Pattern • Kapselt einen Auftrag als Objekt. • Aufträge (Objekte) sind parametrisierbar • Aufträge können in einer Queue nacheinander abgearbeitet werden • Aufträge können rückgängig gemacht werden.
  • 103. Command-Pattern interface CarWashCommand { public function execute(Car $car); } class CarSimpleWashCommand implements CarWashCommand { public function execute(Car $car) { echo "Das Auto wird gewaschen"; } } class CarDryingCommand implements CarWashCommand { public function execute(Car $car) { echo "Das Auto wird getrocknet"; } }
  • 104. Command-Pattern class CarWash { protected $programmes = array(); public function addProgramme($name, array $commands) { $this->programmes[$name] = $commands; } public function wash($prog, Car $car) { foreach ($this->programmes[$prog] as $command) { $command->execute($car); } } }
  • 105. Command-Pattern $wash = new CarWash(); $wash->addProgramme('standard', array( new CarSimpleWashCommand(), new CarDryingCommand() )); $wash->addProgramme('komfort', array( new CarSimpleWashCommand(), new CarEngineWashCommand(), new CarDryingCommand(), new CarWaxingCommand() )); $wash->wash('standard', $bmw);
  • 106. Command-Pattern Das Command-Pattern kapselt einen Auftrag als Objekt. Dadurch wird ermöglicht, andere Objekte mit Aufträgen zu parametrisieren, Aufträge in eine Queue zu stellen oder diese rückgängig zu machen.
  • 107. parametrisieren. t, also das Objekt, das die Mit Client ist im aktuell en Beispiel die Waschanlage gemein Warteschlange gestellt Befehle verwendet. Dabei müs sen die Befehle nicht immer in eine denkbar, dass nur des Command-Patterns ist es auch werden. Bei anderen Anwendungen ausgeführt i Eint reten einer bestimmten Bedingung ein Befehl übergeben wird, der be Command-Pattern wird. Es handelt sich trotzdem um ein Command-Pattern, da der Au zeit ausgetauscht werden kann. Ab ftrag in einer Klasse bildung 6-3 zeigt gekapselt wird und somit zur Lauf se miteinander in Verbin- Ihnen die im Command-Pa ttern beteiligten Akteure und wie die dung stehen. CarWash, also CarWashCommand- die Waschanlage Interface «interface» Client Invoker Command +execute() Car-Objekte, die gewaschen werden Receiver ConcreteCommand -state +execute() +action() Konkrete Implementierungen der Wasch-Befehle, z.B. CarMotorWashCommand Command-Patterns Abbildung 6-3: UML-Diagramm des 290 | Kapitel 6: Verhaltensmuster
  • 108. Enterprise Patterns • Kommen aus der Java Welt • Stark geprägt durch Martin Fowler • Meistens komplexer als die Gang-of-Four Patterns • Deswegen ab hier keine Beispiele mehr • Mehr zu Enterprise Patterns in PHP im Buch "PHP Design Patterns" http://www.phpdesignpatterns.de
  • 109. Die Weisheit der Biene Nutze bestehende Lösungen. Abstrahiere Deine konkreten Probleme und wende Design Patterns als Vorlage für Deine Lösung an.
  • 112. You Ain‘t Gonna Need It (YAGNI) „Always implement things when you actually need them, never when you just foresee that you need them“ Ronald E Jeffries
  • 113. You Ain‘t Gonna Need It (YAGNI) • Anforderungen sind in der Software-Entwicklung notorisch ungenau oder wechselnd • Ungenaue Anforderungen werden oft durch möglichst flexible und funktionsfähige Software kompensiert • Es werden Features entwickelt die keine Anwendung finden • Dinge die niemand braucht, haben keinen Wert.
  • 114. Do the simplest thing that could possibly work. • YAGNI kann als Ergänzung des XP-Prinzips "Do the simplest thing that could possibly work." verstanden werden • Wann ist ein Design am einfachsten? • Es verkörpert die Absicht des Entwicklers und besteht alle Tests. • Es enthält kein Duplizierungen. • Es enthält das Minimum an Klassen und Methoden
  • 115. Emergenz „Emergenz ist die spontane Herausbildung von komplexen Systemen und Strukturen durch eine Vielzahl von relativ einfachen Interaktionen.“ Wikipedia
  • 116. Saubere Software durch emergentes Design • Alle Tests bestehen • Software muss in erster Linie den gewollten Zweck erfüllen. • Software, die nicht testbar ist, kann nicht verifiziert werden. • Klassen die dem Single Responsibility Prinzip folgen sind leichter zu testen. • Je mehr Tests wir schreiben, desto mehr bemühen wir uns Code zu schreiben, der einfacher zu testen ist.
  • 117. Saubere Software durch emergentes Design • Alle Tests bestehen • Eine starke Kopplung erschwert das Schreiben von Tests • Je mehr Tests wir schreiben, desto mehr bemühen wir uns, die Kopplung zu minimieren
  • 118. Saubere Software durch emergentes Design • Refactoring nach dem Bestehen eines Tests • Duplizierten Code eliminieren • Ausdrucksstärke des Codes verbessern • Anzahl der Klassen und Methoden minimieren • Tests sichern das bisherige Ergebnis ab
  • 119. Vorsicht: Perfekt ist der Feind von "Gut genug" • Entwickler tendieren dazu Lösungen danach zu analysieren wie elegant und optimal sie für die Problemstellung sind. • Software Entwicklung ist kein Schönheitswettbewerb • Der Code ist klar, ausdrucksstark, gut dokumentiert und getestet. Geht es noch besser? • Klar. Aber es er ist gut genug. • Verschwende keine Zeit auf der Suche nach dem perfekten Design
  • 120. Permature Optimization „Premature optimization is the root of all evil“ Donald Knuth
  • 121. Permature Optimization • Premature Optimization beschreibt die Situation in der Design Entscheidungen aufgrund von Performance-Optimierungen getroffen werden • Solche Optimierungen resultieren oft in unleserlicherem Code • M. A. Jackson über Optimierung • Dont't do it. • (For experts only) - Don't do it yet
  • 122. Premature Optimization • Was wenn Performance-Optimierung unumgänglich ist? • Anwendung & Design entwickeln • Profiler / Benchmarks einsetzen • Flaschenhälse identifizieren • Ein einfaches und elegantes Design ist oft leichter zu optimieren
  • 123. Die Weisheit der Bulldogge Mit kleinen Schritten zum großen Ziel. Mach es nicht perfekt, mach es gut genug. Je länger Entscheidungen aufgeschoben werden, desto mehr Wissen hat man darüber
  • 126. Vermeide Accidential Complexity „Simplify essential complexity; diminish accidental complexity“ Neal Ford
  • 127. Essential Complexity • "Essential Complexity" ist die Komplexität, die dem eigentlichen Problem innewohnt • Am besten mit "notwendige Komplexität" übersetzt • Die Komplexität ist durch das Business getrieben und kann nicht ignoriert werden
  • 128. Accidential Complexity • "Accidential Complexity" ist die Komplexität. die durch die technische Lösung hinzugefügt wird, mit der Absicht, die notwendige Komplexität zu kontrollieren • Häufiges Problem von eingekauften Lösungen und generischen Frameworks • Entwickler werden von Komplexität angezogen • Entwickler wollen komplexe Probleme lösen und lösen damit oft Probleme, die die Lösung erst eingeführt hat
  • 130. Accidential Complexity • JPA • Rules Engine Stateful Webservices Java Persistence API Aspect Oriented Programming • Aspect Oriented Programming MultiRules Engine Module Build • komplexes Build System • Stateful Webservices
  • 131. Vermeide Accidential Complexity • Verwende Frameworks, die aus produktivem Code entstanden sind. • Extrahiere Frameworks aus bestehendem Code. • Prüfe, wie viel Prozent des Codes das tatsächlich vorhandene Problem adressiert • Triff keine Entscheidungen aus dem Elfenbeinturm.
  • 132. Die Weisheit des Regenwurms Fokussiere Dich auf das Problem. Implementiere Lösungen, die Probleme der Domäne lösen, ohne unnötige Komplexität einzuführen.
  • 135. Unit Tests „Im Unit Test werden kleinere Programmteile in Isolation von anderen Programmteilen getestet.“ Frank Westphal
  • 136. Unit Tests • Testen eine einzelne Codeeinheit isoliert. • Die Granularität der Codeeinheit kann von Methoden über Klassen bis hin zu Komponenten reichen. • Unit Test-Frameworks für PHP • PHPUnit - JUnit Portierung für PHP von Sebastian Bergmann • SimpleTest - von Marcus Baker
  • 137. Unit Tests require_once 'RentalCompany.php'; class RentalCompanyTest extends PHPUnit_Framework_TestCase { protected $rentalCompany; protected function setUp() { $this->rentalCompany = new RentalCompany(); } public function testAddToFleet() { $this->rentalCompany->addToFleet(new Car('VW', 'silber')); $carCount = $this->rentalCompany->countCarsInFleet(); $this->assertEquals(1, $carCount); } }
  • 138. Unit Tests $ phpunit RentalCompanyTest PHPUnit 3.4.2 by Sebastian Bergmann. . Time: 0 seconds OK (1 test, 1 assertion)
  • 139. Integrationstests „There is a vast gulf between the process mappers who model business systems pictorially, and the programmers who grind out the C++ or Java or .Net services that support those business systems. Between the two camps lies a fertile land of opportunity. It's time to jointly explore it.“ Ward Cunningham
  • 140. FIT - Framework for Integrated Tests • Framework für Integrations- und Akzeptanz-Tests • Der Kunde schreibt die Testfälle in HTML, Word oder Excel • Bezieht den Kunden in den Entwicklungsprozess ein und fördert agiles Vorgehen • Mittlerweile für sehr viele Sprachen verfügbar, für PHP innerhalb von PEAR
  • 141. Funktionsweise • Kunde erstellt eine Tabelle mit Eingabe-Parametern und erwarteten Rückgabe-Werten • FIT parst die HTML-Tabelle und interpretiert diese als Testfälle • FIT reicht die Eingabeparameter an den Testcode (Fixture) weiter • Der Testcode führt den zu testenden Code aus • FIT holt die das Ergebnis aus dem Testcode • FIT markiert Abweichungen in der HTML-Tabelle
  • 143. Webtests mit Selenium • Dem Kunden sind Unit-Tests egal, wenn die Website nicht funktioniert • Selenium prüft die Anwendung auf der Ebene, die der Kunde sieht • Steuert den Browser fern und prüft gegen das erwartete Verhalten • Funktioniert in allen großen Browsern, auch im IE6 • Tests können über Firefox-Extension aufgezeichnet werden • Selenium RC ermöglicht Fernsteuerung aus PHPUnit Tests
  • 146. Continuous Integration • Beschreibt den Prozess des regelmäßigen, vollständigen Builds und Testens einer Anwendung • Vorteile durch den Einsatz von CI • Integrations-Probleme werden frühzeitig entdeckt • Fehler werden nicht verschleppt • Code Qualität ist über den gesamten Entwicklungsprozess sichtbar
  • 147. Continuous Integration SVN Repository CI Server
  • 150. Die Weisheit des Kugelfischs Better safe than sorry. Schaffe dir Sicherheitsnetze durch automatisierte Tests auf verschiedenen Ebenen deiner Applikation. Integriere regelmäßig und stelle Fehler frühzeitig fest.
  • 152. Der Waschbär Halte deinen Code sauber.
  • 153. Coding Standards • Legen fest, wie lang eine Zeile sein darf, wie eingerückt wird, wo geklammert wird, wo Leerzeichen stehen, wann Großbuchstaben oder Kleinbuchstaben verwendet werden, wie eine Funktionsdefinition aussehen soll, wie eine Klassendefinition aussehen soll, wie eine Methodendefinition aussehen soll, wie und wo Includes verwendet werden sollen, und, und, und, … • Haben religiöse Sprengkraft • Sorgen dafür, dass der Code für alle Entwickler lesbar bleibt • Entwickler haben dadurch Zeit, sich auf das Wesentliche zu fokussieren
  • 154. Coding Standards in PHP • PHP_CodeSniffer kann Code gegen verschiedene Regeln prüfen • Liefert bereits Regelsets mit, ist jedoch erweiterbar (hört auf die Schildkröte) $ phpcs --standard=pear badClass.php FILE: /var/www/phpcodesniffer/badClass.php -------------------------------------------------------------------------------- FOUND 5 ERROR(S) AND 0 WARNING(S) AFFECTING 3 LINE(S) -------------------------------------------------------------------------------- 2 | ERROR | Missing file doc comment 3 | ERROR | Class name must begin with a capital letter 5 | ERROR | Line indented incorrectly; expected at least 4 spaces, found 1 5 | ERROR | Spaces must be used to indent lines; tabs are not allowed 5 | ERROR | Class constants must be uppercase; expected MYCONSTANT but found | | MyConstant --------------------------------------------------------------------------------
  • 155. Verwende Name die ihre Absicht aufdecken • Namen von Variablen, Funktionen oder Klassen, sollten folgende Fragen beantworten: • Warum existiert die Variable (Funktion oder Klasse)? • Was macht sie? • Wie wird sie verwendet? • $d = 1; // elapsed time in days $elapsedTimeInDays = 1;
  • 156. Benennung • Verwende aussprechbare Namen • Verwende ein Wort pro Konzept (z.B. fetch, retrieve oder get) • Vermeide "Nerd Names" in Klassennamen • ...Helper, ...Manager oder ...Util • http://www.classnamer.com/
  • 160. Kommentare • Gute Kommentare • Schlechte Kommentare • @todo-Kommentare • Redundante Kommentare • Informative Kommentare • Postionsmarkierungen • PHPDocs in öffentlichen APIs • Auskommentierter Code Kommentare sind keine Ausrede für schlechten Code.
  • 161. DRY - Don‘t Repeat Yourself „Every piece of knowlege must have a single, unambiguous, authoritative representation within a system“ Andrew Hunt and Dave Thomas
  • 162. DRY - Don‘t Repeat Yourself • Nichts ist einfacher als Copy & Paste • „Nummer Eins der Gestanksparade“ in Refactoring von Martin Fowler • Jede Doppelung von Code leistet Inkonsistenzen und Fehlern Vorschub.
  • 163. Fehlerhandling • Verwende Exceptions • Reichere deine Exceptions mit sinnvollen Informationen an. • Definieren Exception-Klassen nach den Bedürfnissen der aufrufenden Systeme. • Verwende Exceptions nicht als billige Alternative für goto. • Gib niemals null zurück.
  • 164. Die Pfadfinder-Regel „Leave the campground cleaner than you found it“ Robert C. Martin (Clean Code)
  • 165. Die Pfadfinder-Regel • „Don‘t live with Broken Windows“ • Fixe schlechte Designs, falsche Entscheidungen und schlechten Code sobald du ihn siehst • Es muss nichts großes sein • Ändere den Namen einer Variable in einen besseren Breche eine Funktion auf, die zu groß ist Eliminiere ein kleine Duplizierung • Software muss dauerhaft sauber gehalten werden
  • 166. Die Weisheit des Waschbärs Dreckiger Code führt zu dreckigem Design. Lass auch bei Detail-Fragen die gleiche Sorgfalt walten wie bei großen Design-Entscheidungen.
  • 185. Fragen? Vielen Dank für die Aufmerksamkeit.
  • 186. Fragen? Vielen Dank für die Aufmerksamkeit. Bildquellen © iStockphoto.com Kontakt holger.rueprich@1und1.de stephan.schmidt@1und1.de

Notas do Editor

  1. Wissen - Ich muss meine Technologie und die Dom&amp;#xE4;ne kennen &amp;#xDC;bung - Der erste Entwurf geht schief (&amp;#xDC;berflieger: 1000 Stunden, 1000 Fotos f&amp;#xFC;r die Tonne) Wahrnehmung - Sehen wo die Probleme liegen, Schnelles Verstehen Vorstellung - Software ist abstrakt Intuition - Software-Entwurf ist kein striktes logisches Vorgehen
  2. Stabil - Unser Leben basiert auf Software, wenn unserer Software versagt... Sicher - Online Banking, Sensible Daten im Netz Flexibel - &quot;640kb reichen f&amp;#xFC;r jeden&quot; Performance - Twitter Ausfall
  3. Stabil - Unser Leben basiert auf Software, wenn unserer Software versagt... Sicher - Online Banking, Sensible Daten im Netz Flexibel - &quot;640kb reichen f&amp;#xFC;r jeden&quot; Performance - Twitter Ausfall
  4. Stabil - Unser Leben basiert auf Software, wenn unserer Software versagt... Sicher - Online Banking, Sensible Daten im Netz Flexibel - &quot;640kb reichen f&amp;#xFC;r jeden&quot; Performance - Twitter Ausfall
  5. Stabil - Unser Leben basiert auf Software, wenn unserer Software versagt... Sicher - Online Banking, Sensible Daten im Netz Flexibel - &quot;640kb reichen f&amp;#xFC;r jeden&quot; Performance - Twitter Ausfall
  6. Stabil - Unser Leben basiert auf Software, wenn unserer Software versagt... Sicher - Online Banking, Sensible Daten im Netz Flexibel - &quot;640kb reichen f&amp;#xFC;r jeden&quot; Performance - Twitter Ausfall
  7. Stabil - Unser Leben basiert auf Software, wenn unserer Software versagt... Sicher - Online Banking, Sensible Daten im Netz Flexibel - &quot;640kb reichen f&amp;#xFC;r jeden&quot; Performance - Twitter Ausfall
  8. Stabil - Unser Leben basiert auf Software, wenn unserer Software versagt... Sicher - Online Banking, Sensible Daten im Netz Flexibel - &quot;640kb reichen f&amp;#xFC;r jeden&quot; Performance - Twitter Ausfall
  9. Stabil - Unser Leben basiert auf Software, wenn unserer Software versagt... Sicher - Online Banking, Sensible Daten im Netz Flexibel - &quot;640kb reichen f&amp;#xFC;r jeden&quot; Performance - Twitter Ausfall
  10. Stabil - Unser Leben basiert auf Software, wenn unserer Software versagt... Sicher - Online Banking, Sensible Daten im Netz Flexibel - &quot;640kb reichen f&amp;#xFC;r jeden&quot; Performance - Twitter Ausfall
  11. Stabil - Unser Leben basiert auf Software, wenn unserer Software versagt... Sicher - Online Banking, Sensible Daten im Netz Flexibel - &quot;640kb reichen f&amp;#xFC;r jeden&quot; Performance - Twitter Ausfall
  12. Stabil - Unser Leben basiert auf Software, wenn unserer Software versagt... Sicher - Online Banking, Sensible Daten im Netz Flexibel - &quot;640kb reichen f&amp;#xFC;r jeden&quot; Performance - Twitter Ausfall
  13. Stabil - Unser Leben basiert auf Software, wenn unserer Software versagt... Sicher - Online Banking, Sensible Daten im Netz Flexibel - &quot;640kb reichen f&amp;#xFC;r jeden&quot; Performance - Twitter Ausfall
  14. Stabil - Unser Leben basiert auf Software, wenn unserer Software versagt... Sicher - Online Banking, Sensible Daten im Netz Flexibel - &quot;640kb reichen f&amp;#xFC;r jeden&quot; Performance - Twitter Ausfall
  15. Stabil - Unser Leben basiert auf Software, wenn unserer Software versagt... Sicher - Online Banking, Sensible Daten im Netz Flexibel - &quot;640kb reichen f&amp;#xFC;r jeden&quot; Performance - Twitter Ausfall
  16. Stabil - Unser Leben basiert auf Software, wenn unserer Software versagt... Sicher - Online Banking, Sensible Daten im Netz Flexibel - &quot;640kb reichen f&amp;#xFC;r jeden&quot; Performance - Twitter Ausfall
  17. Stabil - Unser Leben basiert auf Software, wenn unserer Software versagt... Sicher - Online Banking, Sensible Daten im Netz Flexibel - &quot;640kb reichen f&amp;#xFC;r jeden&quot; Performance - Twitter Ausfall
  18. Hamstert N&amp;#xFC;sse, l&amp;#xE4;sst keinen dran...
  19. Seite 120 -129 5min -&gt; Holger
  20. Seite 129 - 130 Weitere Themen 5min -&gt; Stephan
  21. Seite 137 - 153 Wikipedia / Internet 10min -&gt; Holger
  22. YAGNI Premature Optimization Emergenz Negativ Beispiele 10min -&gt; Holger
  23. http://www.xprogramming.com/Practices/PracNotNeed.html Spekulatives Programmieren
  24. Fallbeispiele 5-10min Stephan
  25. http://www.xprogramming.com/Practices/PracNotNeed.html Spekulatives Programmieren
  26. Holger
  27. Cruise Control haupts&amp;#xE4;chlich f&amp;#xFC;r Java bekannt phpUnderControl Erweiterung f&amp;#xFC;r PHP Funktionsweise - Konfiguration per ant (build.xml) - Checkout Target -&gt; Neuste SVN Version holen - PHPDoc Target -&gt; Dokumentation generieren - CodeSniffer Target -&gt; Coding Guidelines validieren - PHPUnit Target -&gt; Unit Tests durchf&amp;#xFC;hren
  28. Hudson - Haupts&amp;#xE4;chlich f&amp;#xFC;r Java l&amp;#xE4;sst sich aber auch f&amp;#xFC;r PHP einsetzen Xinc - in PHP f&amp;#xFC;r PHP entwickelt Bamboo - kostenpflichtig