Sie haben beschlossen, Ihr eigenes Framework zu schreiben. War es das wert?





Wie die Klassiker sagten: "Ich wusste, dass wir früher oder später dazu kommen würden". Nach vielen Jahren des ruhigen Lebens mit Symfony in Arbeitern und ReactPHP in Haustierprojekten füge ich mich in die Erstellung meines Frameworks ein.



Aber seine Geschichte fängt gerade erst an. Und was ist mit denen, deren Idee auf das Produktionsniveau angewachsen ist, aber eine Nischenlösung geblieben ist? Ich habe jemanden gefunden, der die Antwort auf diese Frage kennt - den Autor und Hauptentwickler eines aspektorientierten Frameworks.



Hallo! Hier ist eine teilweise Abschrift meines Podcasts "Between the Brackets" - Interviews mit interessanten Menschen aus der PHP-Welt. In dieser Folge werden wir mit Alexander Lisachenko sprechen, dem Entwickler eines Java-basierten Frameworks, das häufig von Google gegoogelt wird.



Wenn Sie besser hören möchten, finden Sie in der Audioversion weitere technische Beispiele.


Höchstwahrscheinlich sind nicht alle von uns auf so etwas wie AOP gestoßen - aspektorientierte Programmierung in PHP. Und Sasha blieb stecken und traf seine eigene Entscheidung, dieses Ding in unsere Anwendungen zu ziehen.



Sergey Zhuk, Skyeng und DriftPHP: Fangen wir bei Null an - was ist AOP und welches Problem löst es?



Alexander Lisachenko, PHP Russland und Go! AOP : Die Idee ist nicht neu. AOP wurde bei Xerox erfunden, um das Problem der End-to-End-Funktionalität zu lösen. In der Java-Welt wird der Ansatz aktiv verwendet, um Funktionen wie Autorisierung, Authentifizierung, Caching, Protokollierung, Verwaltung von Funktionsumschaltungen und Leistungsschalter zu überprüfen.



Eine Vielzahl von Aufgaben kann unter Verwendung von Aspekten gelöst werden. Verwenden wir Beispiele:



  • . , . , , . — , .
  • — . , - . , , - .
  • : , , . Xdebug — .
  • , — circuit breaker, , , , .


Wenn wir uns die Anwendung ansehen, werden wir feststellen, dass solche Codefragmente überall zu finden sind und es nicht sehr bequem ist, damit zu arbeiten. Diese sogenannte End-to-End-Funktionalität ist in der gesamten Anwendung vorhanden.



Und es gibt keine gute Möglichkeit, es mit traditioneller objektorientierter Programmierung irgendwie herauszuarbeiten.



Ja, natürlich können wir versuchen, einen Dekorator zu nehmen - aber wenn unsere Klasse dieselbe Schnittstelle implementieren soll, müssen wir jede Methode direkt im Dekorator implementieren oder generieren. Das heißt, Dekoratoren für alle Klassen zu haben, die wir zwischenspeichern möchten.



Sergey Zhuk: Ok, ich habe es verstanden. Dafür gab es aber schon einige PECL-Erweiterungen, das Framework existierte sogar. Warum hast du dich entschieden, deine eigenen zu schreiben?



Aleksandr Lisachenko: Ja, Sie haben richtig bemerkt, dass es bereits eine Reihe von Lösungen gab. Aber wie es mir schien, hatten sie erhebliche Nachteile.



Einige der Lösungen versuchten, den Quellcode zu transformieren und einen bestimmten Hinweis sofort in eine bestimmte Klasse einzubetten - einen Code, der von einer Methode zur anderen wiederholt wird. Mit xlt erzeugen sie eine Klasse und setzen dort absolut alles ein. Im Allgemeinen ist es besser, diesen Code überhaupt nicht zu öffnen.) Die



zweite Klasse von Lösungen sind Erweiterungen. Zum Beispiel PHP AOP - es ist im Prinzip ziemlich funktionsfähig, aber es macht alles zur Laufzeit. Wenn wir einen Rat hinzufügen, scheint alles in Ordnung zu sein, aber wir fügen einen zweiten hinzu und die Geschwindigkeit nimmt proportional ab. Dementsprechend verlangsamt sich die Anwendung bei zehn Tipps, und wenn wir ein paar Dutzend weitere hinzufügen, ist das alles - eine Zeitüberschreitung ist garantiert.



Irgendwie kam es vor, dass ich sah, wie eine Idee namens "Filter" im Lithium-Framework implementiert wurde - ein solcher Prototyp moderner Middleware. Wir erstellen einige zuvor bekannte Punkte im Programm, und Filter können auf diese Punkte angewendet werden - sowohl vor als auch nach dem Aufruf. Diese Idee schien so interessant, dass ich mich entschied, eine Anwendung zu schreiben und die Querschnittsfunktionen mithilfe dieser Filter bereitzustellen. Ich begann zu studieren, wie es in Java gemacht wird.



Und mir wurde klar, dass es in PHP nicht möglich sein wird, es ohne weiteres zu implementieren. Das war wahrscheinlich der interessanteste Moment.



Im Allgemeinen war der gesamte Prozess des Schreibens des Frameworks ein ständiger Kampf mit "Nein" und "Unmöglich". Es scheint, dass ich grundlegende Dinge nicht umsetzen konnte, aber es war umso interessanter, mit ihnen umzugehen.



Sergey Zhuk: Ich kann einfach nicht anders als zu fragen. Warum AOP gehen? Die erste Veröffentlichung des Frameworks fand Anfang 2013 statt, die Go-Sprache existierte bereits damals und Sie hatten PHP. Es ist wie bei JavaScript und Java, oder?)



Alexander Lisachenko: Das erste Commit entspricht nicht dem Beginn der lokalen Entwicklung auf meinem Computer.) Zu dieser Zeit war Go noch nicht beliebt. Ich habe gegoogelt und gesehen, dass es eine Art interne Entwicklung von Google gibt, die eine eigene Nische einnimmt ... Und mich nicht darum gekümmert hat.



Ich habe den Namen des Frameworks selbst gewählt, basierend auf den internen Wünschen sozusagen. Von go - "go", "forward", "do".



Sergei Zhuk: Und dann gab es keine Gedanken zum Umbenennen?



Alexander Lisachenko: Formal ist der vollständige Name des Go! AOPPHP . Aber im Laufe der Zeit habe ich PHP entfernt, da es über Composer installiert wird und es anscheinend keinen Sinn macht, das Öl ölig zu machen.



Bisher bekomme ich zusätzlichen Datenverkehr: Viele Leute, die versuchen, AOP for Go zu finden, landen auf meinem PHP-Framework. Vielleicht muss in einer zukünftigen Version betont werden, dass es nicht um Go geht. Bisher hat diesbezüglich niemand ein Problem mit GitHub gestartet. Es gab auch keine Beschwerden von Google oder der Community.



Sergey Zhuk: Ok, wie wird dies aus Sicht des Client-Codes implementiert? Hier habe ich eine Anwendung, zum Beispiel auf Laravel, es gibt einige Integrationen mit Diensten von Drittanbietern, ich möchte diese Anrufe protokollieren.



Alexander Lisachenko: Für Laravel gibt es bereits ein spezielles Modul. Er wird alles, was Sie brauchen, in das System einbauen und konfigurieren. Sie müssen einen Aspekt schreiben - es wird ein Dienst sein, Sie werden ihn markieren und er wird automatisch vom AOP-Kern aufgenommen. Genau in diesem Aspekt müssen Sie verstehen, an welchen Punkten der Anwendung, in welchen Klassen und Methoden Sie die Caching-Funktionalität implementieren möchten. Sie können eine Methode direkt mit einer Signatur angeben (die Option ist jedoch nicht sehr flexibel, sodass die Methode umbenannt werden kann, aber im Aspekt verbleibt), oder Sie können die Methode mit einer Anmerkung markieren. Die zweite Option ist flexibler: Wenn ein Cache erforderlich ist, markieren Sie sie einfach als zwischenspeicherbar, und die Engine übernimmt das Caching für Sie und ruft den Rückruf auf, der im Code des Aspekts enthalten ist.



Zum Zeitpunkt des Ladens Ihrer Klasse mit Composer greift das Framework ein und prüft, ob im Cache eine fertige Version für diese Klasse mit einem eingebetteten Aspekt vorhanden ist. Wenn ja, gibt er es sofort zurück, zur Laufzeit werden keine zusätzlichen Prüfungen durchgeführt. Wenn es keinen Cache gibt, erstellen wir einen AST-Baum und erstellen über diesem Baum eine Reflexionsklasse, ohne sie jedoch in den Speicher zu laden. Und in diesem Moment können wir es so ändern, wie wir es wollen, dh den Aspektcode innerhalb dieser Klasse weben.



Ich mag keine Nudeln in Aspekten und habe beschlossen, die Klasse in zwei Teile zu teilen.



Die ursprüngliche Klasse bleibt praktisch unverändert - nur der Name ändert sich. Und eine zweite Klasse wird mit dem ursprünglichen Klassennamen angezeigt, der die Hauptklasse erweitert und bei Bedarf mehrere Methoden überschreiben kann.



Warum eigentlich Vererbung? Es gibt viele Methoden und Klassen, die die Instanz zurückgeben. Zum Beispiel die bekannte Kettenmethode: Wir rufen die Methodenkette für das Objekt auf und geben $ this zurück. Wenn wir dekorieren, funktioniert der erste Anruf, aber dann fällt der Aspekt ab. Zusammen mit der Vererbung wird Speicher gespeichert, da sich noch eine Instanz im Speicher befindet.



Sergey Zhuk: Bei all dieser Architektur, dem Motor, haben Sie von Anfang an an alles gedacht oder?



Alexander Lisachenko:Es gab viele Dinge, in die man eintauchen konnte. Zum Beispiel war ich mit AST nicht sehr vertraut, deshalb habe ich viele Disziplinen studiert, die mit der Beschreibung von Grammatiken zusammenhängen. Und wenn Sie sich mein Framework ansehen, dann implementiert mein Pointcut eine vollwertige Grammatik und hat eine eigene Syntax - dies ist wahrscheinlich eine der großen Errungenschaften. Sie können so viele komplexe Ausdrücke schreiben, wie Sie möchten, z. B. "Aufruf einer öffentlichen Methode, die nicht mit Asset beginnt, implementiert die Schnittstelle so und so im Innenraum von so und so".



Außerdem habe ich viel in PHP gegraben. Ich habe beobachtet, wo Erweiterungen sind und wie sie funktionieren. Irgendwo saß ich mit Profiling, optimierte etwas, optimierte: Aber jetzt, wenn Sie nur das AOP-Framework verbinden, wird die Anwendung einige lustige 7-10 Millisekunden hinzufügen. Auf der Ebene der klassischen 100-Millisekunden-Antwort ist es sogar nicht wahrnehmbar, dass ein so großes Framework unter der Haube aufgerufen wird.



Sergey Zhuk: Gibt es eine Spezifität für verschiedene PHP-Frameworks?



Alexander Lisachenko: Grundsätzlich wurde das AOP-Framework als allgemeine Bibliothek konzipiert, die keine spezifische Bindung erfordert. Die Hauptbedingung ist die Verwendung von Composer. Aber es ist nicht sehr freundlich mit Symfony.



Es gibt zu viel schwarze Magie in Symfony, und wenn sie mit der Magie in meinem Framework kollidiert, gewinnt die stärkste, Symfony.



Im Allgemeinen besteht die Idee von Symfony darin, dass es einen Container gibt. Sie müssen ihn verwenden und dürfen keine separaten Frameworks erfinden, um die AOP-Funktionalität zu erhalten. Es gibt traditionellere Möglichkeiten: Fügen Sie ein Bundle hinzu, z. B. JMS AOP oder mein Symfony Go AOP-Bundle .



Sergey Zhuk: Lassen Sie uns über die Community und die Konkurrenten sprechen. Hast du sie?



Alexander Lisachenko: Soweit ich weiß, gibt es jetzt drei Rahmenbedingungen. Da ist Ray. Aop, aber es wird für die Produktion nicht nützlich sein, da es nicht weiß, wie man effektiv mit Composer arbeitet. Die Autoren von Flow servieren ihren Rahmen mit der Sauce, die wir hier AOP haben. Neben den chinesischen Frameworks gibt es noch etwas anderes: Auf Swoole befinden sich Gurte - aber dies alles auf der Ebene der Erweiterungen, und Erweiterungen können von Administratoren aus Sicherheitsgründen nicht übersehen werden. Ich habe immer noch ein klassisches Framework und es bleibt in jeder Version am Leben.



Wie für die Gemeinschaft. Es gibt wahrscheinlich nur vier Leute, die gut verstehen und verstehen: ich, ein Mann aus Serbien, und zwei Leute aus meinem früheren Job, die an allem teilgenommen haben, was ich getan habe. Natürlich habe ich ihnen alle meine Entwicklungen und Ergebnisse gezeigt. In den letzten Monaten, als ich meinen Job gewechselt habe, habe ich sehr wenig Aufwand und Energie in Open Source gesteckt, aber es lebt und arbeitet autonom.



, - Z-Engine — c , , PHP.



Ich plane, sobald die Zeit frei ist, weiter an der Z-Engine zu arbeiten und die nächste Version des Frameworks zu erstellen, basierend auf den internen Strukturen der Sprache selbst. Es wird fast wie Java AspectJ funktionieren. Das Ziel ist es, in PHP 8 dorthin zu gelangen.



Sergey Zhuk: Dies ist fast eine vollständige Neufassung des Frameworks?



Alexander Lisachenko: Nein, ich habe alles zerlegt. Nur der Code-Injection-Prozess ändert sich: Es gibt buchstäblich einige Klassen, die für die Bearbeitung einer bestimmten Klasse verantwortlich sind. In diesem Fall erstellt diese Klasse keine Dateien im Cache mit unterschiedlichen Strukturen, sondern ändert zur Laufzeit den OPcache und die PHP-Strukturen im Speicher.



Sergey Zhuk: Und wie ist die allgemeine Einstellung der PHP-Community zu diesem Thema? Ich mag asynchrones PHP, es lässt nur wenige Menschen gleichgültig. Wie geht es dir damit?



Alexander Lisachenko: Es wird immer diejenigen geben, die sagen, dass wir dies ohne AOP tun können. Warum brauchen wir es in Anwendungen ? Meine Antwort lautet: Wenn Sie nicht in einem Unternehmen arbeiten, brauchen Sie die Aspekte nicht. Und wenn Sie denken, dass Sie ein Unternehmen haben, aber einen Service und 2-3 Entwickler haben, funktioniert dies auch nicht für Sie.) AOP funktioniert gut in Teams, in denen mehrere Dutzend Personen anwesend sind. Jeder von ihnen schreibt in seinem eigenen Stil. In der Regel mehrere Anwendungen und in der Regel eine Microservice-Architektur.



Ich weiß mit Sicherheit, dass es eine Reihe großer Unternehmen gibt, die das Framework zu Hause verwenden: Französisch, Russisch. Es kommt vor, dass einige Nachrichten mit Dankbarkeit per Post eingehen: Sie sagen, sie dachten, wir hätten einen Monat Arbeit, aber sie haben Ihr Framework ausgegraben und diese Aufgabe in ein paar Tagen erledigt. Die Jungs haben einen Monat der Arbeit ihrer Entwickler gespart, das ist großartig.



Sergey Zhuk: Führen Sie Bildungsaktivitäten durch? Ihr Framework ist alt genug, aber ich habe schnell nach Tutorials gesucht - sparsam. Es scheint, als würden zehn Leute gefragt, was AOP ist, neun werden sagen, dass sie es nicht wissen.



Alexander Lisachenko: Ja, das stimmt.



Sergey Zhuk: Obwohl es vielleicht gut ist, dass sie es nicht wissen?



Alexander Lisachenko:Dies ist ein strittiger Punkt.) Aber es gibt ein Problem, das ich hatte und immer noch habe - es ist die Dokumentation. Ich schreibe von Natur aus keine Dokumentation. Ich kann coole Lösungen schreiben, ich kann einige ungewöhnliche Dinge erfinden, Bibliotheken, aber mit Dokumentation ist es nur ein Schmerz.



Sogar in einem Moment schlug mir ein Freund aus Serbien vor: Lass uns schreiben. Und er fing sogar an, es zu schreiben, aber nach einer Weile endete auch die Sicherung ... Und so stellte sich heraus, dass sie nicht reich an Dokumentation sind, sagen wir mal.



Sergey Zhuk: Also, natürliche Auslese? Die hartnäckigsten, die geklettert sind, graben tiefer, sie benutzen es ...



Alexander Lisachenko: Ja, und das sind die Leute, die ein ausreichendes Niveau haben, um nicht zu vermasseln.



Sergey Zhuk: Haben Sie Feedback von Leuten erhalten, die das Framework auf eine Weise verwendet haben, die Sie nicht erraten hätten?



Alexander Lisachenko: Ja, es gab solche Fälle. Zum Beispiel Mikhail Bodnarchuk, der AspectMock geschrieben hat . Er nahm den Rahmen und erkannte, dass er damit das Problem lösen konnte, endgültige Methoden, Klassen und sogar Funktionen zum Einweichen zu bringen.



Eine andere Geschichte wurde von Leuten geworfen, die eine alte Anwendung überarbeitet haben und keine Tests hatten - im Allgemeinen ist alles klassisch. Mit Hilfe meines Frameworks haben sie aufgezeichnet, womit jede einzelne Methode aufgerufen wird, und einen globalen Aspekt erstellt. Vor dem Aufrufen aller öffentlichen Methoden in allen Klassen in diesem Ordner wurde geschrieben, was aufgerufen und was zurückgegeben wird: welche Typen, welche Werte. Dann haben sie begonnen, diese Anwendung unter Last auszuführen, um alle möglichen Zustände des Codes zu erhalten. Sie erhielten einen automatischen Satz von Werten, die für jede der Methoden zulässig sind, und geben Werte zurück. Das heißt, sie machten eine Momentaufnahme des gesamten Zustands und setzten dann den umgekehrten Aspekt, der die Methode aufrief und prüfte, ob sich die Logik geändert hatte.



Tatsächlich gelang es ihnen, automatisches Code-Refactoring zu implementieren, ohne es mit Tests abzudecken.



Es war eine so coole Idee, dass ich einige Zeit darüber nachdachte, wie ich ein Tool für Legacy-Anwendungen erstellen kann, damit ich alle Klassen einfrieren, sehen kann, wie und wie sie aufgerufen werden, und dann beim Refactoring überprüfen kann, ob die vorhandenen Beziehungen nicht unterbrochen werden. Die Implementierung in einem Tool, das ausgelagert werden könnte, hat jedoch noch nicht funktioniert.



ps Danke, dass Sie das Ende gelesen und angehört haben! Weitere Podcast-Folgen finden Sie hier .



All Articles