Inzwischen kennt jeder PHP-Entwickler das Framework Laravel. Ursprünglich geschrieben von Taylor Otwell ist es eine Erleichterung für Entwickler und Teams Projekte im Bereich der Webanwendungen zuverlässig umzusetzen. Eine aktive Community und der Status als eines der größten PHP-Frameworks auf dem Markt machen es zu einer sicheren Lösung für Unternehmen und Einzelpersonen auf Jahre hinaus.
In diesem Beitrag behandeln wir die zumeist weniger beleuchteten Seiten, die mit der Anwendung dieses Frameworks einhergehen und unsere eigenen Erfahrungen über die Jahre hinweg.
Als Laravel mit Version 5 einen Meilenstein erreichte, haben unsere Entwickler gedrängt dieses Framework für zukünftige Projekte zu übernehmen. Manche unserer Mitarbeiter hatten bereits vorgreifende Erfahrungen mit Laravel 4 und anderen Frameworks, die ebenfalls nach dem MVC Schema aufgebaut waren.
Die Diskussion um dieses Thema war sehr kurz.
Die Frage war nicht ob, sondern wann – beziehungsweise wo – wir dieses Framework zur Anwendung bringen konnten.
Wie sich über die Jahre herausstellte, konnten wir Laravel für eine Vielzahl an Projekten verwenden. Tatsächlich ging das soweit, dass ein Großteil unserer Eigenentwicklungen über dieses Framework liefen. Unterwegs sind uns aber auch die Einschränkungen und die Probleme aufgefallen, die dieses Framework mit sich bringt. Manchmal waren das so gravierende Probleme, dass sie uns am Framework im Ganzen zweifeln ließen und wir uns schon nach Alternativen wie Symfony oder Django umgesehen haben.
Einige dieser Hürden konnten wir bezwingen andere umgehen wir seither.
Im Folgenden listen wir einige der Punkte auf, die uns damals Probleme gemacht haben, wie wir sie gelöst haben oder wie wir sie inzwischen umgehen.
Nested Relations
Laravel ist bekannt für seinen umfangreichen Query-Builder “Eloquent”. Eine Abstraktion auf dem PHP-Internen PDO Layer, welches auf SQL-Datenbanken wie MySQL, MariaDB, PostgreSQL etc. zugreifen kann. Es erlaubt den Zugriff auf die Datenbank durch ein einheitliches Interface. Zumeist deckt es all unsere Anwendungsfälle ab und selbst die, die wir eventuell nicht bedacht haben oder sich erst im späteren Verlauf ergeben.
Diese Vereinfachung von komplexen Queries oder verknüpften Einträgen ist in den meisten Fällen eine wirkliche Arbeitserleichterung und sorgt schlussendlich dafür, dass wir schneller das Produkt an den Markt bringen können. Allerdings mussten wir die Erfahrung machen, dass komplexe, verschachtelte Datensätze häufig zu ebenso verschachtelten Eloquent Relations führen. Wenn nicht aufgepasst wird, kann schnell eine tiefe Verschachtelung entstehen, die sowohl Performance als auch Wartbarkeit der Applikation in Mitleidenschaft zieht.
Es kann schnell passieren, dass Code wie dieser entsteht:
$user->contracts->customers->comments
Um derlei Missgeschicke in Zukunft zu verhindern, limitieren wir uns auf eine maximale Tiefe von 2 und bauen die Struktur im Allgemeinen sehr viel flacher auf.
Collection Performance
Laravel’s Collection sind ein praktisches Tool, um Datensätze verschiedenster Ausführungen zu manipulieren und seinen Bedürfnissen anzupassen. Viele der Methoden sind äußerst nützlich und lassen einen immer wieder nach diesen wünschen, wenn sie einmal nicht zur Verfügung stehen und man selbst eine ganze Reihe von Operationen in Standard PHP schreiben muss.
Allerdings mussten wir auch für uns feststellen, dass es einen Punkt gibt ab dem uns die Collections mehr behindert als genutzt haben.
Hier geht es wieder um die Performance. Wenn die Datensätze eine überschaubare Menge besitzen, ist es zumeist kein Problem die Collections zu verwenden, wenn wir allerdings wieder einmal komplexere Strukturen vorfinden wie etwa ein 400 Schritte tiefes, verschachteltes Array, dann stoßen Collections schnell an ihr Limit. Wir haben also bewusst auf Collection Objekte verzichten müssen, um die Performance, die mit nativen PHP Objekten bzw. Arrays einhergeht, nutzen zu können.
Siehe da Ladezeiten von 30 Sekunden wurden auf unter 4 Sekunden reduziert, konnten problemlos gecached werden und anschließend verwendet werden.
Database Abstractions + Packages
Laravels Ökosystem bietet tausende von Packages und für viele Probleme gibt es auch gleich mehrere Lösungen. Laravel bietet darüber hinaus auch praktische In-House Utilities wie Sanctum oder Breeze, die oft mühsame und repetitive Prozesse vorfertigt und dem Entwickler nur noch die Konfiguration übrig lässt. Ein Großteil unserer Projekte hat mindestens eine handvoll dieser Open-Source Pakete, weil sie das Entwickeln um ein so vielfaches erleichtern.
Nun ist es allerdings so, dass wir gerne auch einmal MongoDB verwenden für Datensätze bei denen wir es als lohnend empfinden. MongoDB wird als Nicht-Relationales Datenbanksystem nicht von Laravel out-of-the-box unterstützt. Dafür wird dann ein von der Community gepflegte Adapter genutzt. Wenn wir jetzt aber Packages haben, die mit der Datenbank interagieren und einem festen Schema folgen, um ihre Funktionalität bereitzustellen, ist diese meistens auf SQL-Datenbanken ausgelegt – also inkompatibel mit MongoDB. Das führte bei uns vermehrt dazu eigene Lösungen zu entwickeln und mehr Zeit und Aufwand als nötig in das Projekt zu stecken. Das macht es schwierig Laravel in seiner Vollumfänglichkeit ausnutzen zu können, wenn eine “wahre” Datenbank-Unabhängigkeit nicht gegeben ist.
Convenience & Magic
Laravel steckt voller Magic Methods und Convenience. Das macht es auf der einen Seite sehr angenehm schnell ein Model zu befüllen und abzuspeichern, oder die Authorization für eine Route zu setzen, aber weniger angenehm, wenn man mit einem Projekt mit vielen hunderttausenden Zeilen Code arbeitet und die Convenience dazu verleitet den Code unstrukturiert in einen Controller zu schreiben.
Wir mussten feststellen, dass wirklich große Projekte meistens unter Laravels lockerem System leiden. Die Möglichkeit das Meiste so zu tun wie es einem gefällt oder wie es gerade am geschicktesten erscheint, sorgt auf längerfristige Sicht für schlechte Wartbarkeit. Strikte Standards ermöglichen es einem konkreten System zu folgen, ohne unbewusste Nebenwirkungen zu verursachen und kryptische Bugs bereits im Keim zu ersticken.
Es ist nicht, dass diese Convenience keine Vorteile bietet. Im Gegenteil, wir verwenden sie gerne, weil sie uns erlaubt schnell und zuverlässig ans Ziel zu kommen. Dafür müssen wir auch in Kauf nehmen, dass es in komplexen Strukturen zu unvorhergesehenen Effekten kommen kann.
Fazit
Laravel gibt uns die Möglichkeit zum Rapid-Prototyping, was in einer Welt, die immer größere Projekte immer schneller umgesetzt haben will, um anschließend mit inkrementellen Verbesserungen weiterzumachen, sehr hilfreich ist. Es erlaubt für eine Vielzahl von Möglichkeiten von CLI-Anwendungen über APIs bis hin zu Shopsystemen. Es wird auf absehbare Zeit auch weiterhin ein absoluter Favorit unserer Entwickler bleiben. Convenience und Developer Experience lassen sich nur schwer schlagen mit einem Framework, dass alles daran legt diese Punkte zu fördern. Dennoch evaluieren wir jedes Mal kritisch, ob dieses Framework unsere Anforderungen hinreichend abdeckt oder sie verfehlt. Sollten wir zu viele Aspekte finden, die dem geplanten Projekt im Weg stehen, dann wählen wir eine Alternative.
Es ist die Wahl des richtigen Werkzeugs für den richtigen Job. Mit Laravel als Hammer mag vieles wie ein Nagel aussehen, aber am Ende sollte man immer gründlich planen, ob der vermeintliche Nagel nicht vielleicht doch eine Schraube ist.