„Lass mich in Ruhe, bitte, ich bin ein Schöpfer! Lass mich kreieren! “- der Programmierer Gennady rezitiert heute Abend zum dritten Mal dieses Mantra in seinem Kopf. Er hat jedoch noch keine einzige Codezeile geschrieben, da eine weitere Pull-Anfrage in der Bibliothek eingetroffen ist, die er zu entwickeln versucht. Gemäß den Unternehmensrichtlinien sollten Codeüberprüfungen mit minimalen Verzögerungen erfolgen. Jetzt überlegt Gennady, was zu tun ist: ohne die Änderungen zu akzeptieren, sie abzulehnen, ohne zu schauen, oder immer noch wertvolle Zeit zu verbringen, um ihre Essenz zu verstehen. Wer außer ihm? Er hat diesen Code geschrieben, er wird ihm folgen. Und alle Änderungen sind nur mit seiner persönlichen Zustimmung möglich, denn dies ist die Doomsday Library.
Währenddessen verteilt ein Team namens "Cedar Beavers" buchstäblich hinter der Mauer Anfragen untereinander neu, so dass die Belastung beim Betrachten mehr oder weniger gleichmäßig sinkt. Ja, sie beschäftigen sich nicht mit der Doomsday Library, aber sie erledigen andere Aufgaben, die schnelle Codeänderungen und schnellere Prozesse erfordern.
Es gibt keine einheitliche Lösung für alle Fälle: Für einige ist die Rationalisierung und Geschwindigkeit der Prozesse wichtig, irgendwo kann es durchaus notwendig sein, eine feste Hand und vollständige Kontrolle zu haben. Darüber hinaus können in verschiedenen Entwicklungsstadien desselben Produkts unterschiedliche Ansätze erforderlich sein, um sich gegenseitig zu ersetzen. Jeder von ihnen hat seine eigenen Vor- und Nachteile, und basierend auf ihnen sind wir dort angekommen, wo wir jetzt sind.
Welchen Weg sind wir in Wrike gegangen?
Welche Optionen haben wir gewählt, um den Code selbst zu besitzen?
Streng persönlich. Wir haben dies nicht einmal berücksichtigt. Wenn Gennady das Erstellen von Pull-Anfragen für seine Bibliothek verbietet und alle Änderungen persönlich vornimmt, erhalten Sie einen streng persönlichen Ansatz. Sicherlich hat Gennady so angefangen.
Von den offensichtlichen Nachteilen des Ansatzes ist es einfach Totalitarismus in der Entwicklungswelt. Gennady ist ohne Übertreibung die einzige Person auf der Erde, die den Code genau kennt, Pläne für seine Entwicklung hat (oder nicht) und ihn ändern kann. Der gleiche Bus, der "Bassfaktor", hat bereits die Ecke verlassen. Wenn Gennady sich erkältet, wird das Projekt höchstwahrscheinlich mit ihm untergehen. Ein anderer Entwickler wird sich gabeln müssen, es wird viele von ihnen geben, und es wird ein völliges Chaos entstehen.
Dieser Ansatz hat ein Plus - einen vollständig konsolidierten Entwicklungsansatz. Eine Person trifft alle Entscheidungen über Architektur, Codestil und löst jedes Problem persönlich. Kein Kommunikationsaufwand.
Bedingt persönlich. Dies ist genau das, was Gennady nicht tun möchte: Alle MRs beobachten, die Möglichkeit geben, den Code seiner Bibliothek an andere Personen zu ändern, aber die volle Kontrolle über die Änderungen haben und das Vetorecht haben. Die Vor- und Nachteile sind dieselben wie im vorherigen Absatz, aber jetzt werden sie durch die Möglichkeit, eine Pull-Anfrage an Entwickler von Drittanbietern direkt an das Repository zu senden und keine technische Spezifikation für die Implementierung einiger Funktionen zu erstellen, ein wenig geglättet.
Kollektivwie Cedar Beavers. In diesem Fall ist das gesamte Team für den Code verantwortlich, und seine Mitglieder entscheiden selbst, wer welche Anfrage überwacht.
Zu den Vorteilen zählen die hohe Geschwindigkeit der Überprüfung der Überprüfung, die Verteilung des Fachwissens zwischen den Teammitgliedern und eine Verringerung des Busfaktors. Natürlich gibt es auch Nachteile. In Diskussionen im Internet erwähnen viele Menschen die mangelnde Verantwortung, wenn sie auf mehrere Personen "verteilt" wird. Dies hängt jedoch von der Struktur des Teams und der Kultur der Entwickler ab: Der Senior Developer oder der Teamleiter können für das Team verantwortlich sein, dann ist er der Einstiegspunkt für Fragen. MR und das Schreiben neuer Funktionen können nach dem Grad der Entwicklerschulung unterteilt werden. Schließlich wäre es falsch, einem Neuling, der gerade erst anfängt, die Architektur der Anwendung zu verstehen, den Code zu überarbeiten.
Bei Wrike verfolgen wir einen kollaborativen Ansatz in Bezug auf Code-Besitz, wobei der Teamleiter die Hauptverantwortung trägt. Diese Person verfügt über das größte Fachwissen im Code, weiß, welcher der Entwickler für die Überprüfung einer bestimmten Komplexität zuständig ist, und trägt die volle Verantwortung für die Qualität des Code des Teams.
Der Weg zur technischen Implementierung dieser Lösung war jedoch nicht der einfachste. Ja, in Worten, alles klingt ziemlich einfach: Hier ist eine Funktion, hier ist ein Befehl. Das Team weiß, wofür es verantwortlich ist, was bedeutet, dass es es überwacht.
Solche Vereinbarungen können als mündlicher Vertrag funktionieren, wenn die Anzahl der Befehle geringer ist als die Anzahl der Finger an der Hand. In unserem Fall sind es mehr als dreißig Befehle und Millionen von Codezeilen. Darüber hinaus können die Grenzen eines Features häufig nicht von einem Repository festgelegt werden: Einige Features sind recht eng in andere integriert.
Das Filterfeld rechts ist für alle Ansichten gleich. Dies ist ein Merkmal des "A" -Teams. Darüber hinaus sind alle Ansichten Merkmale der anderen drei Teams.
Das offensichtlichste Beispiel sind Filter. Sie sehen in allen möglichen Ansichten gleich aus und verhalten sich gleich, während sich die Ansichten in ihrer Funktionalität unterscheiden können. Dies bedeutet, dass die Ansicht einem Team gehört und das einzelne Filterfeld einem anderen. Und so Dutzende von Repositorys, Tausende von Dateien mit unterschiedlichem Code. An wen sollten Sie sich mit einer Überprüfung wenden, wenn Sie Änderungen an einer bestimmten Datei vornehmen müssen?
Zuerst haben wir versucht, dieses Problem mit einer einfachen JSON-Datei zu lösen, die sich im Stammverzeichnis des Repositorys befand. Es gab eine Beschreibung der Funktionalität und der Namen der Verantwortlichen. Sie könnten kontaktiert werden, um eine Bewertung für ihre Pull-Anfrage zu erhalten.
Dies ist ein bisschen wie ein Modell für den Besitz von bedingten persönlichen Codes. Die einzige Ausnahme ist, dass nicht eine Person als verantwortlich aufgeführt ist, sondern zwei oder drei. Aber dieser Ansatz passte nie zu uns: Die Leute wechselten zu anderen Teams, wurden krank, machten Urlaub, kündigten und jedes Mal mussten wir zuerst jemanden suchen, der den angegebenen Eigentümer ersetzt, und dann den Eigentümern sagen, dass sie den Namen manuell ändern und die Änderungen übernehmen sollen.
Später wechselten sie von bestimmten Personen zur Angabe von Befehlen.Es befindet sich jedoch alles in derselben JSON-Datei. Es wurde nicht viel besser, denn jetzt war es notwendig, Teammitglieder zu finden, denen der Code zur Überprüfung vorgelegt werden konnte. Und wir haben Hunderte (ein bisschen gerissen, fast 70) Front-End-Entwickler, und es war zu dieser Zeit nicht einfach, alle Teilnehmer zu finden. Das Besitzersystem ist bereits kollektiv geworden, aber es war manchmal nicht einfacher, die richtigen Leute zu finden, als einen stellvertretenden Eigentümer aus der vorherigen Version zu suchen. Außerdem konnte das Problem mit dem Code, bei dem sich mehrere Features überschneiden könnten, immer noch nicht gelöst werden.
Daher war es von entscheidender Bedeutung, zwei Fragen zu lösen: Wie können bestimmte Funktionen einem bestimmten Team im Repository eines anderen Teams zugewiesen werden und wie können Informationen für alle Teams, denen der Code möglicherweise gehört, einfach und zugänglich gemacht werden?
Warum die vorgefertigten Werkzeuge nicht zu uns passten. Auf dem Markt gibt es Tools, mit denen Personen Bewertungen zugewiesen und bestimmte Personen einem Code zugeordnet werden können. Wenn Sie sie verwenden, müssen Sie nicht auf die Erstellung von Dateien mit den Namen der Personen zurückgreifen, für die Sie im Falle von Überprüfungen, Fehlern oder komplexen Refactorings ausgeführt werden müssen.
Bei Azure bietet DevOps Services Funktionen - Code-Reviewer automatisch einschließen. Der Name spricht für sich und ein ehemaliger Kollege von mir sagt, dass er dieses Tool in seinem Unternehmen sehr erfolgreich einsetzt. Wir arbeiten nicht mit Azure, daher wäre es großartig, von Lesern zu hören, wie die Dinge mit dem Autoreviewer laufen.
Wir verwenden GitLab, daher wäre es logisch, sich an GitLab-Codebesitzer zu wenden. Das Funktionsprinzip dieses Tools passte jedoch nicht zu uns: Die Funktionalität von GitLab besteht aus einer Reihe von Pfaden im Repository (Dateien und Ordner) und Personen über ihre Konten in GitLab. Dieses Bundle wird in eine spezielle Datei geschrieben - codeowners.md. Wir brauchten eine Reihe von Pfaden und Funktionen. Darüber hinaus sind unsere Funktionen in einem speziellen Wörterbuch enthalten, in dem sie dem Befehl zugewiesen sind. Auf diese Weise können Sie komplexe Funktionen markieren, die möglicherweise in mehr als einem Repository vorhanden sind, von mehreren Teams entwickelt werden und wiederum nicht an bestimmte Namen gebunden sind. Außerdem hatten wir vor, diese Informationen zu verwenden, um ein praktisches Verzeichnis von Teams, verwandten Funktionen und allen Teammitgliedern zu erstellen.
Aus diesem Grund haben wir uns entschlossen, ein eigenes Code-Besitzkontrollsystem zu erstellen. Die Implementierung der ersten Version unseres Systems basierte auf den Funktionen des Dart SDK , da es zunächst für die Front-End-Abteilungs-Repositorys und nur für Dart-Dateien gestartet wurde. Wir haben unsere eigenen Meta-Tags verwendet (dies wird zum Glück auf Sprachebene unterstützt), dann alle Quelldateien mit einem statischen Analysegerät durchlaufen und so etwas wie eine Tabelle erstellt: Datei / Feature - Eigentümerbefehl. Sie können sowohl einzelne Dateien als auch ganze Pfade mit mehreren Ordnern markieren.
Nach einiger Zeit wurde Markup mit Funktionen für Code in Dart, JS und Java verfügbar, und dies ist die gesamte Codebasis: sowohl das Frontend als auch das Backend. Um Informationen über die Eigentümer zu erhalten, wird ein statischer Analysator verwendet. Aber natürlich ist es nicht dasselbe wie in der ersten Version und hat nur mit Dart-Code funktioniert. Für Java-Dateien wird beispielsweise die Javaparser- Bibliothek verwendet . Diese Analysegeräte werden nach einem Zeitplan ausgeführt und sammeln alle relevanten Informationen in einer Registrierung.
Zusätzlich zur Bindung bestimmter Codes an die Eigentümerteams haben wir eine Integration mit dem Service zum Sammeln von Produktionsfehlern erstellt und alle nützlichen Informationen zu Teams und Funktionen in einer internen Ressource veröffentlicht. Jetzt kann jeder Mitarbeiter sehen, zu wem er laufen muss, wenn er plötzlich Fragen in einer bestimmten Ansicht hat. Außerdem haben wir es automatisch gemacht, Aufgaben für die Verantwortlichen zu erstellen, falls einige globale Änderungen vorgenommen werden, z. B. die Umstellung auf eine neue Version von Dart oder Angular.
Durch Klicken auf den Befehl sehen Sie alle Funktionen, alle Teammitglieder, welche Funktionen rein technisch und welche produktiv sind
Als Ergebnis haben wir nicht nur ein ziemlich flexibles System zum Verknüpfen von Funktionen mit Teams erhalten, sondern auch eine vollwertige Infrastruktur, die ausgehend vom Code hilft, eine damit verbundene Funktion, ein Team mit allen Teilnehmern, einen Produktbesitzer einer Funktion und Fehlerberichte zu finden.
Zu den Nachteilen gehören die Notwendigkeit, das Markup von Features beim Refactoring und Übertragen von Code von einem Ort zum anderen genau zu überwachen, und die Notwendigkeit zusätzlicher Leistung, um alle Informationen über das Markup zu sammeln.
Wie lösen Sie das Problem, Ihren Code zu besitzen? Und gibt es damit verbundene Probleme und vor allem deren Lösung?