Wir haben leider gar kein Framework im Einsatz

Stefan PriebschArne Blankerts |

Die Geschichte der PHP-Frameworks beginnt in der Mitte der Nullerjahre, genau genommen 2005. Denn obwohl PHP eigentlich bereits seit 1995 existiert, war erst mit der Version 4 eine rudimentäre Unterstützung von etwas verfügbar, das man aus heutiger Sicht mit viel gutem Willen als Objektorientierung bezeichnen mag. Das hinderte freilich einige Wagemutige nicht daran, erste objektorientierte Gehversuche zu unternehmen und Bibliotheken und Klassen zu veröffentlichen, die zumeist einfach nur bestimmte Funktionalitäten bündelten: PEAR, das PHP Extension and Application Repository, war geboren. Und wenn gleich diese Lösungen wenig mit dem zu tun haben, was man heute unter einem Framework verstehen mag, so findet sich das modulare Konzept von PEAR auch in modernen Frameworks wieder.

Bis zur nächsten Generation von Frameworks in PHP brauchte es die Version 5 der Sprache in 2004 – jetzt mit ernstzunehmender Unterstützung für Objektorientierte Entwicklung –, den Dotcom-Boom und nicht zuletzt den Dänen David Heinemeier Hansson. Ob man aus Sicht von PHP heute stolz darauf sein sollte, den Dotcom-Boom begünstigt zu haben, ist vermutlich eine Frage, über die man hervorragend diskutieren oder gar streiten kann. Unstrittig hingegen ist, dass David Heinemeier Hansson mit seinem Framework Ruby on Rails einen großen Einfluss, auch und gerade auf die PHP-Welt, hatte und vermutlich bis heute hat.

Die PHP-Community schaute anfangs durchaus neidisch auf die ersten Erfolgsmeldungen, wie produktiv man doch mit einem Framework wie Ruby on Rails programmieren könne. Zugegebenermaßen ist ein Vergleich zwischen einer Programmiersprache und einem Framework nicht gerade sinnvoll, aber wer fragt in der heutigen (Medien)welt noch nach der Sinnhaftigkeit von Vergleichen?

Das Standardbeispiel für Ruby on Rails-Anwendungen, die Erstellung eines Blogs in weniger als 10 Minuten, war durchaus beeindruckend, täuscht aber über die Komplexitäten einer realen Anwendung mit ernsthafter Geschäftslogik hinweg. Hinzu kommt die aus heutiger Sicht problematische Verwendung von Active Record und die starke Kopplung von Code an die dahinter stehende Datenbank.

Wohl auch aus der Befürchtung heraus, dass PHP – nicht zuletzt wegen des Rails-Frameworks – Marktanteile an Ruby verlieren könnte, und weil es zu diesem Zeitpunkt kaum ernstzunehmende PHP-Frameworks gab, kündigte die Firma Zend ein eigenes quelloffenes Produkt an: Das Zend Framework.

Bis zu dessen erstem Release am 30. Juni 2007 sollten allerdings rund zwei Jahre vergehen. Zeit, in der auch andere Entwicklerteams an ihren Frameworks für PHP arbeiteten und von denen einige eine durchaus beachtliche Verbreitung erreichten. Den Anfang unter den bekanntesten Frameworks dürften 2005 die Frameworks CakePHP, Agavi und Symfony 1 gemacht haben, gefolgt von CodeIgniter in 2006 und dessen Fork Kohana in 2007.

Selbstverständlich entstanden nicht nur allgemein verwendbare Frameworks, sondern auch mehr oder weniger schlüsselfertige Lösungen für Content Management Systeme, interaktive Portale oder das Erstellen von Online Shops. Neben Typo 3 und Drupal stieg vor allem Magento zu einer der beliebtesten (und häufig gehassten) Plattformen für E-Commerce auf. Fun Fact: Ursprünglich von Zend als Showcase für die Leistungsfähigkeit des eigenen Frameworks angepriesen, verwendete Magento 1 nur sehr wenige Teile einer frühen Vor-Version des Frameworks, und selbst dabei wurden die zugrunde liegenden Konzepte fast bis zur Unkenntlichkeit verbogen.

Die zunehmende Vielfalt an Frameworks und Konzepten brachte schnell die Frage mit sich, welches Framework denn nun das Beste sei. Diese Frage scheint natürlich nahe zu liegen, wenn man schon nicht (mehr) fragen darf, welche Programmiersprache denn nun die Beste ist. Die Diskussionen, die sich an die Versuche einer Beantwortung anschließen, sind freilich in höchstem Maße religiös. Entwickler können schließlich über kaum ein Thema so trefflich streiten, außer vielleicht über Einrückungen und die Frage, an welche Stelle man geschweifte Klammern setzen soll.

Gegen Ende der Nullerjahre dachten sich daher auch verschiedene Konferenzveranstalter, dass eine öffentliche Framework-Diskussion unterhaltsam sein müsse. Wenn schon die Anwender einzelner Frameworks dazu neigen, sich über die Frage, wessen Framework das bessere sei, die Köpfe einzuschlagen, was würde dann erst geschehen, wenn man Kernentwickler verschiedener Frameworks gemeinsam in eine Panel-Diskussion setzt? Wir erinnern uns an eine Konferenz, in der ein – natürlich amerikanischer – Veranstalter vorsorglich auf jeden Platz eine geladene Nerf-Gun gelegt hatte.

Was dann geschah, muss eine bittere Enttäuschung für die Veranstalter gewesen sein: Die Vertreter der verschiedenen Frameworks, die sich ohnehin untereinander kannten, sprachen sich gegenseitig großen Respekt aus, lobten hie und da den technischen Vorsprung der "Konkurrenz" und erzählten, an welchen Stellen man sich vom jeweils anderen hatte inspirieren lassen. Den im Titel der Veranstaltung beschworenen "War of the Frameworks" hatte es so nie gegeben. Die PHP-Community, auch wenn es nach Außen nicht immer den Anschein hat, war immer schon stark miteinander verwoben.

Wer nicht nach Marktanteilen streben muss, um den eigenen Umsatz weiter zu erhöhen und immer wieder neue geschäftliche Erfolgsmeldungen zu veröffentlichen, der kann sich, ähnlich wie PHP als Sprache es auch tat und weiterhin tut, von Ideen, Konzepten und Lösungen anderer inspirieren lassen. Dabei ist es vor allem dieses "voneinander lernen", dass die Innovation beschleunigt. In einer quelloffenen Welt geht das noch besser und noch schneller, da man den Quelltext der anderen ohne technische und juristische Hürden einfach einsehen und – je nach Lizenz – sogar direkt übernehmen oder als Komponente in die eigene Lösung integrieren kann.

Fabien Potencier, Gründer von Sensio Labs und Vater von Symfony, hat sich in diesem Zusammenhang in der PHP-Community verdient gemacht wie kein Zweiter. Er hat es immer schon verstanden, über den Tellerrand von PHP hinaus zu schauen und von anderen Sprachen und deren Frameworks zu lernen. Auf diese Weise hat er neue Ideen und viele Best Practices in die PHP-Community gebracht. Symfony war insofern all die Jahre ein Innovationstreiber in der PHP-Welt und hat viele andere Lösungen und Frameworks beeinflusst. Dabei muss man selbstverständlich nicht mit allen Entscheidungen, Konzepten sowie daraus resultierenden Lösungen einverstanden sein, so manche Innovation allerdings ist – zumindest in der Welt der PHP-Frameworks – heute kaum mehr wegzudenken.

Das konsequente Setzen auf Dependency Injection (DI) beispielsweise, das in der objektorientierten Programmierung eigentlich eine Selbstverständlichkeit sein sollte, war in der PHP Entwicklung nicht immer das so selbstverständliche Mittel der Wahl wie heute. Im Unconference-Track am Rand einer ZendCon in Santa Clara, wo es eine Session zum Thema Dependency Injection gab, saßen Fabien, Stefan und einer der Kernentwickler des Zend Frameworks, Ralph Schindler, zusammen und diskutierten das Für und Wider von DI. Ralph war dabei eingangs wenig überzeugt, warum und weshalb man Dependency Injection überhaupt einsetzen sollte. Offensichtlich waren aber die Argumente von Fabien und Stefan überzeugend, denn beim nächten Release erhielt Zend Framework unter anderem eine neue Komponente, nämlich einen Dependency Injection Container (DIC), geschrieben von eben jenem Ralph Schindler.

Interessant ist, dass das Zend Framework trotz des Namens am Anfang eigentlich eher als eine lose Sammlung von Komponenten vermarktet wurde, die man gut zusammen einsetzen konnte und die einem relativ einheitlichen Entwicklungsschema folgten. Ganz anders als viele der anderen Frameworks, die eher einem "Alles-oder-Nichts" Prinzip folgend eine feste, eher monolitische, Struktur aufwiesen und daher auch als Full-Stack-Framework bezeichnet werden.

Was uns zu einer spannenden Frage führt: Was eigentlich ist ein Framework? Fragt man das Internet, so erhält man wie so häufig unzählige Erklärungen, die sich zum Teil auch noch widersprechen. Dabei ist etwas akademisch formuliert ein Framework einfach nur eine Kontrollflussumkehr (Inversion of Control). Dies bedeutet in der Praxis, dass eine Anwendung nicht selbst den Kontrollfluss steuert, sondern dies eben dem Framework überlässt. So können wiederkehrende Abläufe einmal generisch abgebildet werden, so dass der Anwendungsentwickler sich auf das Schreiben der Anwendung selbst konzentrieren kann, deren Bestandteile dann jeweils vom Framework aufgerufen werden.

Die meisten Frameworks in der PHP-Welt kümmern sich wenig überraschend um die Abstraktion von HTTP-Anfragen und wollen es dem Entwickler so einfach wie möglich machen, eine Anwendung zu erstellen und mit dem Internet zu integrieren.

Viele Frameworks behaupten dabei von sich, auf das MVC-Entwurfsmuster zu setzen. Dass das bereits 1979 von Trygve Reenskaug für Desktop-Anwendungen in Smalltalk erdachte Model-View-Controller Pattern im Web und über Client-Server-Grenzen hinweg konzeptionell gar nicht funktionieren kann, wurde und wird einfach ignoriert. Die Folge ist, dass niemand so genau beantworten kann, welcher Code eigentlich ins Model und welcher in den Controller gehört, auch die Autoren der jeweiligen Frameworks nicht. Nur beim View sind sich die meisten dann wieder mehr oder weniger einig.

Doch egal, für welches HTTP-Framework man sich entscheidet, der Kontrollfluss für das Beantworten einer HTTP-Anfrage ist immer gleich: Abhängig davon, was für ein Request vorliegt, muss entschieden werden, welcher Code auszuführen ist – ein Vorgang, den man Routing nennt. Um das Ergebnis darzustellen, kommt dann meist HTML und somit der eben erwähnte View zum Einsatz. Fehler werden in entsprechende HTTP-Fehlercodes "umgewandelt" beziehungsweise, im Falle von Formularverarbeitung, nutzerfreundlich aufbereitet.

Formular- beziehungsweise Datenverarbeitung ist übrigens ebenfalls ein typischer Anwendungsfall für ein Framework zur Kontrollflussumkehr. Anstelle den Kontrollfluss zu implementieren, definiert der Anwendungsentwickler nur das Formular selbst, legt fest, mit welchen Werten es vorpopuliert werden soll und definiert dann die Validierungsregeln mit den entsprechenden Fehlermeldungen. Im Anschluss muss dann nur noch festgelegt werden, welche Aktion(en) im Erfolgs- und welche im Fehlerfall ausgeführt werden sollen. Die Steuerung übernimmt dann der Inversion-of-Control-Container, im einfachsten Fall eine selbstgeschriebene abstrakte Basisklasse.

Auch ein vermeintlich modernes CQRS-Framework sieht im Grunde nicht viel anders aus, nur dass eben zwischen Kommando (Command) und Anfrage (Query) unterschieden wird und diese getrennt geroutet werden. Hinzu kommt, dass Kommandos normalerweise keine Inhalte zurück geben, während Anfragen offensichtlich dazu dienen, Content auszuliefern. Dass diese Inhalte im Idealfall bereits außerhalb des Requests statisch erzeugt wurden und so in einer optimal zur Anfrage passenden Form vorliegen, ändert am eigentlichen Verarbeitungsablauf nur wenig.

Interessant wird es, wenn sich Anforderungen ändern und dies dazu führt, dass grundlegende Annahmen vor allem des Frameworks nicht mehr zutreffen: Was passiert, wenn statt HTML mit JSON geantwortet werden soll oder der gleiche Geschäftsvorfall unabhängig und ohne einen auslösenden HTTP-Request verarbeitet werden muss? Wie sieht es aus, wenn an stelle einer vollständigen HTML-Seite dynamische, kleine Fragmente in verschiedenen Formaten benötigt werden? Klassische Full-Stack-Lösungen wie Magento oder Typo3 leiden noch heute darunter, dass ihre Architektur auf derart geänderte Anforderungen nicht wirklich ausgelegt ist.

Wer die Geschäftslogik seiner eigenen Anwendung nicht sauber isoliert entwickelt hat, sondern eng mit dem Framework verzahnt, bekommt hier ebenfalls ein Problem. Die Lösung dafür ist dann oft ein Werkzeug wie wget, mit dem von der Kommandozeile aus ein HTTP-Request ausgelöst wird. Oder es kommen mitunter komplexe zusätzliche Technologien zu Einsatz, um die gelieferte Seite zu zerschneiden, zuparsen oder zu konvertieren.

Spannenderweise führt die Erkenntnis, dass mit dem bisher verwendeten Framework nicht mehr alle Anforderungen abgedeckt werden können, nur selten dazu, dass man zunächst die eigentliche Geschäftslogik extrahiert. Der Regelfall scheint zu sein, dass man versucht, die aktuelle Lösung immer weiter zu verbiegen, und damit jegliche Chance auf ein Upgrade verliert oder die gleichen Fehler bei der Migration in ein anderes Framework direkt zu wiederholen.

Die meisten Framework-Anbieter jedenfalls haben ihre Lektion gelernt: War ein Migrationspfad beispielsweise von Zend Framework 1 zur Version 2 faktisch nicht vorhanden, so sind aktuelle Frameworks durchaus darauf bedacht, die Rückwärtskompatibilität zu früheren Versionen weitestgehend zu wahren.

Für uns ist es im Beratungsalltag immer wieder interessant zu erleben, dass sich Entwickler sprichwörtlich bei uns dafür entschuldigen, dass man kein Framework im Einsatz habe. Neben der Tatsache, dass dies in den meisten Fällen nach der obigen Definition von Framework gar nicht stimmt, schimmert hier auch eine vollkommen unnötige Abwertung der eigenen Arbeit durch. Man muss sich weder schämen, wenn man sein eigenes Framework entwickelt hat, das auf die eigenen Anforderungen zugeschnitten ist, noch muss man sich dafür schämen, ein Standardframework einzusetzen.

Ein Framework muss – vielleicht sogar sollte – dabei gar nicht als Full-Stack-Lösung implementiert sein, sondern eben genau eine Aufgabe effizient lösen. In den Zehnerjahren entstand ein klarer Trend weg vom Full-Stack-Framework hin zu den so gennannten Microframeworks wie Slim. Ausgelöst durch die Erkenntnis, dass ein schwergewichtiges Framework, das darauf ausgelegt ist, eine Menge Daten zu laden, um daraus dynamisch eine komplexe HTML-Seite zusammenzubauen, nicht unbedingt geeignet ist, AJAX-Requests aus dem Frontend besonders performant zu beantworten. Mit den möglicherweise übertriebenen Trends hin zu Microservices und Containern scheint eine endgültige Abkehr von großer, monolithischer Software erfolgt zu sein – wenn da nicht die großen Legacy-Brocken wären, die bei den meisten Firmen noch irgendwo im Rechenzentrum im Keller lagern.

Die zwei wichtigsten Lektionen im Zusammenhang mit Frameworks sind: frage nicht, wie Du von Framework X zu Framework Y migrierst, sondern frage, wie Du Deine Anwendung von Framework X unabhängig machen kannst – der Rest kommt dann von selbst, und ist möglicherweise mit der interessanten Erkenntnis gekrönt, dass man so viel Framework dann doch gar nicht braucht.

Und: ein Framework ist eine Lösungsschablone. Es liefert meist einige sinnvolle Best Practices in Form von Konventionen, Regeln oder Dokumentation mit. Man muss sich nur immer wieder bewusst machen, dass niemand, auch nicht das tollste Framework der Welt, den Anspruch darauf hat, der "one and only way" zu sein, etwas zu tun.


Dieser Artikel ist ursprünglich im PHP-Magazin (Ausgabe 6, 2019) erschienen.

Über die Autoren

Stefan Priebsch

Stefan Priebsch inspiriert durch Kombination von neuen Ideen mit erprobten Ansätzen.

Arne Blankerts

Arne Blankerts hat schon Lösungen parat, bevor andere ein Problem erkannt haben.