Kapitel 8. Entwicklung einer Blogging-Anwendung

Inhaltsverzeichnis

8.1. Einleitung
8.2. Planung
8.3. Inkrementelle Entwicklung und YAGNI
8.4. Kontrollieren wir unsere Toolbox
8.5. Das hier ist nicht das Referenzhandbuch

8.1. Einleitung

Da Sie das Zend Framework nun schon etwas kennengelernt haben, ist es jetzt an der Zeit, mit dem Planschen im Kinderbecken aufzuhören und sich ins tiefe Wasser vorzuwagen. Aber keine Sorge, fürs Erste dürfen Sie die Schwimmflügel dabei anbehalten.

Das Thema des zweiten Teils dieses Buches ist das Schreiben einer Blog-Anwendung. Ich habe mich für einen Blog entschieden, weil die meisten von uns diese Anwendung sehr gut kennen. Indem Unsicherheit reduziert wird, was da überhaupt entwickelt wird, können wir uns besser auf die Implementierung wohl bekannter Funktionalitäten konzentrieren. Dennoch ist es nie eine gute Idee, sich mit verbundenen Augen in ein Projekt zu stürzen. Ich wollte schon seit längerer Zeit selbst einen kleinen persönlichen Blog bauen (mir machen solche Dinge Spaß), also fangen wir an.

8.2. Planung

Wenn wir unser kleines Projekt planen, müssen wir uns zuerst die offensichtlichste Frage stellen. Was ist das Ziel des Projekts?

Unser Ziel ist, eine Blogging-Anwendung zu entwerfen und zu entwickeln, die es dem Benutzer erlaubt, Artikel zu schreiben und diese online zu veröffentlichen.

Ich halte meine Ziele gerne kurz und knapp. Wenn sie eindeutig sind, umso besser. Ihr Hauptzweck ist, uns daran zu erinnern, warum wir das machen und einen Anhaltspunkt für zukünftige Diskussionen über weitere Features anzubieten.

Ein knapp formuliertes Ziel weist uns zwar darauf hin, was wir letzten Endes erreichen wollen, doch wir müssen mehr Details hinzufügen, damit wir wissen, wo wir anfangen müssen. Anstatt uns in einem langen Anforderungsheft zu verstricken, werden wir aber nur ein paar Entwürfe erstellen, die genauer definieren, wie die Anwendung funktioniert.

  1. Der Autor schreibt Einträge über das Blog-Interface.

  2. Einträge werden als HTML-Seiten veröffentlicht, wenn sie vom Autor fertiggestellt worden sind.

  3. Veröffentlichte Einträge werden über aggregierte RSS-2.0- und Atom-1.0-Feeds verbreitet.

  4. Nur Autoren dürfen Einträge schreiben und veröffentlichen.

  5. Leser können Kommentare verfassen, die auf den HTML-Seiten unterhalb der Einträge angezeigt werden.

  6. Leser-Kommentare werden über aggregierte RSS-2.0- und Atom-1.0-Feeds verbreitet.

An dieser Stelle haben wir genug Material zum Spielen. Wir könnten Punkte zu der Liste hinzufügen, bis sie mehrere Seiten lang ist, aber mit dieser Kernfunktionalität erreichen wir bereits unser anfänglich definiertes Ziel.

Mittels dieser Liste benötigter Funktionen - illustriert durcht einfache Aussagen, was verschiedene Benutzer tun können - können wir die Bausteine der Anwendung ausmachen. Da wir das Zend Framework verwenden, können wir einige Abkürzungen nehmen und uns auf das konzentrieren, was wirklich wichtig ist: die anwendungsspezifischen Anforderungen. Und an diesem Punkt schauen wir auch schon dem Domain-Modeling in den blutrünstigen Rachen. Aber wir halten es ganz einfach und beginnen damit, Entitäten sowie die damit verbundenen Daten in unserem System zu identifizieren.

Aber Achtung: es ist wichtig an diesem Punkt festzuhalten, dass wir nicht eine Datenbank betrachten. Datenbanken sind ein Tool, die es einem Model erlauben, sich zwischen Anfragen zu speichern, aber an dieser Stelle entwerfen wir keine Tabellen und schreiben kein SQL. Warum wir das so machen, werden wir im nächsten Kapitel behandeln, wenn wir in weit tiefere Gewässer vorstoßen und uns der Frage stellen, wie wir das Model implementieren.

Die Entitäten, die wir identifizieren konnten (und die in der Zukunft zu unseren Domain-Objekten werden könnten) umfassen:

  • Autor (Author)

  • Eintrag (Entry)

  • Leser (Reader)

  • Kommentar (Comment)

Den Leser könnten wir eventuell eliminieren, da der Leser in unserer Anwendung ein anonymer Benutzer ist. Das einzige, was wir für anonyme Benutzer verwalten wollen, sind einige Sitzungsdaten. Wenn wir aber eine Datenbank für ein Model verwenden dürfen, ist ein Leser-Objekt zum Kapseln der Sitzungsdaten für einen anonymen Benutzer vielleicht doch keine schlechte Idee - denn wo sonst wollen wir uns darum kümmern? Im Controller? Wie wir im vorherigen Kapitel gesehen haben, ist der Controller NICHT das Model.

Die drei anderen sind hingegen ganz eindeutige Kandidaten für Domain-Objekte. Wir können diese potentiellen Entitäten genauer definieren, um herauszuarbeiten, welche Daten sie zumindest benötigen werden. Ich sollte anmerken, dass ich bei Diskussionen um Models davon ausgehe, dass alle Entitäten durch Objekte dargestellt werden. Fremdschlüssel werden daher nicht erwähnt (das ist eine Angelegenheit von Datenbanken), denn jedes Objekt kann andere Objekte enthalten, um auf zugehörige oder damit verbundene Entitäten zu verweisen.

  • Autor

    Vollständiger Name (fullname)

    Benutzername (username)

    E-Mail (email)

    URL (url)

    Passwort (password)

  • Eintrag

    Titel (title)

    Inhalt (content)

    Veröffentlichungsdatum (published date)

    Autor (author)

  • Kommentar

    Name (name)

    Title (title)

    Inhalt (content)

    Veröffentlichungsdatum (published date)

    Eintrag (entry)

Wir könnten noch viel mehr hinzufügen, aber weitere Punkte sind für uns momentan unwichtig. Momentan müssen wir nur diese grundlegenden Daten betrachten und überlegen, in welcher Verbindung sie zu anderen Models unserer Domain stehen.

Im letzten Teil dieser anfänglichen Analyse schauen wir uns an, welche Art von "Seiten" unsere Anwendung generieren muss. Das ist - je nachdem, wie wir den Begriff "Seite" definieren - eine gar nicht so einfache Angelegenheit. Zählen wir Seiten oder URLs dazu, die nur auf AJAX-Anfragen reagieren? Wie sieht es mit Web-Service-APIs aus, zum Beispiel für eine zukünftige Implementierung des AtomPub-Protokolls, damit wir außerhalb der Anwendung bloggen können? Auch hier werden wir uns das Thema wieder für später aufheben, wenn wir uns noch über etwas unsicher sind. Die Hauptseiten, die wir auf jeden Fall benötigen werden, umfassen:

  • Blog-Index (Blog Index)

  • Eintragsseite (Entry Page)

  • Autor-Login (Author Login)

  • Bearbeiten von Einträgen (Entry Editing)

  • Freischalten von Kommentaren (Comment Approval)

  • RSS-Einträge-Feed (RSS Entry Feed)

  • Atom-Einträge-Feed (Atom Entry Feed)

  • RSS-Kommentar-Feed (RSS Comment Feed)

  • Atom-Kommentar-Feed (Atom Comment Feed)

Jetzt haben wir zumindest eine Vorstellung davon, was wir machen müssen. Wir starren nicht mehr blind und ohne Idee auf unsere IDE, sondern können uns hinsetzen und mit dem Schreiben von Code anfangen. Im nächsten Kapitel beginnen wir damit, indem wir unser Model erstellen. Danach können wir an der Präsentation der Anwendung arbeiten.

8.3. Inkrementelle Entwicklung und YAGNI

Viele Blogs prahlen mit einer Vielzahl von Features und führen uns so in Versuchung, unsere neue Anwendung überzuspezifizieren. Das würde aber zu Problemen führen, denn a) wir würden unsere Aufmerksamkeit nicht mehr so sehr auf die Kernfunktionen richten, b) wir würden versuchen einen Bedarf vorherzusehen, dessen Existenz gar nicht bestätigt ist und c) die Extraspezifikationen sind wertlos, solange die Blog-Kernanwendung nicht fertiggestellt ist. Wir werden den Blog daher inkrementell entwickeln und nötige Funktionen Iterationen zuweisen, die wir Schritt für Schritt durchlaufen und in denen wir die Funktionen implementieren. Zugleich gewährleisten wir dabei, dass die Anwendung stabil ist und ihre Unit-Tests ohne Fehler durchläuft, bevor wir mit einer weiteren ausstehenden Iteration beginnen.

Das geschieht in Kooperation mit einem Partner aus der Welt des eXtreme Programming, "You Ain't Gonna Need It" (kurz YAGNI; auf Deutsch "du wirst es nicht brauchen"). YAGNI lehrt uns, dass eine Menge von schwerwiegenden Nachteilen daraus entsteht, wenn man sich zu sehr auf Funktionalitäten einlässt, die momentan nicht notwendig sind. Erstens benötigt man dafür Zeit, was entweder heißt, dass Sie zu viele Entwickler haben (nein, das hab' ich nie gesagt!) oder dass Ihre jetztigen Entwickler Zeit für zukünftige Features auf Kosten der aktuell benötigten Features aufwenden. Diese Zeit wird zum Beispiel für die Entwicklung, das Testen, das Sammeln von Anforderungen, die Dokumentation etc. verwendet. Alles Dinge, die wir im Moment nicht brauchen. Zweitens ignorieren wir so, dass die Zukunft ungewiss ist. Was, wenn sich herausstellt, dass wir dieses Feature nie brauchen werden? Was, wenn ein Kunde seine Meinung bei grundlegenderen Punkten ändert und somit gleich mehrere dieser zukünftigen Features obsolet sind? Was, wenn die Implementierung eines solchen zukünftigen Features ein anderes Feature verhindert, das wir - wie sich später herausstellt - benötigen? Unter anderen Umständen muss für das Hinzufügen des neuen Features zusätzliche Unterstützungsarbeit geleistet werden, was womöglich lawinenartig noch mehr neue, aktuell nicht benötigte Features nach sich zieht, die wir dem neuen Feature hinzufügen.

Inkrementelle Entwicklung funktioniert hier, da ich der Kunde bin (der eigene Kunde zu sein ist wohl der schlimmstmögliche Fall). In vielen Projekten jedoch sind andere die Klienten. Ihre Anforderungen können sich mit der Zeit beträchtlich verändern. Inkrementelle Entwicklung ist eine exzellente Vorgehensweise, aber man muss dennoch eine Anwendung schreiben, bevor alle Anforderungen bekannt sind, verstanden und dokumentiert wurden. Nicht alle Klienten werden dazu fähig oder bereit sein, einen so ungewissen Prozess mitzumachen. Eventuell ist es für sie auch schwer, eng genug mit Ihnen zu arbeiten um zu gewährleisten, dass es funktioniert. Ein anderer Effekt der inkrementellen Entwicklung ist, dass wir auf die Atomarität unserer Unit-Tests achten müssen. Ein häufiger Fehler ist, dass man versucht zu viel zu testen, indem man Assertion über Assertion in einem einzelnen Test aufschichtet. In einem sehr begrenzten Szenario richtet man dadurch kaum Schaden an, aber sobald wir zur Darstellung kompletter Seiten und den Tests von Workflows kommen, laufen wir Gefahr uns dabei wiederzufinden, wie wir ständig Tests editieren, um die eigentlichen Anforderungen nachzubilden. Das Bearbeiten alter Tests ist kein gutes Zeichen - es zeigt, dass sie von Anfang an nicht fokussiert genug waren.

Dieser Prozess ist für unseren Blog äußerst gut geeignet. Es handelt sich um eine einfache Anwendung, bei der wir es uns leisten können, neue Anforderungen erst später zu erfüllen, wenn sie sich in zukünftigen Kapiteln materialisieren.

8.4. Kontrollieren wir unsere Toolbox

Es wäre großartig, alles mit dem Zend Framework zu erledigen, aber wir werden von Zeit zu Zeit ein paar zusätzliche Werkzeuge benötigen. Da ich bekennender jQuery-Liebhaber bin, der keine Ahnung von Dojo hat, sollten Sie die aktuellste jQuery-Version griffbereit haben, wenn wir dazu kommen, mit AJAX-Requests und der Manipulation des User-Interfaces zu spielen. Ich werde außerdem das Blueprint-CSS-Framework verwenden, um die CSS-Bearbeitung auf ein Minimum zu beschränken und ein einfaches Layout verwenden zu können, ohne dass ich stundenlang mit dem Raster kämpfen muss. Weiters arbeite ich kaum einmal ohne eine gute HTML-Filter-Bibliothek - etwas, was das Zend Framework momentan nicht anbietet. Ich werde zu diesem Zweck HTMLPurifier 4.0.0 verwenden. Nicht zuletzt werde ich PHPUnit für alle Unit-Tests verwenden, also achten Sie bitte darauf, dass Sie es über den PHPUnit-Pear-Channel installieren.

Ich werde diese Tools und ihre Installation näher beleuchten, wenn wir sie brauchen.

8.5. Das hier ist nicht das Referenzhandbuch

Dieses Kapitel ist sehr kurz und ich möchte es damit abschließen zu betonen, was ich in der Einleitung des Buches geschrieben habe. Da der Zweck dieses Buches ist, diejenigen zu unterstützen, die ins "kalte Wasser" springen wollen, nehme ich an, dass Sie bereits etwas mit dem Zend Framework bekannt sind. Ich gehe auch davon aus, dass Sie fähig sind, das Referenzhandbuch eigenständig zu lesen. Deswegen werde ich nicht viel Zeit dafür aufwenden, auf jede einzelne Komponente einzugehen, der wir auf dem Weg begegnen, solange wir sie nicht ständig verwenden. Ein Beispiel ist Zend_Db, das im Referenzhandbuch ausführlich bezüglich der API, Beispiele und Verwendungsmöglichkeiten behandelt wird. Anstatt ein ganzes Kapitel (oder fünf) dafür aufzuwenden, Zend_Db und seine Komponentenklassen zu erklären, beschäftigt sich das nächste Kapitel vielmehr damit zu zeigen, wie man die Klassen von Zend_Db verwendet, um ein Model zu erstellen. Unser Model braucht dafür nicht einmal viele Kenntnisse über Zend_Db.

Wenn Sie genauere Informationen zu Zend_Db benötigen, wenden Sie sich bitte an das Referenzhandbuch. Falls begründeter Bedarf besteht, werde ich dem Buch einmal ein zusätzliches Kapitel oder einen Anhang dazu hinzufügen, aber ich kann nur wenig anbieten, was nicht durch das Referenzhandbuch geboten wird (es ist hier sehr detailliert und verständlich).

Es sollte auch klar sein, dass dies kein einfaches Blog-Tutorial wird. Web-Application-Frameworks sind voll von einfachen Blog-Beispielen, aber dies hier wird eine vollfunktionale Anwendung, die ausführlichen Gebrauch von Zend-Framework-Komponenten machen wird (und muss).