Mein Name ist Danil Mukhametzyanov und ich arbeite seit sieben Jahren als Backend-Entwickler bei Badoo. In dieser Zeit konnte ich eine große Menge Code erstellen und ändern. So groß, dass eines Tages ein Manager auf mich zukam und sagte: „Die Quote ist vorbei. Um etwas hinzuzufügen, müssen Sie etwas entfernen. "
Okay, das ist nur ein Witz - das hat er nicht gesagt. Das ist schade! Während der gesamten Existenz des Unternehmens hat Badoo mehr als 5,5 Millionen Zeilen logischen Geschäftscodes gesammelt, ausgenommen Leerzeilen und schließende Klammern.
Die Menge selbst ist nicht so beängstigend: Er lügt, bittet nicht um Essen. Vor zwei oder drei Jahren bemerkte ich jedoch, dass ich immer öfter las und versuchte, Code herauszufinden, der in einer Produktionsumgebung nicht wirklich funktioniert. Das ist in der Tat tot.
Dieser Trend wurde nicht nur von mir bemerkt. Badoo erkannte, dass unsere hochbezahlten Ingenieure ständig Zeit mit totem Code verschwenden.
Ich habe diesen Vortrag beim Badoo PHP Meetup # 4 gehalten
Woher kommt der tote Code?
Wir suchten nach den Ursachen der Probleme. Unterteilte sie in zwei Kategorien:
- Prozess - diejenigen, die als Ergebnis der Entwicklung entstehen;
- historisch - Legacy-Code.
Zunächst haben wir uns entschlossen, Prozessquellen zu zerlegen, um das Auftreten neuer Probleme zu verhindern.
A / B-Tests
Badoo begann vor vier Jahren, A / B-Tests aktiv einzusetzen. Jetzt laufen ungefähr 200 Tests ständig, und alle Produktfunktionen durchlaufen dieses Verfahren.
Infolgedessen wurden in vier Jahren etwa 2000 abgeschlossene Tests gesammelt, und diese Zahl wächst ständig. Sie hat uns Angst gemacht, dass jeder Test ein toter Code ist, der nicht mehr ausgeführt wird und überhaupt nicht benötigt wird.
Die Lösung des Problems kam schnell: Wir haben nach Abschluss des A / B-Tests automatisch ein Ticket zum Schneiden des Codes erstellt.
Ein Beispiel für ein Ticket
Aber der menschliche Faktor wird regelmäßig ausgelöst. Immer wieder fanden wir den Testcode, der weiter lief, aber niemand dachte darüber nach und beendete den Test.
Dann gab es einen starren Rahmen: Jeder Test muss ein Enddatum haben. Wenn der Manager vergaß, die Testergebnisse zu lesen, stoppte er automatisch und schaltete sich aus. Und wie bereits erwähnt, wurde automatisch ein Ticket zum Ausschneiden erstellt, wobei die ursprüngliche Version der Logik der Funktion beibehalten wurde.
Mit Hilfe eines so einfachen Mechanismus haben wir eine große Arbeitsebene beseitigt.
Vielfalt der Kunden
In unserem Unternehmen werden mehrere Marken unterstützt, aber der Server ist eine. Jede Marke ist auf drei Plattformen vertreten: Web, iOS und Android. Unter iOS und Android haben wir einen wöchentlichen Entwicklungszyklus: Einmal pro Woche erhalten wir zusammen mit einem Update auf jeder Plattform eine neue Version der Anwendung.
Es ist leicht zu erraten, dass wir mit diesem Ansatz in einem Monat ungefähr ein Dutzend neue Versionen haben, die unterstützt werden müssen. Der Benutzerverkehr ist ungleichmäßig zwischen ihnen verteilt: Benutzer wechseln allmählich von einer Version zur anderen. Einige ältere Versionen haben Datenverkehr, aber er ist so klein, dass es schwierig ist, ihn zu warten. Es ist schwer und nutzlos.
Also haben wir angefangen, die Anzahl der Versionen zu zählen, die wir unterstützen möchten. Für den Kunden gibt es zwei Grenzen: die weiche und die harte Grenze.
Wenn das Soft-Limit erreicht ist (wenn bereits drei oder vier neue Versionen veröffentlicht wurden und die Anwendung noch nicht aktualisiert wurde), wird dem Benutzer ein Bildschirm mit der Warnung angezeigt, dass seine Version veraltet ist. Wenn das harte Limit erreicht ist (dies sind je nach Anwendung und Marke etwa 10 bis 20 "verpasste" Versionen), entfernen wir einfach die Option, diesen Bildschirm zu überspringen. Es wird blockiert: Sie können die Anwendung nicht damit verwenden.

Bildschirm für das harte Limit
In diesem Fall ist es sinnlos, die vom Client kommenden Anforderungen weiter zu verarbeiten - er sieht nur einen Bildschirm.
Aber hier, wie im Fall von A / B-Tests, entstand eine Nuance. Kundenentwickler sind auch Menschen. Sie verwenden neue Technologien, Chips von Betriebssystemen - und nach einer Weile wird die Anwendungsversion auf der nächsten Version des Betriebssystems nicht mehr unterstützt. Der Server leidet jedoch weiterhin, da er diese Anforderungen weiterhin verarbeiten muss.
Wir haben eine separate Lösung für den Fall gefunden, dass die Unterstützung für Windows Phone beendet wurde. Wir haben einen Bildschirm vorbereitet, der den Benutzer informiert: „Wir lieben dich sehr! Du bist sehr cool! Aber können Sie eine andere Plattform verwenden? Neue coole Funktionen werden Ihnen zur Verfügung stehen, aber hier können wir nichts tun. " In der Regel bieten wir als alternative Plattform eine Webplattform an, die immer verfügbar ist.
Mit einem so einfachen Mechanismus haben wir die Anzahl der vom Server unterstützten Client-Versionen begrenzt: ungefähr 100 verschiedene Versionen aller Marken, von allen Plattformen.
Feature-Flags
Durch Deaktivieren der Unterstützung für ältere Plattformen haben wir jedoch nicht vollständig verstanden, ob es möglich war, den von ihnen verwendeten Code vollständig auszuschneiden. Oder Plattformen, die für ältere Betriebssystemversionen verbleiben, weiterhin dieselbe Funktionalität verwenden?
Das Problem ist, dass unsere API nicht auf dem versionierten Teil basiert, sondern auf der Verwendung von Feature-Flags. Wie wir dazu gekommen sind, können Sie diesem Bericht entnehmen .
Wir hatten zwei Arten von Feature-Flags. Ich werde Ihnen anhand von Beispielen davon erzählen.
Kleinere Funktionen
Der Client sagt zum Server: „Hallo, ich bin es. Ich unterstütze Fotopostings. " Der Server schaut es sich an und antwortet: „Großartig, Support! Jetzt weiß ich davon und werde Ihnen Fotonachrichten senden. " Das Hauptmerkmal hierbei ist, dass der Server den Client in keiner Weise beeinflussen kann - er akzeptiert einfach Nachrichten von ihm und ist gezwungen, diese abzuhören.
Wir nennen diese Flags Nebenfunktionen. Derzeit haben wir über 600 davon.
Was ist der Nachteil bei der Verwendung dieser Flags? In regelmäßigen Abständen gibt es umfangreiche Funktionen, die nicht nur von der Clientseite aus abgedeckt werden können. Sie möchten sie auch von der Serverseite aus steuern. Zu diesem Zweck haben wir andere Arten von Flags eingeführt.
Anwendungsfunktionen
Der gleiche Client, der gleiche Server. Der Client sagt: „Server, ich habe gelernt, Video-Streaming zu unterstützen. Mach es an? " Der Server antwortet: "Danke, das werde ich mir merken." Und er fügt hinzu: „Großartig. Lassen Sie uns unserem geliebten Benutzer diese Funktionalität zeigen, er wird sich freuen. " Oder: "Ok, aber wir werden es noch nicht aufnehmen."
Wir nennen diese Funktionen Anwendungsfunktionen. Sie sind schwerer, daher haben wir weniger davon, aber immer noch genug: mehr als 300.
Benutzer wechseln also von einer Version des Clients zu einer anderen. Eine Art Flag wird von allen aktiven Versionen von Anwendungen unterstützt. Oder umgekehrt nicht unterstützt. Es ist nicht ganz klar, wie man das kontrolliert: 100 Client-Versionen, 900 Flags! Um dies zu bewältigen, haben wir ein Dashboard erstellt.
Ein rotes Quadrat bedeutet, dass nicht alle Versionen dieser Plattform diese Funktion unterstützen. grün - Alle Versionen dieser Plattform unterstützen dieses Flag. Wenn die Flagge ein- und ausgeschaltet werden kann, blinkt sie regelmäßig. Wir können sehen, was in welcher Version passiert.
Dashboard-Bildschirm
Direkt in dieser Benutzeroberfläche haben wir begonnen, Aufgaben zum Ausschneiden von Funktionen zu erstellen. Es ist zu beachten, dass nicht alle roten oder grünen Zellen in jeder Zeile ausgefüllt werden müssen. Es gibt Flags, die nur auf einer Plattform ausgeführt werden. Es gibt Flaggen, die nur für eine Marke ausgefüllt werden.
Die Automatisierung des Prozesses ist nicht so bequem, aber im Prinzip nicht erforderlich. Sie müssen lediglich eine Aufgabe festlegen und das Dashboard regelmäßig überprüfen. In der ersten Iteration konnten wir mehr als 200 Flags ausschneiden. Das ist fast ein Viertel der Flaggen, die wir verwendet haben!
Damit sind die Prozessquellen abgeschlossen. Sie sind als Ergebnis unseres Entwicklungsflusses entstanden, und wir haben die Arbeit mit ihnen erfolgreich in diesen Prozess integriert.
Was tun mit Legacy-Code?
Wir haben die Entstehung neuer Probleme in Prozessquellen gestoppt. Und wir standen vor einer schwierigen Frage: Was tun mit dem im Laufe der Jahre angesammelten Legacy-Code? Wir näherten uns der Lösung aus technischer Sicht, dh wir beschlossen, alles zu automatisieren. Es war jedoch nicht klar, wie der nicht verwendete Code zu finden war. Er versteckte sich in seiner gemütlichen kleinen Welt: Er wird in keiner Weise gerufen, er lässt niemanden von sich wissen.
Wir mussten von der anderen Seite gehen: Nehmen Sie den gesamten Code, sammeln Sie Informationen darüber, welche Teile genau ausgeführt werden, und führen Sie dann die Inversion durch.
Dann haben wir es zusammengestellt und auf der minimalsten Ebene implementiert - auf Dateien. Auf diese Weise können wir leicht eine Liste der Dateien aus dem Repository abrufen, indem wir den entsprechenden UNIX-Befehl ausführen.
Es blieb eine Liste der Dateien zu sammeln, die in der Produktion verwendet werden. Es ist ganz einfach: Rufen Sie für jede Anforderung beim Herunterfahren die entsprechende PHP-Funktion auf. Die einzige Optimierung, die wir hier vorgenommen haben, besteht darin, OPCache anzufordern, anstatt jede Anforderung anzufordern. Andernfalls wäre die Datenmenge sehr groß.
Als Ergebnis entdeckten wir viele interessante Artefakte. Bei einer eingehenderen Analyse stellten wir jedoch fest, dass uns nicht verwendete Methoden fehlten: Der Unterschied in ihrer Anzahl betrug drei- bis siebenmal.
Es stellte sich heraus, dass die Datei nur für eine Konstante oder ein Methodenpaar geladen, ausgeführt und kompiliert werden konnte. Alles andere blieb nutzlos, um in diesem bodenlosen Meer zu liegen.
Zusammenstellung einer Liste von Methoden
Es stellte sich jedoch schnell genug heraus, um eine vollständige Liste der Methoden zu sammeln. Wir haben gerade Nikita Popovs Parser genommen , ihm unser Repository zugeführt und alles bekommen, was wir im Code haben.
Die Frage bleibt: Wie kann man zusammenbauen, was in der Produktion gespielt wird? Wir sind an der Produktion interessiert, weil Tests abdecken können, was wir überhaupt nicht brauchen. Ohne nachzudenken, haben wir XHProf genommen. Es wurde bereits in der Produktion für einen Teil der Abfragen ausgeführt, und daher hatten wir Profilbeispiele, die in den Datenbanken gespeichert sind. Es genügte, nur zu diesen Datenbanken zu gehen, die generierten Snapshots zu analysieren - und eine Liste der Dateien zu erhalten.
Nachteile von XHProf
Wir haben diesen Vorgang in einem anderen Cluster wiederholt, in dem XHProf nicht gestartet wurde, aber dringend benötigt wurde. Dies ist ein Cluster zum Ausführen von Hintergrundskripten und zur asynchronen Verarbeitung, der für hohe Auslastung wichtig ist und viel Logik ausführt.
Und dann haben wir dafür gesorgt, dass XHProf für uns unpraktisch ist.
- Es erfordert das Ändern des PHP-Codes. Sie müssen den Startcode für die Ablaufverfolgung einfügen, die Ablaufverfolgung beenden, die gesammelten Daten abrufen und in eine Datei schreiben. Immerhin ist dies ein Profiler, und wir haben Produktion, das heißt, es gibt viele Anfragen, Sie müssen auch über Sampling nachdenken. In unserem Fall wurde dies durch eine große Anzahl von Clustern mit unterschiedlichen Einstiegspunkten verschärft.
- . . , OPCache. : XHProf, . , core- .
- . . XHProf . ( XHProf): CPU, , . , , . - XHProf aggregator ( XHProf Live Profiler, open-source) , , , . , : «, , », CPU , , Live Profiler . , , .
- XHProf. , . . , . : , ( , youROCKDies wird von lsd nicht benötigt , aber es war bequemer, einen einzelnen Wrapper darüber zu verwalten. Das Patchen von XHProf ist nicht das, was wir tun wollten, da es ein ziemlich großer Profiler ist (was ist, wenn wir versehentlich etwas kaputt machen?).
Es gab noch eine weitere Idee: Bestimmte Namespaces, z. B. Vendor-Namespaces, vom Composer auszuschließen, die in der Produktion ausgeführt werden, weil sie unbrauchbar sind: Wir werden Vendor-Pakete nicht umgestalten und zusätzlichen Code aus ihnen herausschneiden.
Lösungsanforderungen
Wir haben uns wieder getroffen und uns angesehen, welche Lösungen es gibt. Und sie formulierten die endgültige Liste der Anforderungen.
Erstens: minimaler Overhead. Für uns war XHProf die Messlatte: nicht mehr als nötig.
Zweitens wollten wir den PHP-Code nicht ändern.
Drittens wollten wir, dass die Lösung überall funktioniert - sowohl im FPM als auch in der CLI.
Viertens wollten wir mit den Gabeln umgehen. Sie werden in der CLI auf Cloud-Servern aktiv verwendet. Ich wollte in PHP keine spezifische Logik für sie erstellen.
Fünftens: Probenahme aus der Box. Tatsächlich folgt dies aus der Anforderung, den PHP-Code nicht zu ändern. Im Folgenden werde ich erklären, warum wir Proben genommen haben.
Sechster und letzter:die Fähigkeit, aus Code zu erzwingen. Wir lieben es, wenn alles automatisch funktioniert, aber manchmal ist es bequemer, manuell zu starten, anzupassen und zu schauen. Wir brauchten die Fähigkeit, alles direkt aus dem Code heraus zu aktivieren und zu deaktivieren, und nicht durch zufällige Entscheidung des allgemeineren Mechanismus des PHP-Moduls, der die Wahrscheinlichkeit der Aufnahme durch die Einstellungen festlegt.
Wie funcmap funktioniert
Als Ergebnis haben wir eine Lösung, die wir funcmap nennen.
Funcmap ist im Wesentlichen eine PHP-Erweiterung. In PHP-Begriffen ist dies ein PHP-Modul. Um zu verstehen, wie es funktioniert, schauen wir uns an, wie der PHP-Prozess und das PHP-Modul funktionieren.
Sie starten also einen Prozess. PHP ermöglicht das Abonnieren von Hooks beim Erstellen eines Moduls. Der Prozess wird gestartet, der GINIT-Hook (Global Init) wird gestartet, mit dem Sie die globalen Parameter initialisieren können. Dann wird das Modul initialisiert. Dort können Konstanten erstellt und zugeordnet werden, jedoch nur für ein bestimmtes Modul und nicht für eine Anfrage, da Sie sich sonst in den Fuß schießen.
Wenn die Benutzeranforderung eingeht, wird der RINIT-Hook (Request Init) aufgerufen. Wenn die Anforderung abgeschlossen ist, erfolgt das Herunterfahren und ganz am Ende das Herunterfahren des Moduls: MSHUTDOWN und GSHUTDOWN. Alles ist logisch.
Wenn es sich um FPM handelt, geht jede Benutzeranforderung an einen bereits vorhandenen Mitarbeiter. Grundsätzlich arbeiten RINIT und RSHUTDOWN nur im Kreis, bis FPM entscheidet, dass der Arbeiter veraltet ist. Es ist Zeit, ihn zu erschießen und einen neuen zu erstellen. Wenn wir über die CLI sprechen, ist es nur ein linearer Prozess. Alles wird einmal aufgerufen.

Wie funcmap funktioniert
Von diesem Set waren wir an zwei Hooks interessiert. Der erste ist RINIT . Wir haben begonnen, das Datenerfassungsflag zu setzen: Dies ist eine Art Zufall, der aufgerufen wurde, um die Daten abzutasten. Wenn es funktioniert hat, haben wir diese Anfrage verarbeitet: Wir haben Statistiken für Aufrufe von Funktionen und Methoden dafür gesammelt. Wenn es nicht funktioniert hat, wurde die Anfrage nicht verarbeitet.
Als Nächstes erstellen Sie eine Hash-Tabelle, falls diese nicht vorhanden ist. Die Hash-Tabelle wird intern von PHP selbst bereitgestellt. Hier muss nichts erfunden werden - nehmen Sie es einfach und verwenden Sie es.
Als nächstes initialisieren wir den Timer. Ich werde unten über ihn sprechen. Denken Sie vorerst daran, dass er wichtig und gebraucht ist.
Der zweite Haken ist MSHUTDOWN... Ich möchte darauf hinweisen, dass es sich um MSHUTDOWN handelt, nicht um RSHUTDOWN. Wir wollten nicht für jede Anfrage etwas ausarbeiten - wir interessierten uns für den ganzen Arbeiter. Auf MSHUTDOWN nehmen wir unsere Hash-Tabelle, gehen sie durch und schreiben eine Datei (was könnte zuverlässiger, bequemer und vielseitiger sein als die gute alte Datei?).
Die Hash-Tabelle wird ganz einfach mit demselben PHP-Hook zend_execute_ex gefüllt, der jedes Mal aufgerufen wird, wenn eine benutzerdefinierte Funktion aufgerufen wird. Der Datensatz enthält zusätzliche Parameter, anhand derer Sie verstehen können, um welche Art von Funktion es sich handelt, um Namen und Klasse. Wir akzeptieren es, lesen den Namen, schreiben ihn in die Hash-Tabelle und rufen dann den Standard-Hook auf.
Dieser Hook schreibt keine Inline-Funktionen. Wenn Sie integrierte Funktionen überschreiben möchten, gibt es für diese eine separate Funktionalität namens zend_execute_internal.
Aufbau
Wie kann ich dies konfigurieren, ohne den PHP-Code zu ändern? Die Einstellungen sind sehr einfach:
- enabled: Gibt an, ob es aktiviert ist oder nicht.
- Die Datei, in die wir schreiben. Es gibt einen PID-Platzhalter, um eine Race-Bedingung auszuschließen, wenn verschiedene PHP-Prozesse gleichzeitig in dieselbe Datei schreiben.
- Wahrscheinlichkeitsbasis: unser Wahrscheinlichkeitsflag. Wenn Sie den Wert auf 0 setzen, wird keine Anfrage geschrieben. Wenn 100 - bedeutet dies, dass alle Anforderungen protokolliert und in die Statistik aufgenommen werden.
- flush_interval. Dies ist die Häufigkeit, mit der wir alle Daten in eine Datei speichern. Wir möchten, dass die Datenerfassung in der CLI ausgeführt wird, aber es gibt Skripte, die für eine lange Zeit ausgeführt werden können und Speicher verbrauchen, wenn Sie eine große Menge an Funktionen verwenden.
Wenn wir einen Cluster haben, der nicht so stark ausgelastet ist, versteht FPM außerdem, dass der Worker bereit ist, mehr zu verarbeiten, und beendet den Prozess nicht - er lebt und verbraucht einen Teil des Speichers. Nach einer gewissen Zeit leeren wir alles auf die Festplatte, setzen die Hash-Tabelle zurück und füllen sie erneut auf. Wenn das Timeout jedoch noch nicht erreicht wurde, wird der MSHUTDOWN-Hook ausgelöst, in den wir schließlich alles schreiben.
Das Letzte, was wir wollten, war die Möglichkeit, funcmap über PHP-Code aufzurufen. Die entsprechende Erweiterung bietet die einzige Methode, mit der Sie die Erfassung von Statistiken unabhängig von der Funktionsweise der Wahrscheinlichkeit aktivieren oder deaktivieren können.
Gemeinkosten
Wir haben uns gefragt, wie sich das auf unsere Server auswirkt. Wir haben ein Diagramm erstellt, das die Anzahl der Anfragen an eine echte Kampfmaschine eines der am meisten geladenen PHP-Cluster zeigt.
Es kann viele solcher Maschinen geben, daher zeigt die Grafik die Anzahl der Anforderungen, nicht die CPU. Der Balancer erkennt, dass die Maschine mehr Ressourcen als gewöhnlich verbraucht, und versucht, die Anforderungen auszugleichen, damit die Maschinen gleichmäßig geladen werden. Dies war genug, um zu verstehen, wie schlecht der Server ist.
Wir haben unsere Erweiterung nacheinander bei 25%, 50% und 100% eingeschaltet und das folgende Bild gesehen:
Die gepunktete Linie gibt die Anzahl der Anfragen an, die wir erwarten. Die Hauptzeile ist die Anzahl der eingehenden Anfragen. Wir sahen eine Verschlechterung von ungefähr 6%, 12% und 23%: Dieser Server begann, fast ein Viertel weniger eingehende Anfragen zu verarbeiten.
Diese Grafik zeigt zunächst, dass Stichproben für uns wichtig sind: Wir können nicht 20% der Serverressourcen für das Sammeln von Statistiken ausgeben.
Falsches Ergebnis
Die Probenahme hat einen Nebeneffekt: Einige Methoden sind nicht in der Statistik enthalten, werden jedoch tatsächlich verwendet. Wir haben versucht, dies auf verschiedene Weise zu bekämpfen:
- . -, . , , , , .
- . , : , , .
Wir haben zwei Lösungen für die Fehlerbehandlung ausprobiert. Die erste besteht darin, die Statistiksammlung ab dem Zeitpunkt der Fehlergenerierung zwangsweise zu aktivieren: Sammeln Sie das Fehlerprotokoll und analysieren Sie es. Hier gibt es jedoch eine Gefahr: Wenn eine Ressource fällt, steigt die Anzahl der Fehler sofort an. Wenn Sie mit der Verarbeitung beginnen, gibt es viel mehr Mitarbeiter - und der Cluster beginnt langsam zu sterben. Daher ist dies nicht ganz richtig.
Wie mache ich das anders? Wir lasen und gingen mit Nikita Popovs Parser die Einsätze durch und stellten fest, welche Methoden dort aufgerufen werden. Auf diese Weise haben wir die Belastung des Servers beseitigt und die Anzahl der Fehlalarme verringert.
Dennoch gab es Methoden, die selten genannt wurden und bei denen unklar war, ob sie benötigt wurden oder nicht. Wir haben einen Helfer hinzugefügt, mit dessen Hilfe festgestellt werden kann, ob solche Methoden verwendet werden: Wenn die Stichprobe bereits gezeigt hat, dass die Methode selten aufgerufen wird, können Sie die Verarbeitung zu 100% aktivieren und nicht darüber nachdenken, was passiert. Jede Ausführung dieser Methode wird protokolliert. Sie werden es wissen.
Wenn Sie sicher sind, dass die Methode verwendet wird, ist sie möglicherweise übertrieben. Vielleicht ist dies eine notwendige, aber seltene Funktionalität. Stellen Sie sich vor, Sie haben die Option "Beschweren", die nur selten verwendet wird, aber wichtig ist - Sie können sie nicht ausschneiden. In solchen Fällen haben wir gelernt, solche Methoden manuell zu kennzeichnen.
Wir haben eine Schnittstelle erstellt, die zeigt, welche Methoden verwendet werden (sie befinden sich auf einem weißen Hintergrund) und welche möglicherweise nicht verwendet werden (sie befinden sich auf einem roten Hintergrund). Hier können Sie auch die notwendigen Methoden markieren.
Schnittstellenbildschirm
Die Benutzeroberfläche ist großartig, aber gehen wir zurück zum Anfang, dem Problem, das wir gelöst haben. Es bestand darin, dass unsere Ingenieure toten Code lasen. Wo lesen sie es? In der IDE. Stellen Sie sich vor, wie es wäre, einen Fan seines Fachs zu zwingen, die IDE-Welt in einer Art Webschnittstelle zu verlassen und dort etwas zu tun! Wir haben beschlossen, dass wir unsere Kollegen auf halbem Weg treffen müssen.
Wir haben ein Plugin für PhpStorm erstellt , das die gesamte Datenbank nicht verwendeter Methoden lädt und anzeigt, ob diese Methode verwendet wird oder nicht. Darüber hinaus können Sie die Methode als in der Schnittstelle verwendet markieren. Dies alles wird auf den Server übertragen und steht den übrigen Codebasis-Mitwirkenden zur Verfügung.
Damit ist der Hauptteil unserer Arbeit mit Legacy abgeschlossen. Wir bemerkten schneller, dass wir nicht ausführen, reagierten schneller darauf und verschwendeten keine Zeit damit, manuell nach nicht verwendetem Code zu suchen.
Die funcmap-Erweiterung ist auf GitHub verfügbar . Wir werden uns freuen, wenn es jemandem nützlich ist.
Alternativen
Von außen scheint es, dass wir bei Badoo nicht wissen, was wir mit uns anfangen sollen. Schauen Sie sich doch mal an, was auf dem Markt ist.
Das ist eine faire Frage. Wir haben nachgesehen - und in diesem Moment war nichts auf dem Markt. Erst als wir mit der aktiven Implementierung unserer Lösung begannen, stellten wir fest, dass gleichzeitig ein Mann namens Joe Watkins, der im nebligen Großbritannien lebt, eine ähnliche Idee umsetzte und die Erweiterung Tombs entwickelte.
Wir haben es nicht sehr sorgfältig studiert, weil wir bereits unsere eigene Lösung hatten, aber dennoch einige Probleme gefunden haben:
- Fehlende Probenahme. Oben habe ich erklärt, warum wir es brauchen.
- . , APCu ( ), .
- CLI. , , CLI-, .
- . Tombs, , , , , , . funcmap («» , ): , . Tombs , , FPM CLI. - , .
Zuerst denkt im Voraus darüber , wie Sie die Funktionalität entfernen, die für einen kurzen Zeitraum durchgeführt wird, vor allem , wenn die Entwicklung sehr aktiv ist. In unserem Fall waren dies A / B-Tests. Wenn Sie nicht im Voraus darüber nachdenken, müssen Sie die Trümmer beseitigen.
Zweitens: Kennen Sie Ihre Kunden vom Sehen. Es spielt keine Rolle, ob sie intern oder extern sind - Sie müssen sie kennen. Irgendwann müssen Sie ihnen sagen: „Liebes, hör auf! Nein".
Drittens: Bereinigen Sie Ihre API. Dies führt zur Vereinfachung des gesamten Systems.
Und viertens: Sie können alles automatisieren, auch die Suche nach totem Code. Was wir getan haben.