Kategorie: PHP

  • KI erzeugt Code. Programmieren kann sie nicht.

    KI erzeugt Code. Programmieren kann sie nicht.

    „Wir brauchen keinen Entwickler mehr, dafür haben wir jetzt KI.“ Dieser Satz fällt gerade in vielen Unternehmen. Manche sagen ihn laut in Meetings. Andere denken ihn still beim nächsten Budgetgespräch. Und ein paar haben bereits entsprechend gehandelt: Entwickler entlassen, Stellen nicht neu besetzt, Projekte an Tools übergeben die Prompts in Code verwandeln.

    Das ist ein Fehler. Nicht weil KI nutzlos wäre. Sondern weil der Unterschied zwischen „Code erzeugen“ und „programmieren“ größer ist als er auf den ersten Blick aussieht.

    1. Was KI wirklich macht — und was nicht

    Eine KI beantwortet die Frage die ihr gestellt wird. Schreibt man „Erstell mir eine PHP-Funktion die Nutzereingaben validiert“, bekommt man eine PHP-Funktion die Nutzereingaben validiert. Das ist beeindruckend. Das ist auch nützlich. Aber es ist nicht dasselbe wie Programmieren. Unklar bleibt bei diesem Prompt auch, ob es die richtigen, zielführenden Validierungen sind. Und ob im Rahmen des Projekts vielleicht noch weitere Validierungen notwendig sein würden; oder zumindest hilfreich.

    Das liegt vor allem an einem Punkt: Die KI kennt nur den Kontext den man ihr explizit gibt — und der ist fast immer unvollständig. Nicht weil man es nicht besser wüsste, sondern weil beim ersten Prompt niemand daran denkt alles zu nennen: Serverumgebung, bestehende Architektur, Abhängigkeiten, Einsatzzweck, Sicherheitsanforderungen. Die KI baut sich diesen Kontext nicht selbst zusammen. Sie baut die Funktion für das was im Prompt steht und ignoriert alles was fehlt. Dabei greift sie auf clevere Algorithmen und Wahrscheinlichkeiten zurück. Daher passt das Ergebnis dann meist in abstrakten, generellen Anforderungem, aber nicht immer für die konkrete Situation.

    Programmieren bedeutet: Architekturentscheidungen treffen. Wissen welcher Ansatz in drei Jahren noch wartbar ist. Verstehen wie ein Server unter Last reagiert. Einschätzen welche Datenstruktur für diesen konkreten Anwendungsfall passt und welche nicht. Sicherheitsimplikationen durchdenken bevor jemand den Code anfasst. Und sicherlich auch die Edge Cases mit im Blick haben, die der Wahrscheinlichkeit nach nicht so relevant sind, aber wenn sie auftreten, furchtbar wirken können.

    All das steckt nicht im Prompt. All das ist das Handwerk hinter dem Code.

    2. Das Validierungsproblem — wer prüft ob der Code richtig ist?

    Eine Funktion die aus einem gegebenen Prompt entsteht, ist nicht zwingend eine vollständige integrative Lösung. Der entscheidende Test ist nicht „liefert sie das erwartete Ergebnis bei normaler Nutzung“ sondern: Was passiert wenn jemand sie falsch nutzt? Was passiert bei einer leeren Eingabe, einem unerwarteten Datentyp, einem Angreifer der gezielt nach Schwachstellen sucht? Und wie wirkt die Funktion im Zusammenspiel mit der gesamten Anwendung?

    Diese Fragen beantworten zu können setzt voraus zu verstehen was die Funktion im Inneren macht. Wer das nicht weiß, weiß auch nicht wo sie bricht. Und KI-generierter Code bricht — nicht öfter als von Menschen geschriebener Code, aber genauso. Der Unterschied ist: Bei menschlichem Code weiß der Entwickler warum. Bei KI-Code weiß niemand es mehr.

    Das ist kein Argument gegen KI als Werkzeug. Es ist ein Argument gegen KI ohne Review.

    3. Das Skalierungsproblem — Snippet ist nicht Architektur

    Ein CSS-Snippet per KI generieren: unkritisch. Eine Hilfsfunktion zum Formatieren eines Datums: unkritisch. Einen Login-Flow, eine Zahlungsschnittstelle, eine Rechteverwaltung per KI bauen und dann so deployen: fahrlässig.

    Der Unterschied liegt nicht in der Komplexität einzelner Codeblöcke. Er liegt darin wie viele Annahmen in eine Architektur eingeflossen sind, wie viele davon sicherheitsrelevant sind, und wie viele davon ein Nicht-Programmierer weder stellen noch beantworten kann. KI kennt diese Annahmen nicht. Sie beantwortet die Frage die ihr gestellt wird nicht die Fragen die man „vergessen“ hat zu stellen.

    4. Das Kontextproblem — KI hat kein Projektgedächtnis

    Große Softwareprojekte entstehen nicht an einem Tag. Sie wachsen über Wochen und Monate, mit Entscheidungen die aufeinander aufbauen, mit Architekturen die sich entwickeln, mit Kontext der sich anhäuft. Und manchmal auch mit Kehrtwenden, wenn sich herausstellt, dass der Ansatz nicht trägt oder sich die Rahmenbedingungen zwischenzeitlich geändert haben.

    KI hat davon nichts. Jede neue Session startet bei null. Wer täglich mit KI an einer komplexen Codebase arbeitet verbringt einen erheblichen Teil der Zeit damit die KI erst wieder in den Stand zu versetzen der nötig ist um sinnvollen Anschlusscode zu erzeugen: Hier ist die bestehende Struktur. Hier ist die bisherige Logik. Hier sind die Constraints die wir uns letzte Woche überlegt haben.

    Das ist kein theoretisches Problem; es ist ein täglicher Overhead der den versprochenen Geschwindigkeitsvorteil in vielen Projekten schlicht aufzehrt. KI beschleunigt isolierte Aufgaben. Komplexe, gewachsene Systeme sind das Gegenteil davon. Dazu kommt: KI arbeitet nicht deterministisch. Und nur weil ich ihr heute wieder alles rein gebe, was wir gestern erarbeitet haben, muss im Anschluss nicht dasselbe rauskommen, was gestern rausgekommen ist.

    5. Die fatale Unternehmensentscheidung

    Viele Unternehmen entlassen gerade Entwickler oft genug auch erfahrene Senior Developers. Die Begründung: KI übernimmt das. Was dabei übersehen wird: Genau diese Entwickler wären die einzigen die KI-generierten Code seriös reviewen könnten.

    Wer einen Junior fragt ob der Code sicher ist, bekommt „ja“; weil er es nicht beurteilen kann. Wer eine KI fragt ob ihr eigener Code sicher ist, bekommt ebenfalls „ja“. Was fehlt ist der erfahrene Blick der weiß was er suchen muss, der Edge Cases kennt, der Sicherheitslücken erkennt bevor sie ausgenutzt werden.

    Die Quittung für diese Entscheidungen kommt. Nicht heute. Aber in zwei, drei Jahren wenn Systeme die heute mit KI gebaut werden unter Last versagen, Daten verloren gehen oder Sicherheitslücken auftauchen die niemand mehr im Team schließen kann.

    Funfact übrigens: Auch das Entlassen aller Junior-Developer ist fahrlässig. Wer soll denn in einigen Jahren, wenn die „alten Hasen“ weg sind, die Architektur und den Code weiterverfolgen, wenn niemand mehr gelernt hat, wie „Senior Dev“ eigentlich geht!?

    Fazit — KI als Werkzeug, nicht als Ersatz

    KI ist ein leistungsfähiges Werkzeug für klar umgrenzte, überschaubare Aufgaben. Boilerplate-Code. Erste Entwürfe. Recherche. Erklärungen. Das alles ist genuiner Mehrwert.

    Was KI nicht ist: ein Ersatz für Architekturdenken, Sicherheitskompetenz, Projekterfahrung und Reviewkompetenz. Wer das verwechselt baut schnell und baut auf Sand.

    Der sinnvolle Einsatz von KI in der Softwareentwicklung setzt genau das Wissen voraus das angeblich überflüssig geworden ist: zu verstehen was hinter dem Code steckt.

    KI sinnvoll in deine Software integrieren

    KI-Unterstützung entfaltet ihren Mehrwert wenn sie von Entwicklern eingesetzt wird die den Output verstehen, prüfen und verantworten können. Wie das konkret aussieht und wie ich KI in bestehende PHP- und Laravel-Systeme integriere findest du auf unserer Seite zur KI-Integration.

  • SQL Performance und Datenintegrität

    SQL Performance und Datenintegrität

    Die 5 Fehler die ich immer wieder sehe

    Die Datenbank ist das Fundament jeder Anwendung. Das Frontend lässt sich neu bauen, Business-Logik refactoren, ein Framework austauschen — aber eine schlecht strukturierte oder langsame Datenbankschicht zieht die gesamte Anwendung nach unten. Und das meist schleichend: Nicht mit einem Knall, sondern mit Abfragen die nach und nach langsamer werden, mit Daten die irgendwann nicht mehr stimmen, mit einem System das unter Last in die Knie geht.

    Trotzdem bekommt die Datenbank in vielen Projekten die wenigste Aufmerksamkeit. Sie läuft, also ist sie gut. Bis sie es nicht mehr ist.

    In der Praxis sehe ich immer wieder dieselben Muster: Egal ob Neuprojekt oder gewachsenes System. Hier sind die fünf die mir am häufigsten begegnen.

    (mehr …)

    Die 5 Fehler die ich immer wieder sehe

    Die Datenbank ist das Fundament jeder Anwendung. Das Frontend lässt sich neu bauen, Business-Logik refactoren, ein Framework austauschen — aber eine schlecht strukturierte oder langsame Datenbankschicht zieht die gesamte Anwendung nach unten. Und das meist schleichend: Nicht mit einem Knall, sondern mit Abfragen die nach und nach langsamer werden, mit Daten die irgendwann nicht mehr stimmen, mit einem System das unter Last in die Knie geht.

    Trotzdem bekommt die Datenbank in vielen Projekten die wenigste Aufmerksamkeit. Sie läuft, also ist sie gut. Bis sie es nicht mehr ist.

    In der Praxis sehe ich immer wieder dieselben Muster: Egal ob Neuprojekt oder gewachsenes System. Hier sind die fünf die mir am häufigsten begegnen.

    (mehr …)
  • PHP-Dateien ohne PHP — warum das eine stille Performance-Falle ist

    PHP-Dateien ohne PHP — warum das eine stille Performance-Falle ist

    Bei der Analyse einer älteren WordPress-Installation fiel mir kürzlich etwas auf, das auf den ersten Blick harmlos wirkt: Dateien mit der Endung .php — die aber kein einziges Byte PHP enthalten. Stattdessen: XML-Strukturen, SVG-Markup, statische Inhalte. Alles prima, nur eben nicht PHP.

    Klingt nach Kleinigkeit. Ist es nicht.

    (mehr …)

    Bei der Analyse einer älteren WordPress-Installation fiel mir kürzlich etwas auf, das auf den ersten Blick harmlos wirkt: Dateien mit der Endung .php — die aber kein einziges Byte PHP enthalten. Stattdessen: XML-Strukturen, SVG-Markup, statische Inhalte. Alles prima, nur eben nicht PHP.

    Klingt nach Kleinigkeit. Ist es nicht.

    (mehr …)
  • Laravel 12 auf 13 — warum wir migriert haben, obwohl wir nicht mussten

    Laravel 12 auf 13 — warum wir migriert haben, obwohl wir nicht mussten

    Manchmal merkt man beim Arbeiten an einem neuen Projekt was einem an einem älteren fehlt. Genau das ist passiert: Bei neueren Laravel-Projekten haben wir direkt mit Version 13 gestartet und dabei Features entdeckt, die wir rückwirkend auch in unserem eigenen Produkt haben wollten.

    Allen voran: native Suche in verschlüsselten Datenbankspalten. Ein Feature das für datenschutzsensible Anwendungen konkret relevant ist — und das in Laravel 13 sauber im Standard mitkommt, ohne eigene Konstrukte drumherum.

    Dazu kam eine pragmatische Entscheidung: Lieber jetzt migrieren, bevor weitere Features dazukommen. Je mehr ein System wächst, desto mehr gibt es beim nächsten Mal zu testen und anzupassen. Wer das kennt, kennt auch den Moment wo man sich denkt: hätte ich das früher gemacht.

    Das Projekt hatte über die Zeit einige eigene Klassenkonstrukte und Besonderheiten im Front- und Backend angesammelt. Dinge, für die Laravel zwar die Basis gelegt hatte, die wir aber selbständig weiterentwickelt hatten. Entsprechend stand zu Beginn gefühlt eine sehr lange Checkliste im Raum.

    Am Ende zeigte sich: Es ging schneller als erwartet. Der Grund dafür hat weniger mit der Laravel-Version zu tun als mit dem Zustand des Projekts davor.

    (mehr …)

    Manchmal merkt man beim Arbeiten an einem neuen Projekt was einem an einem älteren fehlt. Genau das ist passiert: Bei neueren Laravel-Projekten haben wir direkt mit Version 13 gestartet und dabei Features entdeckt, die wir rückwirkend auch in unserem eigenen Produkt haben wollten.

    Allen voran: native Suche in verschlüsselten Datenbankspalten. Ein Feature das für datenschutzsensible Anwendungen konkret relevant ist — und das in Laravel 13 sauber im Standard mitkommt, ohne eigene Konstrukte drumherum.

    Dazu kam eine pragmatische Entscheidung: Lieber jetzt migrieren, bevor weitere Features dazukommen. Je mehr ein System wächst, desto mehr gibt es beim nächsten Mal zu testen und anzupassen. Wer das kennt, kennt auch den Moment wo man sich denkt: hätte ich das früher gemacht.

    Das Projekt hatte über die Zeit einige eigene Klassenkonstrukte und Besonderheiten im Front- und Backend angesammelt. Dinge, für die Laravel zwar die Basis gelegt hatte, die wir aber selbständig weiterentwickelt hatten. Entsprechend stand zu Beginn gefühlt eine sehr lange Checkliste im Raum.

    Am Ende zeigte sich: Es ging schneller als erwartet. Der Grund dafür hat weniger mit der Laravel-Version zu tun als mit dem Zustand des Projekts davor.

    (mehr …)
  • Primärschlüssel: Warum Auto-Increment IDs UUIDs in den meisten Projekten schlagen

    Primärschlüssel: Warum Auto-Increment IDs UUIDs in den meisten Projekten schlagen

    Die harmlos wirkende Anforderung

    Es fing mit einer simplen Aufgabe an: Eine AJAX-Abfrage sollte idempotent werden. Konkret bedeutete das — egal wie oft der Request gefeuert wird, das Ergebnis bleibt stabil und vorhersehbar. Kein Flackern, keine Race Conditions, keine doppelten Einträge die sich gegenseitig überholen.

    Die klassische Lösung: ORDER BY id. Fertig. Nächstes Problem.

    Nur dass es diesmal kein nächstes Problem gab. Zumindest nicht sofort.

    (mehr …)
  • PHP Warum truthy Prüfungen nicht immer wahr sind

    In PHP – wie natürlich auch in anderen Programmiersprachen – gibt es verkürzte truthy-Prüfungen. Ob, wie und wann man sie einsetzt muss aber genau überlegt sein. Das hilft am Ende nicht nur der Lesbarkeit sondern vermeidet auch Bugs, die auf Grund falsch gedachter oder vermeintlich logischer Prüfungen aufkommen.

    (mehr …)
  • PHPUnit-Tests: Wenn ein roter Test ein Erfolg ist

    Vor einiger Zeit berichteten wir schon mal darüber, dass wir angefangen haben, PHPUnit-Tests zu verwenden. Inzwischen ist das fast schon ein Standard bei uns geworden – Zeit nochmal einen Einblick in etwas Spannendes zu geben…

    Am Anfang steht natürlich immer die Frage: Was teste ich und wie?

    Ein Test existiert schließlich nicht nur, damit am Ende alles schön grün aussieht. Vielmehr geht es darum, Schwachstellen, Edge‑Cases und unerwartete Situationen vor der Produktivsetzung abzufangen.

    Die Erwartungshaltung ist klar


    Ich schreibe einen Test, lasse ihn laufen und arbeite mich durch die Fehler, bis alles grün ist. Wenn ich gut bin, geht das schnell. Wenn ich schlecht bin oder Folgefehler auftreten, dauert es eben länger.

    Und natürlich bringt mir ein Testpaket nur etwas, wenn ich mich nicht selbst belüge. Also: keine „nur einfachen Tests“, sondern Dinge, die realistisch auftreten können. Ein paar Beispiele:

    • Nachname bleibt in einem Anmeldeformular unbelegt
    • Telefonnummern in verschiedenen Schreibweisen -> wichtig! Die Frage hier ist kann mein Setup damit umgehen
    • vielleicht eine nicht konforme Emailadresse
    • bei API Routen und Co. durchaus mal Testen mit gültigem Auth, ungültigem Auth und keinem Auth. Kommt bei ungültigem und keinen Auth z.B. ein passender 401 bzw. 403 zurück? (Hier gern auch ein Hinweis auf unseren Artikel zum HTTP 401 vs. 403)

    Gerade letzteres ist vielleicht etwas, auf das man nicht zwingend direkt kommt. Aber gerade solche Dinge sind auch wichtig, weil sie in der Realität ein Einfallstor liefern. Eine API Route die unautorisierte Zugriffe erlaubt und vielleicht sogar noch wilde Daten rausgibt – absolut undenkbar.

    Aber muss man dafür immer gleich eine neue Testreihe schreiben?

    Nicht unbedingt! Wir hatten zu Beginn der Entwicklung hier erst mal die API Route lokal ohne Auth hinterlegt. Das ist unsere modale Vorgehensweise: Schritt für Schritt und immer nach dem Credo Form follows function!

    Was wir dann gemacht haben? Naja nachdem wir soweit waren das alle Tests „grün“ waren haben wir die Auth-Middleware aktiviert. Und dann? Einfach die Tests nochmal ausgeführt.

    Natürlich waren alle Tests rot und das war auch erwartbar. Das war hier aber auch das Ziel – so konnten wir ohne neue Tests direkt sagen: Die Auth funktioniert, die Routen liefern korrekt ihr 401 zurück..

    Also ja, unsere Tests waren rot.
    Aber nein, das ist nicht schlimm.
    Es war erwartbar – und in diesem Moment genau das, was wir wollten.

  • PHP – catch me if you can!

    In PHP werden natürlich auch Fehler behandelt. Wenn man kritische Fehler nicht abfängt, wandern sie weiter nach oben bis das Script irgendwann eben abbricht. Fast jeder Entwickler dürfte schon einmal eine fatal error message erhalten haben. Oder falls der Server nicht ganz so auskunftsfreudig ist – was natürlich auf Grund der Sicherheit einer Seite begrüßenswert ist – dann eben einfach nur einen 500 internal Server error.

    Beides trägt jetzt in der Regel in Produktivsystemen nicht gerade zur Begeisterung bei. Deswegen könnte der ein oder andere auch schon mal auf die Idee kommen um seinen Code einen try…catch Block zu bauen. Das bietet sich gerad bei potentiell sehr fehleranfälligen Programmpassagen an, hat aber manchmal noch zur Folge, dass der Fehler trotzdem auftritt. Das liegt daran das meistens dann eine solche Struktur genutzt wird:

    try
    {
       echo 50/0;
    }
    catch (Exception $e)
    {
       echo "Division durch null ist nicht erlaubt!";
    }
    

    Das Problem dabei: Nicht alles was auftauchen kann ist auch Exception. Eigentlich ist eine Exception eher sowas wie ein Spezialfall für einen Fehler der auftauchen kann. Deswegen sollte man in einem solchen Fall das ganze besser so aufbauen:

    try
    {
    echo 50/0;
    
    }
    catch (Throwable $e)
    {
       echo "Division durch null ist nicht erlaubt!";
    }

    Denn alles was auftreten könnte ist auf jeden Fall ein Throwable. Hier wird es jetzt korrekt abgefangen und das Programm steigt nicht mehr aus. Natürlich lässt sich das noch verfeinern und erhebt keinen Anspruch auf Vollständigkeit, kann aber in manchen Situationen die Rettung sein…

  • PHPUnit-Tests: Ersterfahrung

    PHPUnit-Tests gibt es schon seit über 20 Jahren. Bisher haben wir aber für unsere Entwicklungen eher auf „klassische“ Tests gesetzt. Heißt: Wir haben eine Software geschrieben und diese dann auf einem Testsystem „live“ ausprobiert. Um unsere Softwarequalität aber zu steigern und gleichzeitig Programmierstandards zu pflegen haben wir beschlossen in Zukunft bei der PHP-Entwicklung auch auf PHPUnit-Tests zu setzen. Ein erster Erfahrungseinblick.

    Ausgangssituation

    Wir hatten sowieso gerad ein neues Projekt am Start – diesmal wieder die Entwicklung eines WordPress-Plugins – und Ende letzten Jahres gerade auf der betterCode()-Konferenz für den Bereich PHP nochmal oder wieder von PHPUnit als „Test-Suite“ gehört. Da ja Stillstand bekanntlich den Tod bedeutet haben wir also mutig beschlossen, unsere Softwarequalität mithilfe dieses Tools einmal gehörig voranzubringen.

    Natürlich behalten wir auch unsere bisherige Testmodalität mit der Testinstallation bei. Schließlich soll ja auch das Aussehen und die Funktionalität im Browser getestet werden. Die PHPUnit-Tests werden wir aber zukünftig verstärkt einsetzen um bereits vorab generelle Tests aufzubauen, die einfach verhindern, dass wir schon mit ganz rudimentären Fehlern an den Start gehen, wie z.B. ein vergessenes Semikolon am Ende oder eine zu viel geöffnete oder geschlossene Klammer…

    Also wir hatten ein brandneues Projekt mit ohne irgendwas. Lokal haben wir einen Apache am Laufen und auch einen MariaDB-Server. Etwas googlen brachte uns dann noch den Hinweis, das es auch für WordPress eine Art „development“ Zweig gibt, mit dem man dann auch in PHPUnit testen können soll. Gesagt getan…

    Einrichten und erst mal Testen der Testumgebung

    Ja richtig: Bevor man sowas nutzen kann muss man das ja erst mal einrichten. Wir haben also erstmal das WordPress-Verzeichnis hingestellt und dann ging der Spaß auch schon los: Zum Einrichten hat uns das große Internet verraten, dass wir vermittels npm und grunt das ganze so aufsetzen können, dass es für unsere Unit-Tests läuft. Das war aber mal gar nicht so einfach. Es gab node und npm aber wir mussten zunächst die Pfade in die Umgebungsvariablen bringen bzw. verbessern, da node und npm ursprünglich über Visual Studio (manchmal entwickeln wir auch in C# ;))  auf das System kam und in dem Ordner noch nicht anständig wollte. nachdem wir das soweit hatten und auch alles sauber loslief, haben wir ins passende Plugin-Verzeichnis unser neues „Plugin“ kopiert und dann einen Ordner Tests angelegt.

    PHPUnit-Tests – jetzt aber!?

    Um erst mal warm zu werden haben wir erst mal ganz einfache Tests geschrieben. Wir wollten zunächst nur prüfen, ob unser Plugin aktiviert wurde, einen Menüeintrag im Adminmenu erzeugt und die Adminseite im Ansatz beim Aufruf der URL irgendwas an Inhalt erzeugt. Da kam aber schon die erste Frage in uns auf: Wie aktiviert man denn ein Plugin, wenn man gerade nicht die WordPress-typische Pluginseite vor der Nase hat? Etwas knifflig. Wir befragten also wieder das Internet und dort hieß es: Einfach in der Datenbank in den Optionen das Plugin unter den aktivierten Plugins mit eintragen. Ok – also auf die lokale DB mittels phpMyAdmin gegangen und: Die Datenbank ist ja leer? Moment – wir hatten doch vorhin mittels npm und grunt das ganze „installaliert“? Offenbar gereicht diese „Installation“ aber nicht soweit, dass auch eine DB ordentlich angelegt wird. Das Internet riet dazu, aus einer anderen frischen WordPress-Installation einfach die WordPress-eigenen Tabellen zu importieren. Gut also auch das erledigt.

    Jetzt aber zu den Tests? Noch nicht ganz. Unser geschriebener Test hatte als erstes Problem das die Ausgabe bereits erzeugt wurde, bevor das PHPUnit-Testgebilde seine Ausgabe gestartet hat. Ein klassisches Problem von Output vor den Headern. Aber auch sonst gab es haufenweise Probleme. Es genügte nicht die wp-load.php einzubinden und ggf. noch die wp-config. Es musste tatsächlich für alle benötigten Funktionen jeweils die passende wp-* Datei eingebunden werden in die Testklasse.

    Erstes Fazit

    Naja so ganz zufrieden sind wir mit den Bedingungen noch nicht. Eigentlich war nicht der Plan, alle Dateien „manuell“ einzubinden nur um dann einen Test fahren zu können. Der Plan war, eine Art WordPress-Instanz zu haben, in der man dann vielleicht noch mittels einfacher Hooks oder ähnlichem die benötigten Seiten und Eigenschaften aufrufen kann. Das hat bisher noch nicht geklappt. Aber vielleicht finden wir auch dafür demnächst nochmal eine etwas charmantere Konfiguration. Wir lernen ja noch… Und ach ja: Die Tests sind am Ende erfolgreich verlaufen. 😉