Contact salesFree trial
Blog

Verknüpfte Daten in PHP beherrschen: Graphen und Algorithmen

SymfonyConPräsentationGitDatenCLIRostAutomatisierung
Teilen Sie

Video-Transkript

Wir haben ChatGPT verwendet, um die Grammatik und Syntax des Transkripts zu verbessern.

Hallo und herzlich willkommen zu diesem fast letzten Termin des Tages. Heute werden wir über Diagramme sprechen. Und um es noch einmal genau zu sagen - nicht die bunten Graphen, sondern die langweiligen Graphen, bei denen es nur um Punkte geht und wie sie miteinander verbunden sind.

Mein Name ist Christian, und ich arbeite derzeit bei Shopware, wo ich der ansässige Verrückte bin, der alle möglichen verrückten Experimente durchführt und mit jeder Technologie arbeitet, die für die Zukunft interessant sein könnte oder noch nicht erforscht wurde, wie zum Beispiel Graphen. Ich bin auch auf Mastodon aktiv, du kannst dich dort also gerne mit mir in Verbindung setzen, wenn du willst.

Heute geht es um Tangles, also darum, wie Dinge miteinander verbunden sind, wenn man sie zusammenfügt, und wie man sie dann wieder herausbekommt. Es gibt verschiedene Arten von Verbindungen, wirklich. Wie der Titel des Vortrags "Gefangen im Netz" schon sagt, geht es um Netze - sie sind verworren, es gibt Städte von oben, und es gibt Karten. Sie alle haben etwas gemeinsam: Sie sind visuell belebt und stark miteinander verbunden. Wir werden das weiter erforschen.

Das Entwirren von Strukturen wie diesen ist kein neues Thema. Es gibt sie schon seit Hunderten von Jahren. Das erste Problem dieser Art sind zum Beispiel die Sieben Brücken von Königsberg, dem heutigen Kaliningrad, die 1736 entstanden sind. Die Frage lautete: "Wie kann ich mich durch die Stadt bewegen und jede Brücke nur einmal überqueren?"

Was als betrunkene Frage bei ein paar Bier am Abend begann, entpuppte sich als mathematisch tiefgründig, denn es gibt keine einfache oder elegante Lösung für dieses Problem mit den üblichen Mitteln wie Geometrie oder Algebra. Der Mathematiker Leonard Euler, den Sie vielleicht kennen, weil er eine Menge Dinge gelöst hat, hatte die Idee, über die Teile dieses Problems nachzudenken. Die Teile sind Orte, an denen man sich befinden kann - in diesem Fall die kleine Insel, die große Insel und die beiden Seiten des Flusses. Die Brücken, die sie verbinden, wurden zu Verbindungen.

Dieses Problem bezog sich nicht mehr auf ein geometrisches Modell. Es ging nur noch um Punkte, die durch Kanten verbunden waren. Euler fand heraus, dass man, um von einem Ort zum anderen zu gelangen, einen Knotenpunkt betreten, ihn verlassen und einen anderen betreten muss. Das bedeutete, dass jeder Knoten eine gerade Anzahl von Verbindungen brauchte, weil man eine Verbindung zum Eintritt und eine weitere zum Austritt brauchte. Wenn ein Knoten eine ungerade Anzahl von Verbindungen hat, kann man sich nicht über sie alle bewegen, ohne eine Kante zweimal zu benutzen.

Euler bewies, dass es mathematisch nicht möglich ist, einen Weg zu finden, der jede Brücke einmal überquert. Aber wie beschreiben Mathematiker heute Graphen? Theoretisch ist das ganz einfach - eine Funktion von Eckpunkten, Kanten und Zuordnungen. Aber in der Praxis ist es nicht so einfach, deshalb gebe ich eine kurze Einführung.

Also, "V" steht für Scheitelpunkte. Scheitelpunkte sind die Punkte, die Sie verbinden - einfach Punkte mit einer ID, einer einzelnen Zahl. Es gibt zum Beispiel Scheitelpunkt eins, Scheitelpunkt zwei, Scheitelpunkt drei und so weiter. Dann gibt es noch die Kanten. Kanten sind auch nur Identitäten, aber sie verbinden zwei Scheitelpunkte. "F" ordnet die Identität der Kanten den beiden Scheitelpunkten zu, so dass man zwei Scheitelpunkte durch eine Kante verbinden kann.

Eine Kante verbindet zwei Teile. Ein Beispiel: Sie haben Scheitelpunkt eins und Scheitelpunkt zwei, und die Scheitelpunkte stammen aus der Menge aller Scheitelpunkte in Ihrem Graphen. Immer noch einfach? Nicht wirklich, aber es gibt eine menschliche Sichtweise - eine nicht-mathematische Sichtweise. Scheitelpunkte sind Punkte, und Kanten zeigen, wie diese Punkte miteinander verbunden sind. In Diagrammen geht es nur darum, wie die Datenpunkte miteinander verbunden sind. Sie haben keine Koordinaten, wie man sie in der Grafik oder Computergrafik erwarten könnte. Die Koordinaten sind willkürlich, und die Art und Weise, wie sie in den Raum gestellt werden, dient nur dazu, dass man sie als Mensch leichter versteht.

Das ist es, was Netze, Städte und Karten miteinander verbindet: Sie alle können dargestellt und in Diagramme umgewandelt werden. Jedes Mal, wenn sich zwei Straßen treffen, kann man das als Punkt beschreiben, wobei die Straßen die Kanten sind. Auf diese Weise können Tools wie Google Maps mithilfe von Graphenalgorithmen Ihren Weg von A nach B verfolgen und Ihnen eine Wegbeschreibung geben.

Daran sehen wir, dass Graphen eine Form der Navigation implizieren. Aber es geht nicht nur um physische Navigation. Als Webentwickler denken wir selten darüber nach, welche Straßen wir nehmen müssen, um von einem Ort zum nächsten zu gelangen. Womit wir aber ständig zu tun haben, sind Daten. Und an dieser Stelle möchte ich einen Bezug zu einem Tool namens JQ herstellen.

Wie viele von Ihnen kennen JQ? Okay, ich sehe viele Hände, aber nicht alle. Die kurze Erklärung ist: JQ ist ein Kommandozeilentool, mit dem man JSON-Daten leicht bearbeiten, lesen und ändern kann. Es hat seine eigene kleine Syntax für den Zugriff auf und die Änderung von Daten in JSON-Objekten. Was ich Ihnen zeigen möchte, ist, dass diese Syntax nichts anderes ist als die Navigation durch ein Stück JSON.

Auf der linken Seite sehen Sie eine zufällige API-Antwort. Sie enthält zwei Entitäten, jede mit einem Namen und einer Adresse. Das JQ-Skript greift auf diese Daten zu, und auf der rechten Seite sehen Sie die Daten, die wir herausholen wollen. Die roten Pfeile zeigen an, wo wir uns in den Daten befinden. Spielen wir also JQ - ich bin jetzt der Computer.

Wir beginnen mit dem Zugriff auf das Root-Element, das JSON-Objekt der obersten Ebene. Dann gehen wir zum ersten benannten Attribut, das "data" heißt und ein Array enthält. Wir greifen auf das erste Element im Array zu, das ein JSON-Objekt mit einem Adressfeld ist, das wiederum die Straße enthält. Am Ende unseres JQ-Skripts lautet der zurückgegebene Wert "Test Street".

So sieht er als Diagramm aus. Das ist die "Google Maps"-Ansicht dieser Datenstruktur. Sie können den Verbindungskanten sinnvolle Namen geben und einen Pfad durch die Daten zeichnen, indem Sie Ihre JQ-Anweisung in diese abstrakte Struktur - einen Strukturpfad - umwandeln. Das ist es, was ich zeigen wollte: Die Struktur der Daten hat nichts mit den Daten selbst zu tun. Sie können die beiden vollständig voneinander trennen und nur mit der Struktur arbeiten.

Warum ist das so wichtig? Weil Sie Unterelemente dieser Pfade verwenden können. Sie könnten zum Beispiel sagen: "Ich möchte nur die Straße jeder Adresse abrufen". Sie navigieren zum Adressfeld, rufen das Straßenfeld ab und verwenden diesen Teilgraphen, um noch größere Datensätze abzufragen. Alles, was nicht auf dem roten Pfad liegt, ist für Sie uninteressant.

Aber bevor wir uns zu weit vorwagen und uns in der Theorie verirren, kommen wir zurück zu etwas, mit dem wir häufiger zu tun haben: Objekte gegenüber Tabellen. Dies ist ein häufiges Problem für Entwickler - es hat sogar einen Namen: objektrelationale Mapper (ORMs). Keine Sorge, in diesem Vortrag geht es nicht um ORMs, sondern um die Leute, die sie pflegen müssen, zu denen auch ich gehöre.

Das Problem ist, dass Objekte oft nur im Speicher existieren. Wir machen uns normalerweise keine Gedanken über die Reihenfolge, in der sie erstellt wurden. Aber wenn wir diese Objekte in Datenbanktabellen umwandeln wollen, haben wir bereits alle Objekte, die wir haben wollen, und wir müssen dann herausfinden, wie wir sie in die Datenbank bekommen. Und warum? Weil die Datenbank ein relationales Modell hat, und dieses Modell verwendet Fremdschlüssel. Fremdschlüssel bedeuten, dass man auf keine Daten verweisen kann, die der Datenbank nicht bereits bekannt sind.

Bei Shopware hatten wir ein besonderes Problem, als wir eine API schreiben wollten, die es Entwicklern ermöglicht, Daten in einem benutzerfreundlichen Format, wie dem folgenden JSON-Objekt, in unsere Datenbank einzufügen. Ein Beispiel: Sie möchten ein "Awesome Product" mit einigen Kategorien in die Shopware-Datenbank einfügen. Das Ziel der Entwickler war es, Bestandsdaten in diesem freundlichen Format bereitzustellen.

Wir haben jedoch schnell festgestellt, dass man kein Produkt mit Kategorien erstellen kann, wenn diese Kategorien nicht bereits in der Datenbank vorhanden sind. Sie müssen die IDs dieser Kategorien kennen, denn ohne eine ID können Sie keine Einfügungen in die Datenbank vornehmen. Es müssen Fremdschlüssel existieren.

Diese Situation erinnerte mich an einen gerichteten Graphen. Ich begann, dies als ein Problem mit einem gerichteten Graphen zu betrachten, was uns dann dazu brachte, die Daten logisch zu sortieren. Doch zunächst sollten wir definieren, was ein gerichteter Graph ist.

Ein gerichteter Graph ist ein Graph, bei dem die Richtung der Verbindungen wichtig ist. In einer Datenbank kann beispielsweise eine Tabelle über eine andere Tabelle durch einen Fremdschlüssel Bescheid wissen, aber der umgekehrte Fall darf nicht eintreten. Andernfalls würde ein Kreislauf entstehen. Ein gerichteter Graph bedeutet, dass die Verbindung von Knoten A zu Knoten B nicht dieselbe ist wie eine Verbindung von B zu A. Im Gegensatz dazu ist bei einem ungerichteten Graph die Richtung egal - die Verbindungen sind gegenseitig.

Da wir nun wissen, dass wir es mit einem gerichteten Graphen zu tun haben und Abhängigkeiten lösen müssen, können wir darüber nachdenken, wie wir den Graphen ordnen können. Glücklicherweise gibt es dafür bereits Algorithmen. Sie können"topologische Sortierung" auf Wikipedia nachschlagen. Diese Methode wird auch von Tools wie Dependency Injection Containern verwendet, um herauszufinden, in welcher Reihenfolge Objekte für Dependency Injection instanziiert werden sollten.

Ich möchte Ihnen einen Algorithmus namens Kahns Algorithmus zeigen, der die Reihenfolge des Einfügens von Daten aus dem JSON-Format bestimmt, das ich Ihnen zuvor gezeigt habe. Um dies effizient zu tun, müssen wir jedem Knoten einen Wert zuweisen, der die Anzahl der eingehenden Verbindungen (oder Kanten) angibt.

Was ist eine eingehende Verbindung? Das ist die Stelle, an der der Pfeil auf einen Knoten zeigt. Weisen wir unserem Diagramm Werte zu. Für das "Awesome Product" am Anfang des Dokuments gibt es keine eingehenden Knoten - keine eingehenden Verbindungen. Unsere Kategorien "Tolle Dinge" und "Produkte" haben jeweils eine eingehende Verbindung und erhalten daher den Wert eins.

Nun können wir Kahns Algorithmus anwenden. Zunächst wählen wir einen Knoten mit null eingehenden Verbindungen aus. Wenn es keinen solchen Knoten gibt, liegt ein Zyklus vor, mit dem wir uns später beschäftigen werden. Gehen wir zunächst davon aus, dass die Benutzereingabe korrekt ist. Wir haben einen oder mehrere Knoten mit null eingehenden Kanten. Wir wählen den ersten aus - das wird der letzte sein, den wir in die Datenbank einfügen müssen.

Dann entfernen wir seine Kanten aus dem Graphen und vermindern die Anzahl der eingehenden Kanten für die verbundenen Knoten. Das Ergebnis ist, dass zwei weitere Knoten nun keine eingehenden Verbindungen mehr haben. Wir wiederholen den Vorgang, indem wir einen Knoten mit null eingehenden Kanten auswählen, ihn in den Stapel legen und die eingehenden Kanten der verbundenen Knoten dekrementieren.

Am Ende erhalten wir eine Einfügereihenfolge. Von links nach rechts: "Root", "Products", "Awesome Things" und schließlich "Awesome Product". Mit dieser Reihenfolge können Sie die Daten in die Datenbank einfügen, ohne Fremdschlüssel-Beschränkungen zu verletzen, da dies die Reihenfolge ist, in der die Entitäten voneinander abhängen.

Aber was ist mit Zyklen? Wie gehen wir mit diesen um? Meine Antwort lautet: Sie können sie googeln. Da wir nun wissen, wie wir unser Problem als Diagramm modellieren können, können wir nachschlagen, wie man Zyklen in einem Diagramm behandelt. Wenn Sie "Zykluserkennung in einem Graphen" googeln, finden Sie Algorithmen wie die Deep-First-Suche(DFS).

Nehmen wir ein Beispieldiagramm. Ich habe absichtlich eine Schleife eingefügt, um zu zeigen, wie wir dies mit der Tiefensuche erkennen können. Wir wählen einen Startknoten - sagen wir, unser aktueller Knoten ist "Handle Basket". Auf der linken Seite haben wir unseren Einfügestapel. Wir untersuchen den Knoten und fügen ihn dem Stapel hinzu. Wir überprüfen auch seine Nachbarn, die die nächsten zu untersuchenden Knoten sind.

Unser Knoten "Produkte" hat eine Verbindung zum Knoten "Wurzel", also fügen wir "Produkte" zum Stapel hinzu und verschieben "Wurzel" in die Liste "Als nächstes zu betrachten". Wir machen das Gleiche noch einmal, und dann kommen wir zu "Awesome Things". Wenn wir uns die Nachbarn von "Awesome Things" ansehen, sehen wir, dass sie auf "Products" zurückverweisen, wodurch ein Zyklus entsteht.

Warum ist die Erkennung von Zyklen nützlich? Weil Sie nun entscheiden können, was Sie mit dem Zyklus machen wollen. In einigen Bereichen kann es sinnvoll sein, die Daten zu betrachten und zu entscheiden, dass einer der Knoten zuerst verarbeitet werden sollte. Oder, je nach Zielsetzung, kann man die Verbindung vorübergehend unterbrechen und später wiederherstellen. In unserem Beispiel handelt es sich jedoch um unterbrochene Daten, die Sie nicht in eine Datenbank übertragen können. Dazu müssten Sie die IDs der Zeilen kennen, bevor sie überhaupt existieren. In diesem Fall können Sie den Benutzer also darüber informieren, dass es einen Zyklus gibt, der "Produkte", "Wurzel" und "Tolle Dinge" verbindet, wodurch die Daten nicht eingefügt werden können.

Mit diesem Ansatz haben Sie alle Werkzeuge, die Sie brauchen, um JSON-Daten aus einer externen Quelle zu übernehmen und sie korrekt und geordnet in eine Datenbank einzufügen.

Aber wir sind noch nicht fertig. Es gibt noch einen weiteren Graphen, den wir alle kennen - einige von uns vielleicht ein bisschen zu gut - und das ist Git. Git ist eigentlich ein Baum, und ein Baum ist ein Graph. Git ist ein gerichteter Baum, weil er von der Zukunft zur Vergangenheit arbeitet.

Dies ist ein Beispiel für einen Git-Baum. Ganz oben befindet sich unser Haupt-Commit - wo wir uns gerade befinden. Dort oben gibt es einen Zweig, der einen Punkt markiert, an dem jemand Änderungen vorgenommen hat. Wir haben einen Merge-Commit, der zwei Eltern hat, und ganz unten ist die Wurzel. Alles ist von jetzt an mit der Vergangenheit verbunden.

Das Interessante daran ist, dass wir diese Informationen, diese Geschichte unseres Projekts, nutzen können, um unsere Architektur zu optimieren. Sie fragen sich vielleicht, warum wir jetzt über Architektur sprechen, aber die Antwort ist: Auch das ist nur ein Graphenproblem. Wenn man bestimmte Algorithmen kennt, kann man nützliche Informationen extrahieren.

Wie machen wir das? Indem wir unsere Git-Daten in ein soziales Netzwerk umwandeln. In diesem Zusammenhang bedeutet ein soziales Netzwerk, dass wir tonnenweise Dateien haben und diese Dateien miteinander "reden". "Reden" bedeutet, dass sie gemeinsam geändert werden. Ein Commit ist eine sinnvolle Änderung an der Codebasis. Ein Commit kann zum Beispiel die Dateien A, B und C erstellen oder ändern.

Der Root-Commit hat die ersten beiden Dateien A und B erstellt. Der nächste Commit hat die Datei C hinzugefügt, und so weiter. Diese Commits verbinden die Dateien, und diese Verbindungen bedeuten etwas - wenn Datei D ein neuer Dienst in Ihrer Architektur ist, muss Datei A vielleicht geändert werden, weil ein Test jetzt fehlschlägt.

Diese Änderungen schaffen eine Verbindung zwischen den Dateien, und wir können dies in ein Diagramm umwandeln, das zeigt, wie die Dateien miteinander verbunden sind. So sieht es Git - es ist nützlich, um zu einem bestimmten Commit zurückzugehen und den Code in diesem Zustand wiederherzustellen. Wir können das Ganze aber auch aus einer anderen Perspektive betrachten, nämlich um zu sehen, welche Dateien zusammen geändert wurden. Zum Beispiel ist die Datei A eng mit der Datei D verbunden, aber überhaupt nicht mit der Datei C. Es gibt keinen Commit, in dem A und C zusammen auftauchen, also sind sie nicht eng miteinander verbunden.

Anhand dieser Informationen können wir dann einen Pfad durch den Graphen zeichnen. Die Zahlen, die Sie neben den Verbindungen sehen, werden Gewichte genannt. Eine Gewichtung gibt an, wie oft zwei Dateien zusammen übertragen werden. Sie können Knoten und Kanten in einem Graphen zusätzliche Daten hinzufügen, und diese Daten, die kein inhärentes Schema haben, werden Gewichtungen genannt. In unserem Fall sind die Gewichte einfach ganze Zahlen, die angeben, wie oft zwei Dateien zusammen übertragen wurden.

Für einen kleinen Graphen wie diesen scheint dies einfach zu sein, aber wenn man es auf eine große Codebasis mit Tausenden von Dateien anwendet, erhält man schnell einen Graphen mit Hunderttausenden von Kanten, mit denen man nur schwer arbeiten kann.

Durch die Berechnung von Pfaden durch den Graphen können wir eine Metrik namens "Betweenness-Zentralität" anwenden. Diese Metrik wurde ursprünglich für soziale Netzwerke entwickelt und von Unternehmen wie Facebook und Twitter verwendet, um festzustellen, welche Personen innerhalb des Netzwerks wichtig oder zentral sind. In unserem Fall verwenden wir sie, um herauszufinden, welche Dateien in unserer Codebasis zentral sind - diejenigen, die verschiedene Komponenten unserer Architektur miteinander verbinden.

Einige von Ihnen haben vielleicht schon bemerkt, dass die Dateien A und D ziemlich wichtig aussehen. Warum ist das so? Wenn Sie von den Dateien G, E oder F zu den Dateien A, J, B oder C gelangen wollen, müssen Sie durch die Datei D. D ist wie eine einzige Brücke, die zwei Teile der Codebasis verbindet.

Wie sieht das in der Praxis aus? Ich habe ein Tool geschrieben, das berechnet, wie zentral jede Datei in unserem System ist, und ich habe eine Datenanalyse damit durchgeführt. Das Ergebnis war diese farbenfrohe Visualisierung, ein so genanntes Sunburst-Diagramm. Es zeigt, wie viel jeder Ordner in unserem Projekt zur Betweenness-Zentralität beiträgt.

Unser "Snippet"-Ordner trägt zum Beispiel zu 25 % der gesamten Verflechtung bei. Und warum? Weil, wie Sie am blauen inneren Ring sehen können, unsere "Administration" (UI-Schicht) ziemlich groß ist. Wenn Sie etwas an der Benutzeroberfläche ändern, müssen Sie oft auch die Snippets aktualisieren, da neue Elemente der Benutzeroberfläche neue Zeichenketten erfordern, um ihre Funktion zu beschreiben. Dadurch entstehen viele Verbindungen zwischen dem UI-Code und den Snippets.

In ähnlicher Weise waren unsere End-to-End-Tests (E2E), obwohl sie nicht so stark miteinander verbunden waren, lange Zeit recht spröde. Jedes Mal, wenn jemand ein bisschen JavaScript oder CSS änderte, brachen die E2E-Tests ab. Wir wussten also, dass jede UI-Änderung einen Eingriff in die E2E-Tests erforderte. Das ist etwas, was viele von Ihnen wahrscheinlich wissen - schlecht ausgeführte E2E-Tests können noch spröder sein als Unit-Tests.

Aber das entschuldigt nicht unsere Unit-Tests. Ich habe die Analyse auch für unsere PHP-Codebasis durchgeführt und die Tests überprüft. Der Betweenness-Centrality-Score zeigte mir, wie wahrscheinlich es war, dass ein Test bei einer zufälligen Änderung der Codebasis abbricht.

Der brüchigste Test war unser API-fähiger Test. Als ich ihn genauer untersuchte, stellte ich fest, dass er darauf ausgelegt war, das gesamte API-Schema mit einer übergebenen JSON-Datei zu vergleichen, um die Feldannotationen zu überprüfen. Das machte den Test absichtlich sehr spröde. Bei jeder Änderung des API-Schemas schlug der Test fehl, und die Entwickler mussten den Fehler beheben.

Ich konnte diesen brüchigen Test allein durch die Analyse des Git-Verlaufs identifizieren. Wir haben uns durch viele Themen bewegt - von Karten, Geschichte und Mathematik bis hin zu Informatik, Datenbanken und Diagrammen. Aber was haben wir davon? Warum machen wir das alles?

Das ist der springende Punkt. Es gibt Standardmethoden für den Umgang mit Daten - wir haben Muster wie Fabriken und Befehlsmuster, die beschreiben, wie sich ein System verhalten sollte. Diese Muster werden gut verstanden. Aber was ist mit der Struktur? Darüber denken wir nicht so oft nach wie über Daten.

Es gibt Muster für Strukturen, z. B. Graphen. Mithilfe von Algorithmen, die das Layout von Daten analysieren, können wir bestimmte Attribute ableiten und Dinge überprüfen. Und nicht nur das - wir können auch neue Daten aus der Struktur berechnen, z. B. wenn wir uns die Commit-Historie eines Projekts oder den Abhängigkeitsgraphen von Klassen ansehen. Wir können Standardalgorithmen verwenden, von denen viele bereits gut etabliert und leicht zu finden sind.

Ich hoffe, dieser Vortrag war für Sie inspirierend. Wie ich schon sagte: Graphen sind überall. Ich wünsche Ihnen einen schönen Abend und einen guten Start in den letzten Slot des Tages!

FRAGEN UND ANTWORTEN

Frage: Was sind gute Gründe für die Verwendung von Graphenstrukturen anstelle von traditionelleren Strukturen, abgesehen von den Beispielen, die Sie gezeigt haben? Haben Sie noch weitere Beispiele, die Sie näher erläutern möchten?
Christian: Ja, auf jeden Fall. Ein Beispiel ist die Verwendung eines Tools wie DepthTrack, das analysiert, wie Klassen voneinander abhängen. Ich habe die Informationen aus DepthTrack verwendet, um die Abhängigkeiten in einem Diagramm darzustellen. Dann habe ich Layout-Algorithmen angewandt, um den Graphen räumlich zu organisieren, wodurch wir sehen konnten, welche Teile unseres Systems stark gekoppelt waren.

Wir färbten die Knoten entsprechend dem Ordner, zu dem sie gehörten, und konnten so erkennen, wenn zwei Ordner, die eigentlich nicht voneinander abhängig sein sollten, eng miteinander verbunden waren. So konnten wir zum Beispiel sehen, wie eng unser Kassensystem mit unserer Datenbankschicht verbunden war oder wie unsere Versandlogik mit unseren Zahlungsdiensten zusammenhing. Layout-Algorithmen können helfen, diese Beziehungen in einem Abhängigkeitsdiagramm sichtbar zu machen.

Frage: Gibt es ein Toolset, das Sie verwenden, um Ihre Repositories zu analysieren und die Diagramme zu erstellen, die die Beziehungen zwischen Ihren Klassen zeigen?
Christian: Die Standardantwort wäre die Verwendung von Python mit der NetworkX-Bibliothek. Allerdings kann NetworkX bei sehr großen Graphen wie einem ganzen Repository sehr langsam sein. Daher habe ich in diesem Fall den Python-Algorithmus in Rust umgeschrieben und parallel ausgeführt. Dadurch verringerte sich die Verarbeitungszeit von 20 Stunden auf nur 2 Minuten.

Es ist ein unfertiges Tool, das ich auf meinem GitHub habe. Es gibt eine CSV-Datei aus, und Sie können Excel oder andere Tools zur Visualisierung verwenden. In diesem Fall habe ich eine Grafikbibliothek aus der Statistiksprache R verwendet, um die Sunburst-Diagramme zu erstellen.

Frage: Haben Sie den Code, mit dem Sie die Zentralität für bestimmte Dateien berechnet haben? Ist der irgendwo verfügbar?
Christian: Ja, er befindet sich auf meinem GitHub, und das Projekt heißt "Rawal" - aus irgendeinem Grund ist es nach einem Wal benannt. Wenn Sie interessiert sind, kann ich den Link im Symfony Slack teilen.

Ihr größtes Werk
steht vor der Tür

Kostenloser Test
Discord
© 2025 Platform.sh. All rights reserved.