// der php hacker

// archiv

Modellgetriebene Softwareentwicklung mit PHP

Geschrieben am 16. Dez 2008 von Cem Derin

Ich bin ein großer Freund von Modellgetriebener Softwareentwicklung. Man hat den Vorteil, dass man Abläufe im Vorfeld definieren kann und merkt so sehr schnell, wenn etwas, dass im Kopf noch wunderbar funktioniert hat, in der Praxis totaler Blödsinn ist. Man steht dann aber nicht vor dem Dilemma, einen Haufen Code nun umwälzen zu müssen, sondern kann im Modell alles verändern, verschieben, umbenennen, hinzufügen oder löschen – und das mit ein paar Klicks.

Neben dem definieren für sich selbst, bekommt man als netten Nebeneffekt auch noch aussagekräftige Diagramme, die meistens schon ausreichen, um Kollegen oder Mitarbeitern seine Idee oder sein Konzept klar zu machen. Und mittels Code-Generation hat man Klssenskellete so schnell erstellt wie nie zuvor – inklusive Type Hinting, DocSyntax und require-Anweisungen. Toll.

Wie ich das ganze angehe, möchte ich im folgenden Artikel beschreiben. Da es leider auch noch ein paar Fallstricke gibt, was den Versuch des Roundtrip Engineering mit PHP angeht, ist dieser Artikel nicht nur für Anfänger interessant, sondern auch für Fortgeschrittene, die den Schritt zu dieser Entwicklungsmethode auf PHP-Basis in Erwägung ziehen.

Software

Als Werkzeug verwende ich hier ArgoUML. ArgoUML stammt aus dem Hause Tigris, ist freie Software und ist in Java geschrieben. Somit ist diese Software für nahezu jedermann zu haben. Und bisher das beste, was mir in Sachen PHP-Code Generierung untergekommen ist.

Also, runtergeladen, installiert und gestartet. Erstmal einstellen. Dazu gehen wir “Bearbeiten -> Einstellungen” in den entsprechenden Dialog und wechseln in den Reiter “Benutzer”. Dort hinterlegen wir uns unseren Namen und unsere eMail-Adresse. Diese wird später für die DocSyntax verwendet. Arbeitet man also in einem Unternehmen oder in nur einem Team, reicht das hier vollkommen. Andernfalls kann man das auch Projektspezifisch hinterlegen.

Umstellung bestehender Projekte

Die Integration Modellgetriebener Entwicklung in bestehende Projekte kann schnell in unglaublich viel Arbeit ausarten. Grade, wenn es nicht möglich ist, bestehende Projekte zu importieren. An dieser Stelle empfehle ich, einfach nur neue, abgeleitete oder benötigte Klassen und Pakete in das Modell zu übernehmen – so erhält man nach und nach ein nahezu komplettes Modell mit vergleichbar geringem Aufwand.

Pakete und Klassen anlegen

Wir erstellen ein neues Projekt. Links haben wir nun einen Eintrag “unbenanntesModell”. Unschön. Das benennen wir um in “BeispielProjekt”. Dazu einfach den Eintrag anklicken. Im unteren Splitview kann man die Modelleigenschaften nun bearbeiten.

Als erstes wird man Pakete anlegen müssen. Egal ob man nur eine eigene Library verwendet, oder ob man zusätzlich auch PEAR, dem Zend Framework oder andere Bibliotheken setzt: man hat alles (hoffentlich) in einer gewissen Paketstruktur untergebracht. Wenn man ein Projekt “from the scratch” beginnt, ist es an dieser Stelle noch einfacher. Wir nehmen einfach mal an, dass wir zwar ein eigenes Framework aufbauen wollen, dieses aber wiederum auf dem Zend Framework basiert. Also legen wir zwei Pakete an: “MyFramework” und “Zend”. Dazu einfach ein Rechtsklick auf “BeispielProjekt” und “Erstelle Modell-Element -> Neues Paket” auswählen. Auch hier wieder: Paket auswählen und im unteren Bereich kann man die Einstellungen editieren. Erstmal ist für uns nur der Name der Pakete interessant.

modell1

Modell erstellen

Nun können wir ein konkretes Modell erstellen. Da stellt sich in unserem Fall zunächst einmal die Frage: Was wollen wir eigentlich genau umsetzen? Als Beispiel wollen wir nun eine Registry für die Cache-Klassen, die das ZF mitbringt, erstellen. Auch die Registry basiert auf der ZF-Registry. Wir nehmen uns nun das erste Klassendiagramm und benennen es um in “Caching”. In dieses leere Diagramm werden wir nun die Klassenbeziehungen zeichnen.

Dazu müssen wir erst einmal die ZF-Klassen anlegen. Das wäre zum einen Zend_Registry. Wir legen also eine Klasse “Registry” und eine Klasse “Cache” unterhalb des “Zend”-Paketes an. Dazu wieder einfach nur einen Rechtsklick auf das entsprechende Pakte und “Erstelle neues Modell-Element -> Klasse” anklicken. Wieder unten den Namen angeben und – et voila!

Wir wechseln wieder in unser “Caching”-Diagramm und ziehen nun die beiden neu erstellten Klassen in die Arbeitsfläche. Uns sollte sich nun folgendes Bild bieten.

modell2

Den Klassen wurde bereits automatisch der Namensraum “Zend” hinzugefügt. Das mag zunächst verwirrend dargestellt sein, da die zwei Doppelpunkte zunächst der Scope Resolution Operator für statische Klassenzugriffe war, dann als Namespace-Seperator diente jetzt aber wieder duch Backslashes abgelöst wurde, aber da müssen wir uns keine Sorgen machen, da ArgoUML die Klassennamen später nach dem Schema <Paket>_<Paket>_<Klasse> benennt. Wobei hier durchaus mehr als zwei Paketebenen möglich sind.

Nun wollen wir flexibel bleiben und leiten diese beiden Klassen in unserem Framework ab. Dazu erstellen wir jeweils die selben Klassen in unserem “MyFramework”-Paket. Diese werden auch in die Arbeitsfläche gezogen. Alles sollte nun so aussehen.

modell3

Da wir aber eine eigene Registry für unsere Cacheobjekte haben wollen, erstellen wir ein neues Paket in unserem Framework welches wir “Cache” nennen und erstellen dort eine neue Klasse namens “Registry”. Wieder schnell in die Arbeitsfläche gezogen haben wir nun insgesamt 5 Klassen in unserer Arbeitsfläche. Schön und gut. Aber wie sagen wir nun, wie welche Klasse sich von welcher ableitet? Nichts einfacher als das. Dazu bedienen wir uns der Generalisierung. Das ist in der Toolbar der nach oben gerichtete Pfeil mit durchgehender Linie und nicht ausgefüllter Spitze. Auswählen, in die Klasse, die spezialisieren soll klicken, die Maustaste gedrückt halten, auf die Klasse ziehen, die spezialisiert wird und loslasen. Tada. Das machen wir nun mit allen Klassen und unser Diagramm ist fast fertig für den Export.

modell4

Verwenden wir keinen Autoloader, so ist es noch nötig Kompositionen anzugeben, die ausdrücken, dass eine Klasse von einer anderen Abhängig ist. Dazu verwenden wir eine Komposition, um auszudrücken, dass unsere Cache-Registry (beliebig viele) Cache-Objekte enthalten kann. Das ganze sollte nun so ausschauen.

modell5

Wenn man will, kann man eine Klasse durch anklicken Auswählen, und um unteren Bereich in die Quellcode-Ansicht wechseln. Dort sieht man dann schonmal, wie der Quellcode aussehen wird. Evtl. muss hier noch “PHP5″ als Sprache ausgewählt werden. Nun wollen wir unseren Kram mal exportieren.

Code Export

Kommen wir nun also zum hässlichen und wahrscheinlich auch aufwändigsten Teil. Dem Code-Export. Das gute: Das Grundgerüst wird uns automatisch erzeugt. Das schlechte: Wir haben ein bisschen Schrott wegzustellen. Fangen wir also erstmal mit dem Export an. Dazu klicken wir auf Generieren. Das nun folgende Kontextmenu “Markierte Klassen generieren …” ist leider deaktiviert. Ich habe bis heute nicht herausgefunden, wie man eine Klasse so “markieren” kann, dass Sie als ausgewählt gilt. Das Netz half hier nicht weiter, alles was ich fand war ein Bug Report, der das 2003 bemängelte. Sei’s drum. Wir Exportieren alles. Aber Obacht. Auf keinen Fall in den Projektordner! Wir nehmen einen neuen Ordner für den Export. Dann schnell den Overall angezogen – jetzt heißts Handarbeit.

Ein bischen aufräumen

So oder so empfehle ich die generierten Klassen zunächst einmal neu zu benamen. Das hässliche “class” vor jeder Datei ist sehr hässlich und stört. Wenn man keinen Autoloader benutzt, müssen die include-Anweisungen ebenfalls angepasst werden – wenn man einen benutzt, müssen sie komplett raus. Mit einer IDE wie PDT oder ähnlichem sollte das kein Problem sein. Wer will, kann die von ArgoUML eingefügten Steuerkommentare ebenfalls entfernen. Die meisten fliegen beim befüllen der Methoden raus – der Rest ist Geschmackssache.

Ein Vorteil hat die “class.*”-Benennung allerdings. Man kann alle Klassen ins Projekt kopieren, ohne sie zu überschreiben. Ich kann mir allerdings denken, dass einige aus Bequemlichkeit das “class.” davor stehen lassen – deswegen der Hinweis auf keinen Fall ins Projekt zu generieren.

Beim kopieren ins Projekt sollte allerdings nicht vergessen werden, dass wir nur neue Klassen/Ordner kopieren. Wir wollen ja nicht versehentlich Zend-Klassen überschreiben.

Round trip Engineering

Kurz, knapp und schmerzlos: Geht nicht. Mir ist bisher kein Werkzeug untergekommen, dass Round trip Engineering mit PHP zulässt. Die fähigste Software auf dem Gebiet war “Enterprise Architect“, welche allerdings eher mäßigen Code generiert (ArgoUML unterscheidet wenigstens zwischen PHP4 und PHP5), und auch der Abgleich zwischen Projekt und Modell stellt sich schnell als Glückspiel heraus.

Bleibt zu hoffen, dass da in Zukunft mehr geschieht – nachher bleibt das noch an uns hängen ;-)

Geschrieben in Entwicklung Ein Kommentar

#001
11. Feb 2009
Remaco

Angeblich soll es BOUML können. Leider konnte ich mit dem Programm nicht umgehen :-( Interessierte können mal in der Wikipedia nachlesen: http://de.wikipedia.org/wiki/BOUML

// kommentieren

// senden
theme von mir, software von wordpress, grid von 960 grid system. funktioniert in allen browsern, aber der safari bekommt das mit der schrift am schönsten hin.