Beiträge mit tag "Dependency Injection

Commercial Break: PHP Design Patterns

0

Die zweite Auflage meines Buches ist mittlerweile zwar fast schon ein Jahr alt, aber trotzdem darf natürlich ein bißchen Eigenwerbung in meinem Blog nicht fehlen.

PHP Design Patterns” ist das erste deutschsprachige Buch zu Entwurfmustern in PHP. Neben einer Einführung in objektorientierte Programmierung im Allgemeinen und mit PHP im besonderen (Kapitel 1) sowie einem kurzen Ausflug in die SPL (Kapitel 2), zeigt das Buch auf grundlegende Regeln für gutes Software Design wie z.B. „Vererbung sorgt für starre Stukturen. Verwenden Sie stattdessen Objektkomposition, um verschiedene Funktionen einfacher miteinander kombinieren zu können.” Kapitel 3 behandelt weiterhin auch Fluent Interfaces und Dependency Injection, samt der Verwendung des DI-Containers in Stubbles.

Kapitel 4,5 und 6 behandeln dann einige der Standard Gang of Four Entwurfsmuster, wie Abstract Factory, Prototype, Composite, Facade, Flyweight, Command, State oder auch Chain-of-Responsibility. Die letzten beiden Kapitel stellen das Schichtenmodell vor und zeigen, wie man dies mit Hilfe eines Model-View-Controllers und Patterns wie Active-Record, Template-View, Registry oder auch Event-Dispatcher implementiert.

Das PHP Magazin schreibt zur ersten Auflage (1/2007):

Ein rundes, das anvisierte Themengebiet hervorragend ausfüllendes Buch, das vom Leser nur eins verlangt: Zeit und Konzentration auf den Inhalt. Der Lohn dieser geringfügigen Investition sind verschiedenste Aha-Effekte und ein echter Schub an neuen Kenntnissen und Ideen. Und ein Nachschlagewerk, das man nach dem ersten Lesen nicht mehr vom Schreibtisch nehmen möchte.

Das Buch wurde für die zweite Auflage komplett überarbeitet und an PHP 5.3 angepasst. Dabei wurde ein Großteil der Kapitel erweitert:

Details zu Buch:

Frisch im RSS-Reader

0

Seit ich mich entschlossen habe, selbst aktiv zu bloggen, habe ich auch wieder angefangen, regelmäßig andere Blogs zu lesen. Neu in meinem RSS-Reader sind jetzt:

Frank Westphal

Mit seinem Buch „Testgetriebene Entwicklung mit JUnit und FIT” verfolge ich in unregelmäßigen Abständen, was Frank Westphal veröffentlicht. Auf seiner Website veröffentlich er interessante Artikel zum Extreme Programming, Agiler Entwicklung und Qualitätssicherung. Seinen Podcast „Tonabnehmer” habe ich mir bislang noch nicht angehört, wären aber sicher ein guter Grund, Podcasts endlich mal auszuprobieren.

Neal Ford

Neal Ford ist Meme Wrangler bei Thoughtworks. Auf ihn bin ich bei einer Keynote auf der Dynamic Languages World aufmerksam geworden. Am meisten beeindruckt hat mich damals (und auch heute noch) sein Satz

Simplify essential complexity; diminish accidental complexity.

Diesem Satz hatten Holger Rüprich und ich auch eine unserer neun Regeln in unserem Workshop „Die Kunst des Software Design” auf der PHP World 2009 gewidmet.

Ludwig Ostrowski

Auf das Blog von Ludwig Ostrowski bin ich nur per Zufall (aka Twitter) gestolpert. In meinen Reader hat er es aus zwei Gründen geschafft:

  1. Seine neusten Einträge befassen sich mit Dependency Injection (und sogar PHP und Google Guice, meine Lieblingsthemen bei DI), Continuous Integration und Sonar. Alles Themen, die mich auch schon seit einiger Zeit fesseln.
  2. In seinem Blog zitiert er Martin Fowler mit einem meiner Lieblingszitate.

Any fool can write code that a computer can understand. Good programmers write code that humans can understand.

Ich werde das Blog auf jeden Fall mal im Auge behalten.

David Seah

Zum Abschluss noch ein Blog, das nichts mit Software-Entwicklung zu tun hat. David Seah schreibt über Design und Produktivität und kombiniert beides, in dem er wunderschöne Vordrucke für Tasklisten oder auch Ressourcenplanung zum kostenlosen Download anbietet. Zusammengefasst werden diese unter dem Namen „The Prinable CEO”, den David Seah wie folgt erklärt:

The Printable CEO name comes from the idea that a good CEO should focus primarily on those things that move the company forward; since I can’t afford to hire my own CEO, being able to print one out seemed like the next best thing!

Die Feeds

new-Operator in PHP überladen…

0

…oder besser nicht? Mit der Extension test_helpers, die Sebastian Bergmann in seinem PHPUnit Channel veröffentlicht hat, ist es möglich, einzugreifen, wenn ein Objekt mit Hilfe des new-Operators erzeugt wird und stattdessen eine andere Klasse zu instanziieren. Das kann vor allem bei Tests nötig werden, wenn es die Architektur einer Anwendung nicht erlaubt, einzelne Klassen auszutauschen:

class NewsFeedGenerator {
    public function generateFeed() {
        $newsTable = new NewsEntryTable();
        foreach ($newsTable->getEntries() as $entry) {
            // hier wird der Newsfeed generiert.
        }
    }
}

Wenn Sie für diese Klasse einen Unit-Test schreiben möchten, der prüft, ob die Klasse einen korrekten Newsfeed generiert, dann sind sie im Test immer davon abhängig, dass sie wissen, welche Einträge aktuell in der Datenbank stehen. Alternativ könnten Sie natürlich auch sicherstellen, dass die Datenbank im Voraus mit den entsprechend erwarteten Einträgen gefüllt wird.

Ein Unittest sollte allerdings eine einzelne Komponente (in diesem Fall den Newsfeed-Generator) isoliert testen, damit der Test nicht fehl schlägt, bloss weil die Datenbank im Moment nicht verfügbar ist. Aus diesem Grund werden in Unit-Tests Mock-Objekte eingesetzt, die das gewünschte Verhalten simulieren. Ein Mock für die Klasse NewsEntryTable könnte ganz einfach implementiert werden:

class NewsEntryTableMock {
    public function getEntries() {
        return array(
            array('id' => 1, 'title' => 'Title 1', 'desc' => 'Description 1'),
            array('id' => 2, 'title' => 'Title 2', 'desc' => 'Description 2')
            // etc.
        );
    }
}

Wenn Sie diese Klasse verwenden, um den Newsfeed zu erzeugen, können Sie sich sicher sein, dass Sie immer die selben Daten als Basis verwenden.

Doch wie bekommen Sie die Klasse NewsFeedGenerator dazu, diese Datenquelle zu nutzen?

Mit Hilfe der neuen Extension ist das ganz einfach, Sie ersetzen die Klasse NewsEntryTable durch NewsEntryTableMock:

function overload_callback($className) {
    if ($className === 'NewsEntryTable') {
        return 'NewsEntryTableMock';
    }
    return $className;
}
set_new_overload('overload_callback');

Wenn Sie nun eine Instanz von NewsEntryTable erzeugen möchten, dann erzeugt PHP stattdessen eine Instanz von NewsEntryTableMock und sie können Ihren Newsfeed-Generator isoliert testen. Problem gelöst, möchte man meinen.

Das Problem ist jedoch nicht, dass ihr Test nicht isoliert ablaufen kann, sondern dass Sie eine feste Kopplung zwischen NewsFeedGenerator und NewsEntryTable in Ihrer Applikation haben. Was passiert, wenn Sie die Datenquelle auch im Betrieb austauschen müssen, da die Newseinträge nicht mehr in einer Datenbank sondern einer XML- oder CSV-Datei gespeichert werden, oder sogar über einen Service von einer anderen Applikation abgefragt werden müssen? Mit der aktuellen Architektur haben Sie dazu keine Möglichkeiten. Mit dem Einsatz von Dependency Injection jedoch schon:

class NewsFeedGenerator {
    protected $dataSource;
    public function __construct(NewsDataSource $dataSource) {
        $this->dataSource = $dataSource
    }
    public function generateFeed() {
        foreach ($this->dataSource->getEntries() as $entry) {
            // hier wird der Newsfeed generiert.
        }
    }
}
interface NewsDataSource {
    public function getEntries();
}
class DBNewsDataSource implements NewsDataSource {
    public function getEntries() {
        // Aus der Datenbank lesen
    }
}

$ds = new DBNewsDataSource();
$generator = new NewsFeedGenerator($ds);

Die beiden Klassen sind nun nicht mehr voneinander abhängig, NewsFeedGenerator hat nur noch eine Abhängigkeit auf das entsprechende Interface, nicht mehr auf die Implementierung. Sie können die Implementierung für den Test oder auch im Live-Betrieb austauschen, ohne dazu die Extension verwenden zu müssen.

Sie mögen Sich nun fragen, wo das Problem liegt, wenn Sie die Klasse durch den Einsatz der test_helpers Extension austauschen, da Sie feste Abhängigkeiten haben. Ein Test für schlecht designten Code ist sicher besser als kein Test für schlecht designten Code. Das hängt jedoch davon ab, was man sich von Tests verspricht. Ich war noch nie ein großer Freund von Unit-Tests, es langweilt mich meistens, Tests zu schreiben. Was mich jedoch dazu gebracht hat, trotzdem Tests zu schreiben, ist, dass ich festgestellt habe, dass die Architektur der Applikation besser wird. Tests sind ein zweiter Client für die Applikation, der uns zwingt, die Applikation aus einem anderen Blickwinkel zu sehen. Durch Tests deckt man Abhängigkeiten auf und wird gezwungen, diese zu lösen. Die ganze Applikation wird loser gekoppelt und einzelne Komponenten leichtegwichtiger.

Das Risiko, das ich also beim Einsatz dieser Extension sehe, ist, dass man nicht mehr gezwungen wird, über die Kopplung nachzudenken. Damit geht ein großer Vorteil von Unit-Tests verloren. Sofern Sie sich sicher sind, dass eine Entkopplung zweier Klassen keine weiteren Vorteile (oder sogar Nachteile) bringt, sollte einem Einsatz der Extension nichts mehr im Wege stehen.

Wenn Sie also test-helpers einsetzen möchten, dann denken Sie jedes Mal darüber nach, ob Sie nicht ein grundlegendes Problem mit Abhängigkeiten haben und besser Ihre Applikation refaktorisieren sollten.

nach oben