Gemeinsame Komponenten von verschiedenen Teams. Yandex-Bericht

Das Erstellen und Verwalten gemeinsamer Komponenten ist ein Prozess, an dem viele Teams beteiligt sein müssen. Der Leiter des Shared Components Service von Yandex Vladimir Grinenko Tadatuta erklärte, wie ihre Entwicklung das engagierte Lego-Team übertroffen hat, wie wir mit Lerna ein auf GitHub basierendes Mono-Repository erstellt und kanarische Releases mit der Implementierung von Services direkt in CI eingerichtet haben, was benötigt wurde und was noch zu sein.



"Freut mich, euch alle willkommen zu heißen." Mein Name ist Vladimir, ich mache übliche Dinge in Yandex-Schnittstellen. Ich möchte über sie sprechen. Wenn Sie unsere Dienste nicht sehr intensiv nutzen, haben Sie wahrscheinlich eine Frage: Was setzen wir alle? Was gibt es zu setzen?





In den Suchergebnissen befindet sich eine Liste mit Antworten. Manchmal befindet sich rechts eine Spalte. Jeder von euch wird wahrscheinlich an einem Tag fertig werden. Wenn Sie sich daran erinnern, dass es verschiedene Browser usw. gibt, fügen wir einen weiteren Tag hinzu, um Fehler zu beheben, und dann wird jeder damit fertig.



Jemand wird sich daran erinnern, dass es noch eine solche Schnittstelle gibt. Unter Berücksichtigung all der kleinen Dinge, die Sie ihm noch eine Woche geben können, können Sie es versuchen. Und Dima hat uns gerade gesagt, dass es so viele von uns gibt, dass wir unsere eigene Schule brauchen. Und all diese Leute machen die ganze Zeit Seiten. Stellen Sie sich vor, sie kommen jeden Tag zur Arbeit und setzen sich? Klar ist da noch etwas anderes.



In der Tat sind die Dienstleistungen in Yandex in der Tat mehr. Und es gibt noch ein bisschen mehr als auf dieser Folie. Hinter jedem solchen Link befindet sich eine Reihe verschiedener Schnittstellen mit großer Variabilität. Sie sind für verschiedene Geräte in verschiedenen Sprachen. Sie arbeiten manchmal sogar in Autos und anderen verschiedenen seltsamen Dingen.



Yandex ist heute nicht nur das Internet, nicht nur verschiedene Waren mit Lagern, Lieferung und all dem. Autos gelb fahren. Und nicht nur was man essen kann und nicht nur Eisenstücke. Und nicht nur alle Arten von automatischen Intelligenzen. All dies wird jedoch durch die Tatsache vereint, dass für jedes Element Schnittstellen benötigt werden. Oft - sehr reich. Yandex ist Hunderte von verschiedenen großen Dienstleistungen. Wir schaffen jeden Tag etwas Neues. Wir haben Tausende von Mitarbeitern, darunter Hunderte von Front-End-Entwicklern und Schnittstellenentwicklern. Diese Leute arbeiten in verschiedenen Büros, leben in verschiedenen Zeitzonen, ständig kommen neue Leute zur Arbeit.

Gleichzeitig versuchen wir, soweit wir genug Kraft haben, es eintönig und einheitlich für die Benutzer zu machen.



Dies ist die Suche nach Dokumenten im Internet. Wenn wir jedoch zur Ausgabe von Bildern wechseln, stimmt der Header überein, obwohl dies ein separates Repository ist, das in einem völlig separaten Team arbeitet, möglicherweise sogar bei anderen Technologien. Es scheint, dass es kompliziert ist? Nun, sie haben zweimal einen Hut erfunden, wie eine einfache Sache. Jeder Knopf in der Kappe hat auch eine eigene, reichhaltige Innenwelt. Einige Popups erscheinen hier, etwas kann auch dort geschoben werden. All dies wird in verschiedene Sprachen übersetzt und funktioniert auf verschiedenen Plattformen. Und hier gehen wir zum Beispiel von den Bildern zum Video, und dies ist wieder ein neuer Dienst, ein anderes Team. Wieder ein Repository. Aber immer noch der gleiche Hut, obwohl es Unterschiede gibt. Und das alles muss einheitlich bleiben.

Was lohnt es sich, auf den Folien so umzuschalten, um sicherzustellen, dass auf dem Pixel nichts passiert ist? Wir versuchen dies zu verhindern.



Um die Skalierung etwas besser darzustellen, habe ich einen Screenshot des Repositorys erstellt, in dem nur der Front-End-Code für neue Browser gespeichert ist - nur die Ausgabe von Dokumenten ohne Bilder und Videos. Es gibt Zehntausende von Commits und fast 400 Mitwirkende. Dies ist nur im Layout, nur ein Projekt. Hier ist eine Liste der blauen Links, die Sie gewohnt sind zu sehen.

Sergey Berezhnoy, mein Anführer, liebt diese Geschichte sehr, da wir uns so sehr im Unternehmen versammelt haben, dass ich möchte, dass unsere Interaktion wie in JavaScript zusammenarbeitet: Eins plus Eins ist mehr als zwei.



Und wir versuchen, aus der Interaktion alles herauszuholen, was wir können. Das erste, was unter solchen Bedingungen in den Sinn kommt, ist die Wiederverwendung. Hier beispielsweise ein Video-Snippet eines Dienstes in den Suchergebnissen für ein Video. Dies ist eine Art Bild mit einer Signatur und einigen anderen Elementen.



Wenn Sie weiter schauen, finden Sie hier die übliche Ausstellung von Dokumenten. Aber auch hier gibt es genau das gleiche Snippet.



Oder nehmen wir an, es gibt einen separaten Yandex.Air-Service, der etwas weniger als vollständig aus ähnlichen Snippets besteht.



Oder sagen wir, das Video-Snippet im Notifier, das sich auf verschiedenen Seiten des Portals befindet.



Oder hier ist ein Video-Snippet, wenn Sie es zu Ihren Favoriten hinzufügen und es dann in Ihren Sammlungen ansehen.



Klingt nach? Offensichtlich scheint es. Na und? Wenn wir den Diensten wirklich erlauben, unsere fertigen Komponenten einfach in andere Portaldienste zu integrieren, wird dieser Dienst aufgrund der Tatsache, dass Benutzer mit ihren Daten auf verschiedenen Websites interagieren können, offensichtlich mehr Benutzer erhalten. Es ist toll. Davon profitieren auch die Nutzer. Sie werden die gleichen Dinge gleichermaßen sehen. Sie werden sich wie gewohnt verhalten. Das heißt, man muss nicht immer wieder raten, was der Designer hier vorhatte und wie man damit umgeht.

Und schließlich wird das Unternehmen dadurch offensichtliche Einsparungen erzielen. Darüber hinaus scheint es nur so zu sein - was gibt es, um eine Videovorschau und eine Art Signatur zu erstellen? Um dies einfach so zu erhalten, müssen Sie viele verschiedene Experimente durchführen, verschiedene Hypothesen testen, Größen, Farben und Einrückungen auswählen. Fügen Sie möglicherweise einige Elemente hinzu und entfernen Sie sie, da sie nicht geflogen sind. Und was passiert ist, was wirklich funktioniert, ist das Ergebnis eines sehr langen Prozesses. Und wenn jedes Mal an jedem neuen Ort, um es erneut zu tun, ist dies eine enorme Anstrengung.

Stellen Sie sich jetzt vor. Nehmen wir an, wir haben etwas, das gut funktioniert. Überall, überall haben sie es implementiert, und dann haben sie ein neues Experiment durchgeführt und erkannt, was verbessert werden könnte. Und wieder müssen wir diese gesamte Implementierungskette wiederholen. Teuer



Ok, es scheint offensichtlich, gut wiederzuverwenden. Aber jetzt müssen wir eine Reihe neuer Probleme lösen. Sie müssen verstehen, wo Sie solchen neuen Code speichern können. Einerseits scheint es logisch zu sein. Hier haben wir ein Video-Snippet, es wird vom Videoteam erstellt, sie haben ein Repository mit ihrem Projekt. Sollte wahrscheinlich dort platziert werden. Aber wie kann man es dann an andere Repositories aller anderen Leute verteilen? Und wenn andere Leute etwas Eigenes in dieses Snippet bringen wollen? Wieder nicht klar.

Es ist notwendig, es irgendwie zu versionieren. Sie können nichts ändern, und so, voila, rollt plötzlich alles aus. Es muss etwas getestet werden. Darüber hinaus haben wir dies beispielsweise im Dienst des Videos selbst getestet. Aber was ist, wenn bei der Integration in einen anderen Dienst etwas kaputt geht? Wieder nicht klar.

Am Ende ist es irgendwie notwendig, irgendwie schnell genug die Lieferung an verschiedene Dienste sicherzustellen, denn es wird seltsam sein, wenn wir irgendwo die vorherige Version haben, irgendwo neu. Der Benutzer scheint auf dasselbe zu klicken, und es gibt ein anderes Verhalten. Und wir müssen Entwicklern verschiedener Teams irgendwie die Möglichkeit bieten, Änderungen an diesem gemeinsamen Code vorzunehmen. Wir müssen ihnen irgendwie beibringen, wie man alles benutzt. Wir haben einen langen Weg vor uns, um die Wiederverwendung von Schnittstellen bequem zu gestalten.



Wir haben seit undenklichen Zeiten in SVN angefangen und es war lampenartig und praktisch: ein Daddy mit HTML, genau wie in Bootstrap. Sie kopieren es zu sich selbst. Neben Papa mit Stilen gibt es eine Art JS, der dann wusste, wie man einfach etwas zeigt / versteckt. Und alle.



Irgendwie sah die Liste der Komponenten so aus. Hervorgehoben wird hier das für die Autorisierung zuständige b-domeg. Vielleicht erinnern Sie sich noch daran, dass es auf Yandex tatsächlich ein solches Formular für Login und Passwort mit einem Dach gab. Wir nannten das "Haus", obwohl es auf den Briefumschlag hinwies, weil sie normalerweise in die Post eingingen.

Dann haben wir eine ganze Methodik entwickelt, um gemeinsame Schnittstellen unterstützen zu können.



Die Bibliothek selbst innerhalb des Unternehmens hat eine eigene Website mit einer Suche und jeglicher Taxonomie erworben.



Das Repository sieht jetzt so aus. Sie sehen, auch fast 10 000 Commits und mehr als 100 Mitwirkende.



Aber dies ist der Ordner des B-Hauses in der neuen Reinkarnation. Jetzt sieht sie so aus. In einem halben Bildschirm befinden sich bereits mehr eigene Ordner.



Und so sieht die Seite heute aus.



Infolgedessen wird die gemeinsam genutzte Bibliothek in mehr als 360 Repositorys in Yandex verwendet. Und es gibt verschiedene Implementierungen, einen Debug-Release-Zyklus usw. Es scheint, dass wir hier eine gemeinsame Bibliothek haben, die wir jetzt überall verwenden können, und alles ist großartig. Das Problem der Einführung allgemeiner Dinge überall gelöst. Nicht wirklich.



Der Versuch, das Problem der Wiederverwendung zu lösen, wenn Sie bereits vorgefertigten Code haben, ist zu spät. Dies bedeutet, dass von dem Moment an, in dem der Designer das Layout der Services gezeichnet, an die Services und insbesondere an das Team verteilt hat, das sich mit gemeinsamen Komponenten befasst, einige Zeit vergangen ist. Zu diesem Zeitpunkt wird sich höchstwahrscheinlich herausstellen, dass bei jedem einzelnen Dienst oder zumindest bei mehreren von ihnen dasselbe Schnittstellenelement ebenfalls erstellt wurde. Sie haben sich irgendwie auf ihre eigene Weise versöhnt.

Und selbst wenn eine allgemeine Lösung später in der gemeinsam genutzten Bibliothek angezeigt wird, stellt sich heraus, dass Sie jetzt alles, was Sie für jeden Dienst abgeschlossen haben, erneut implementieren müssen. Und das ist wieder ein Problem. Es ist sehr schwer zu rechtfertigen. Hier ist das Team. Sie hat ihre eigenen Ziele, alles funktioniert schon gut. Und wir sagen solche Dinge - schau, endlich haben wir ein gemeinsames kleines Ding, nimm es. Aber das Team ist so - wir haben schon genug Arbeit. Warum brauchen wir es? Außerdem wird uns dort plötzlich etwas nicht mehr passen? Wir wollen nicht.

Das zweite große Problem ist in der Tat die Verbreitung von Informationen über diese coolen neuen Komponenten. Nur weil es so viele Entwickler gibt, sind sie mit ihren täglichen Aufgaben beschäftigt. Und sie haben die Möglichkeit zu sitzen und zu studieren, was dort im Bereich des Gemeinsamen passiert, egal was es tatsächlich bedeutet.

Das größte Problem ist, dass es grundsätzlich unmöglich ist, die Probleme, die allen Diensten gemeinsam sind, mit einem einzigen engagierten Team zu lösen. Das heißt, wenn wir ein Team haben, das sich mit Video befasst und ein eigenes Snippet mit Video erstellt, ist es klar, dass wir ihnen zustimmen und dieses Snippet in einer zentralen Bibliothek erstellen werden. Es gibt jedoch direkt Tausende solcher Beispiele für verschiedene Dienste. Und hier reichen bestimmt keine Hände aus. Daher ist die einzige Lösung, dass sich jeder ständig mit allgemeinen Komponenten befassen sollte.



Und seltsamerweise müssen Sie nicht mit Schnittstellenentwicklern, sondern mit Designern beginnen. Sie verstehen das auch. Wir haben mehrere gleichzeitige Versuche im Inneren, damit dieser Prozess konvergiert. Designer machen Designsysteme. Ich hoffe wirklich, dass es früher oder später möglich sein wird, sie auf ein einziges gemeinsames System zu reduzieren, das alle Bedürfnisse berücksichtigt.



Jetzt gibt es mehrere von ihnen. Überraschenderweise sind die Aufgaben dort genau die gleichen: den Entwicklungsprozess zu beschleunigen, das Problem der Konsistenz zu lösen, das Rad nicht neu zu erfinden und die geleistete Arbeit nicht zu duplizieren.



Eine Möglichkeit, das Problem der Informationskommunikation zu lösen, besteht darin, Entwicklern die Möglichkeit zu geben, andere Teams kennenzulernen, einschließlich eines Teams, das sich mit allgemeinen Schnittstellenkomponenten befasst. Wir lösen es auf dieser Seite durch die Tatsache, dass wir ein Bootcamp haben, das es einem Entwickler, wenn er auf Yandex erscheint, zunächst ermöglicht, acht Wochen lang zu verschiedenen Teams zu gehen, zu sehen, wie es funktioniert, und dann zu entscheiden, wo es funktionieren soll . In dieser Zeit wird sich sein Horizont jedoch erheblich erweitern. Er wird dahin geführt, wo das ist.

Wir haben über gemeinsame Dinge gesprochen. Lassen Sie uns nun sehen, wie alles dem Entwicklungsprozess näher kommt. Nehmen wir an, wir haben eine gemeinsame Bibliothek namens Lego. Und wir möchten eine neue Funktion implementieren oder eine Art Überarbeitung vornehmen. Wir haben den Code korrigiert und die Version veröffentlicht.

Wir müssen diese Version in npm veröffentlichen und dann zum Repository eines Projekts gehen, in dem die Bibliothek verwendet wird, und diese Version implementieren. Höchstwahrscheinlich wird dadurch eine Nummer in package.json behoben. Starten Sie die Assembly neu. Vielleicht sogar die Paketsperre neu generieren, eine Pull-Anfrage erstellen und sehen, wie die Tests bestanden werden. Und was werden wir sehen?



Höchstwahrscheinlich werden wir sehen, dass ein Fehler aufgetreten ist. Weil es sehr schwierig ist, alle Verwendungsmöglichkeiten der Komponente für verschiedene Dienste vorherzusagen. Und wenn das passiert ist, was ist dann unser Ausweg? Also stellten wir fest, dass es nicht zusammen passte. Wir wiederholen weiter. Wir kehren mit einer gemeinsam genutzten Bibliothek zum Repository zurück, beheben den Fehler, veröffentlichen die neue Version, senden sie an npm, stellen sie bereit, führen die Tests aus und was ist das? Höchstwahrscheinlich wird ein Fehler erneut auftreten.

Und das ist immer noch gut, wenn wir es in einem Dienst implementieren und genau dort ist alles sofort kaputt gegangen. Es war viel trauriger, als wir das alles in zehn verschiedenen Diensten implementiert haben. Dort ist nichts kaputt gegangen. Wir haben bereits einen Smoothie gebraut oder was auch immer gebraucht wird. Zu diesem Zeitpunkt wird die Version im 11. Projekt oder im 25. Projekt eingeführt. Und es gibt einen Fehler. Wir kehren entlang der gesamten Kette zurück, erstellen einen Patch und implementieren ihn in allen vorherigen 20 Diensten. Darüber hinaus kann dieser Patch in einem der vorherigen explodieren. Gut und so weiter. Viel Spaß

Der einzige Ausweg scheint zu sein, dass Sie nur sehr schnell viel Code schreiben müssen. Wenn wir dann früher oder später höchstwahrscheinlich sehr, sehr schnell laufen, werden wir Zeit haben, eine Version für die Produktion bereitzustellen, in der es noch keinen Fehler gibt. Aber dann erscheint eine neue Funktion und nichts wird uns retten.

Okay. Tatsächlich kann das Schema wie folgt aussehen. Automatisierung wird uns helfen. Es geht im Allgemeinen um die ganze Geschichte. Wir hatten die Idee, dass ein Repository mit einer gemeinsamen Bibliothek nach dem Mono-Repository-Schema erstellt werden kann. Sie sind wahrscheinlich auf etwas gestoßen, jetzt gibt es viele solcher Projekte, insbesondere Infrastrukturprojekte. Alle Arten von Babel und solche Dinge leben wie Mono-Repositories, wenn sich viele verschiedene npm-Pakete darin befinden. Sie können irgendwie miteinander verbunden sein. Und sie werden zum Beispiel über Lerna verwaltet, so dass es angesichts der Abhängigkeiten bequem ist, all dies zu veröffentlichen.

Genau nach diesem Schema ist es möglich, ein Projekt zu organisieren, in dem alles Gemeinsame für das gesamte Unternehmen gespeichert ist. Möglicherweise gibt es eine Bibliothek, die in einem separaten Team beschäftigt ist. Und es kann auch Pakete geben, die jeder einzelne Service entwickelt, die er aber mit anderen teilen möchte.



Dann sieht die Schaltung so aus. Der Anfang ist nicht anders. Auf die eine oder andere Weise müssen wir Änderungen am allgemeinen Code vornehmen. Und dann wollen wir mit Hilfe der Automatisierung auf einen Schlag Tests nicht nur neben diesem Code ausführen, sondern sofort in all jenen Projekten, in denen dieser gemeinsame Code eingebettet ist. Und sehen Sie ihr aggregiertes Ergebnis.

Selbst wenn dort ein Fehler aufgetreten ist, haben wir es immer noch nicht geschafft, eine Version zu veröffentlichen, sie in keiner npm zu veröffentlichen, wir haben sie nicht speziell mit unseren Händen implementiert, wir haben nicht alle diese zusätzlichen Anstrengungen unternommen. Wir haben einen Fehler gesehen, ihn sofort lokal behoben, erneut allgemeine Tests durchgeführt, und das ist alles in Produktion.



Wie sieht es in der Praxis aus? Hier ist eine Pull-Anfrage mit einem Fix. Hier können Sie sehen, dass die Automatisierung die erforderlichen Prüfer dort aufgefordert hat, um zu überprüfen, ob im Code alles in Ordnung ist. In der Tat kamen die Rezensenten und waren sich einig, dass alles in Ordnung war. Und in diesem Moment schreibt der Entwickler einfach einen speziellen / kanarischen Befehl direkt in die Pull-Anfrage.

Ein Roboter kommt und sagt - okay, ich habe eine Aufgabe für das nächste Wunder geschaffen. Das Wunder ist, dass jetzt eine kanarische Version mit diesen Änderungen veröffentlicht wurde, die automatisch in allen Repositorys implementiert wurde, in denen diese Komponente verwendet wird. Dort wurden wie in diesem Repository Autotests gestartet. Hier können Sie sehen, dass eine ganze Reihe von Überprüfungen gestartet wurden.

Hinter jedem Test können weitere hundert verschiedene Tests stehen. Es ist jedoch wichtig, dass wir zusätzlich zu den lokalen Tests, die wir separat in die Komponente schreiben können, auch Tests für jedes Projekt starten, in dem es implementiert wurde. Dort wurden bereits Integrationstests gestartet: Wir überprüfen, ob diese Komponente in der Umgebung, in der sie für den Service konzipiert ist, normal funktioniert. Dies garantiert uns bereits wirklich, dass wir nichts vergessen haben, wir haben niemandem etwas gebrochen. Wenn hier alles in Ordnung ist, können wir wirklich sicher eine Version veröffentlichen. Und wenn hier etwas schlecht ist, werden wir es hier beheben.

Es scheint, dass dies uns helfen sollte. Wenn Ihr Unternehmen über etwas Ähnliches verfügt, sehen Sie, dass es Teile gibt, die Sie möglicherweise wiederverwenden könnten. Im Moment müssen Sie sie jedoch neu anordnen, da keine Automatisierung vorhanden ist. Ich empfehle Ihnen, eine ähnliche Lösung zu finden.



Was haben wir bekommen? Das allgemeine Monorepository, in dem Linters neu erstellt werden. Das heißt, jeder schreibt den Code auf die gleiche Weise, er hat alle Arten von Tests. Jedes Team kann kommen, seine Komponente einsetzen und sie mit JS-Komponententests testen, sie mit Screenshots abdecken usw. Alles ist bereits sofort einsatzbereit. Die clevere Codeüberprüfung, die ich erwähnt habe. Dank umfangreicher interner Tools ist es hier wirklich klug.

Ist der Entwickler jetzt im Urlaub? Es ist sinnlos, ihn in eine Pull-Anfrage zu rufen, das System wird dies berücksichtigen. Ist der Entwickler krank? Das System wird dies ebenfalls berücksichtigen. Wenn beide Bedingungen nicht erfüllt sind und der Entwickler frei zu sein scheint, erhält er eine Benachrichtigung von einem seiner Messenger seiner Wahl. Und er ist so: Nein, jetzt bin ich mit etwas Dringendem oder bei einem Treffen beschäftigt. Er kann dorthin kommen und einfach den Befehl / busy schreiben. Das System wird automatisch verstehen, dass Sie den nächsten aus der Liste zuweisen müssen.

Der nächste Schritt besteht darin, dieselbe kanarische Version zu veröffentlichen. Das heißt, bei jeder Codeänderung müssen wir ein Servicepaket freigeben, das wir für verschiedene Services überprüfen können. Als Nächstes müssen wir Tests ausführen, wenn wir auf all diesen Diensten bereitstellen. Und wenn alles zusammen kam - starten Sie die Releases.

Wenn sich eine Änderung auf eine statische Aufladung auswirkt, die aus dem CDN geladen werden soll, müssen Sie sie automatisch separat veröffentlichen. . , , , , . , , , changelog - .

, , , , . , , .

, . . , , : , ? . , . . , .

Source: https://habr.com/ru/post/de460811/


All Articles