Mein Name ist Eduard Matsukov, ich mache Taximeter - eine Anwendung für Yandex.Taxi-Fahrer. Ich beschäftige mich mit Infrastruktur und allem, was damit zusammenhängt. Vor einiger Zeit habe ich einen Bericht erstellt - ich habe über die Erfahrungen der TeamCity-Freundschaft mit unserem Projekt und mit Entwicklern im Allgemeinen gesprochen. Ein separater Teil des Berichts widmet sich dem, was Kotlin damit zu tun hat.
- Fast jeden Tag kommen sie mit Fragen persönlich zu mir und zu unseren Entwicklern. Und wo bekommt man die Montage? Und wo bekommt man so einen Zweig? Warum ist etwas gefallen? Wo liegt das Problem in meinem Code? Warum funktioniert etwas nicht richtig? Zu diesem Zweck verfügen wir über eine Menge selbst geschriebener Infrastrukturen im Projekt, Plugins, verschiedene Hacks und Tricks, die wir verwenden. Einerseits, um dem Entwickler das Leben zu erleichtern, andererseits, um bestimmte Geschäftsaufgaben zu implementieren.


Und irgendwann verwenden wir natürlich auch CI und TeamCity. Wir waren verwirrt - wir haben TeamCity beigebracht, mit Kotlin befreundet zu sein, und wir können sagen, dass das gesamte CI und die gesamte Versammlung auf ein ganz neues Niveau gebracht wurden.
Aber zuerst ein wenig Geschichte - um zu verstehen, wie wir dazu gekommen sind und warum diese Ebene ich einen separaten Kanon nenne. TeamCity gibt es in Yandex seit vielen Jahren. Wir mussten auf diesem gemeinsam genutzten Server leben, auf dem das gesamte Backend, das gesamte Frontend und in jüngerer Zeit alle mobilen Anwendungen gehostet werden. Vor ungefähr zwei Jahren kamen wir alle zusammen. Und jeder Entwickler richtet jedes Projekt nicht so ein, wie er es möchte, sondern so weit er kann oder soweit er versteht, wie sehr er das System verstehen möchte. Und es gibt niemanden, der alles weiß und weiß wie. Nur wenige Leute wollen sich die Mühe machen, separat Vorlagen zu studieren, TeamCity Wilds. Deshalb sägt jeder, wer was ist.
Wir haben auf diesem einzigen Server gelebt und letztes Jahr hatten wir einen Unfall bei TeamCity. Ungefähr eine Woche war eine vollständige Ausfallzeit. Baugruppen wurden nicht gesammelt, die Tests beschwerten sich ständig. Jemand erfunden, vor Ort gesammelt.

Dies liegt an der Tatsache, dass unser TeamCity-Server grob gesagt eine kniehohe Lösung war, die sich plötzlich zu einem großartigen Service entwickelte. Es wird von Tausenden von Entwicklern auf Yandex verwendet. Natürlich gab es eine Art Fehlertoleranz, aber sie lehnte auch ab. Bei der nächsten Aktualisierung von TeamCity nach dem Neustart stellte sich heraus, dass mehrere Festplatten einfach zusammengebrochen waren und wir nicht wieder aufsteigen konnten. Ich musste raus.
Wir müssen aus allem, was passiert ist, Schlussfolgerungen ziehen. Und wir haben natürlich diese Schlussfolgerungen gezogen: Wir haben analysiert, warum es passiert ist und wie wir sicherstellen können, dass dies nicht noch einmal passiert.
Zuallererst ist es wichtig, dass wir sehr lange aufgestiegen sind und unseren Service wiederhergestellt haben. Mit Service meine ich sowohl einen technischen Prozess als auch teilweise einen Geschäftsprozess für die banale Lieferung von Releases, für die Zusammenstellung von Pool-Anfragen. Wir haben viele Artefakte verloren, einschließlich Release-Builds, und viel Zeit bei Pool-Anfragen verloren, da das Testen seine Aufgabe nicht richtig erfüllen konnte. Und natürlich haben wir viel Zeit damit verbracht, das Projekt von Grund auf neu zu erstellen und die gesamte Struktur, das gesamte Build-System neu zu konfigurieren. Und dann wurde uns klar, dass es Zeit war, etwas zu ändern und unseren eigenen Server einzurichten.
Wir sind lange dazu gegangen. Um nicht zu sagen, dass nur ein Unfall zu dieser Schlussfolgerung führte. Im Allgemeinen beschlossen wir, dass es Zeit war, auf den Berg zu gehen und das Ganze selbst zu machen. Wir haben einen Service-Rollout gestartet. Dies ist extrem schnell erledigt: ein paar Tage und Sie sind fertig. Wenn Sie all dies selbst bereitstellen und in das Innere graben, ein wenig verwalten können, fallen interessante Funktionen auf. Eines davon - mit dem neuen TeamCity können Sie die Versionierung konfigurieren.

Die Versionierung ist sehr primitiv, aber gleichzeitig sehr zuverlässig, schön und cool. Alles, was in TeamCity in Bezug auf Ihr oder ein anderes Projekt gespeichert ist, kann sicher auf Git hochgeladen werden, und Sie können glücklich davon leben. Es gibt jedoch einige Probleme.
Das erste Problem ist, dass alle Menschen daran gewöhnt sind, mit TeamCity ausschließlich über die Benutzeroberfläche zu arbeiten, und diese Gewohnheit ist schwer zu beseitigen. Hier gibt es einen kleinen Life-Hack: Sie können Änderungen an der Benutzeroberfläche einfach verbieten und alle Personen zum Neulernen zwingen. Unser Team hat 2.000 Entwickler. Kein guter Weg, oder?
In der Tat enden die Nachteile dort. Das wichtigste Minus ist, dass die Menschen für etwas Neues neu lernen müssen. Sie müssen also begründet werden, um eine persönliche Schlussfolgerung darüber zu ziehen, warum dies überhaupt notwendig ist. Und dann ist es notwendig, dass TeamCity dank der Versionierung keine Änderungen zulässt, die das System irgendwie beschädigen. TeamCity selbst greift auf die neueste stabile Version zurück.

In TeamCity können Sie jedes Projekt für diese Versionierung starten und ganz flexibel konfigurieren.

Ein bisschen Bildungsprogramm. Alle Projekte in TeamCity sind in einem Baum angeordnet. Es gibt eine Art gemeinsame Wurzel, und weiter davon kommt eine so einfache Struktur. Jedes Projekt steht oben in diesem Diagramm. Es kann als eine bestimmte Reihe von Konfigurationen fungieren, die etwas erstellen, und als übergeordnetes Element für andere Projekte.

In Git können Sie entweder alle auf einmal oder ein bestimmtes Stück versenden. Wenn beispielsweise Kollegen aus dem Backend mit dem Frontend keine Versionierung verwenden möchten, können Sie sich nicht auf sie verlassen und einfach Ihr persönliches Projekt sichern.

Sie können ein ziemlich komplexes hierarchisches System einrichten, zu dem unser Team schließlich gekommen ist. Wir haben eine gemeinsame große Wurzel und einige kleine Wurzeln. Backend, Mobile Development, Frontend, Yandex.Food - alle leben in einem eigenen Repository. Gleichzeitig werden Informationen zu all diesen Projekten in einem großen gemeinsam genutzten Repository gespeichert - im Stammverzeichnis.
Nachdem Sie diese Versionierung endgültig verbunden haben, installieren Sie sie mit all Ihren Kollegen, wo wer und wie leben wird, wer mit dem Support beschäftigt sein wird - nach all dem müssen Sie eine schwierige Wahl treffen.

TeamCity unterstützt nur zwei Konfigurationsformate. Ich vermute, dass mit XML niemand arbeiten möchte, deshalb haben wir das zweite Format gewählt. Sie können diese Konfigurationen in einem Kotlin-Skript vornehmen.

eamCity erstellt ein Maven-Projekt, ein Anschein eines gewöhnlichen Projekts. Sie können damit eines von zwei Dingen tun: entweder in Ihr Projekt hochladen - Android, Backend, es spielt keine Rolle - oder es als eigenständiges Projekt belassen. Dann haben Sie ein unabhängiges Repository mit einem unabhängigen Projekt.

Was ist das Plus dieses Ansatzes? Persönlich wurden ich und die Leute, die sich im Backend und Frontend mit unserer Infrastruktur befassen, sofort von etwas bestochen. Und selbst diejenigen, die mit Kotlin nicht vertraut sind und zum ersten Mal davon hörten, gingen und begannen, ihn zu unterrichten.

Diese beiden Zeilen bilden das gesamte Projekt. Dies ist der Dialekt der TeamCity-API. Die API ändert jede Hauptversion. Es gibt 2018-2, 2018-1, 2017 usw. Bald wird hoffentlich der 2019th veröffentlicht.
Die zweite Zeile deklariert einfach das Projekt.

Hier ist das Projekt selbst. Dies ist absolut realer Code. So sieht unser Root-Repository jetzt aus. Nichts extra, nichts kompliziertes. Die einzige manuelle Arbeit, die hier erforderlich ist, besteht darin, die UUID manuell selbst zu erstellen. TeamCity erfordert, dass jedes Objekt und jedes Projekt eine eigene eindeutige Kennung hat. Sie können dort alles schreiben. Ich benutze nur den Standard-Spitznamen uuidgen team.
Hier beginnt das Abenteuer im Kotlin DSL. Ich denke, dies ist eine völlig unkomplizierte Sprache für das Mastering. Durch Hochladen auf IDEA, Eclipse oder eine andere IDE erhalten Sie die gesamte Dokumentation, Hervorhebung, automatische Vervollständigung und Tipps. Tatsächlich fehlen viele von ihnen in der Benutzeroberfläche. Aus meiner persönlichen Erfahrung geht hervor, dass das Arbeiten mit dem Code viel bequemer, einfacher und intuitiver ist. Wir sind immer noch Entwickler.

So etwas sieht aus wie eine echte Konfiguration, die jetzt zur gleichen Zeit funktioniert und TeamCity-Konfigurationen selbst unterstützt. Das heißt, TeamCity erstellt seine eigenen Konfigurationen in seiner eigenen Umgebung. Wenn alles in Ordnung ist und alles schief gelaufen ist, sendet er es ruhig in den Speicher und repliziert die Änderungen an PostgreSQL. Die Basis ist bereits mit dem Dienst selbst verbunden. Und hier wird es eine Sünde sein, nicht alle Funktionen von Kotlin zu nutzen.

In diesem Fall können diese Konfigurationen im Gegensatz zu XML mithilfe von Polymorphismus und Vererbung beschrieben werden. Alle Funktionen der Kotlin-Sprache sind zulässig. Der einzige wichtige Punkt ist, dass all dies schließlich zu Chaos führen kann, das bei uns bestand, bevor wir die Versionierung der Konfigurationen im Kotlin-Skript eingeführt haben.

Aber seltsamerweise ist dieses Chaos viel geringer geworden. Denn vorher war nicht ganz klar, wie man macht, was ich will, wie man dieses oder jenes Feature erreicht? In meiner Praxis ist es anhand des Codes viel einfacher zu verstehen, wie eine Funktion implementiert wird.
Hier beginnen die interessantesten Abenteuer: Wie setzen wir einige Dinge um und wie erleichtern wir im Prinzip die Interaktion des Projekts mit TeamCity?
Jeder, der hier in der einen oder anderen Form anwesend ist, bereitet eine Veröffentlichung vor, die an seiner Versammlung in der Veröffentlichung teilnimmt. Wir veröffentlichen unsere Veröffentlichungen auf verschiedenen Kanälen bei Google Play.


Wir haben Beta, es gibt Experimente, es gibt stabile. Wir verwenden ein spezielles Plugin mit einem Roboter, der Kommentare mit einem Bericht über den Release-Build im Release-Ticket veröffentlicht. Und das alles ist mit einem so schönen Fenster eingerichtet. Es wird angezeigt, sobald Sie versuchen, eine Version zu erstellen. Diese Fragen können nicht vermieden werden.

In der TeamCity-Oberfläche sieht es ungefähr so aus. Um sofort zu verstehen, was, wo, wo und wie Sie jeden Parameter durchlesen müssen, müssen Sie experimentieren. Aus der Dokumentation kann neben dem, was auf dem Bildschirm angezeigt wird, nichts anderes entnommen werden.

Im Code sieht es so aus. Zumindest bis jetzt, seit einem halben Jahr, ist noch niemand gekommen und hat gefragt - wie mache ich ein Feature? Meistens ist aus dem Code alles intuitiv klar.

Gleichzeitig werden einige Dinge ganz einfach erledigt, aber hinter mehreren Ebenen der Benutzeroberfläche versteckt. Wir müssen gehen, hin und her gehen.

Hier ist ein Beispiel dafür, wie Sicherheit in TeamCity implementiert wird. In meiner Praxis scheint TeamCity für die meisten Menschen ein ziemlich einfaches Cold-System zu sein, das die Integration beispielsweise in Sicherheitsdienste nicht unterstützt. Daher stachen alle Token, alle Schlüssel, alle Anmeldeinformationen bei uns am häufigsten offen heraus. Warum nicht?
In der Tat ist TeamCity sicher. Er weiß, wie er auf seinem Server eine eigene Spezialdatei erstellt, die wie gezeigt als "Credential Json" bezeichnet wird. Und er erstellt einen solchen Schlüssel für jedes Token, für jeden Berechtigungsnachweis, den wir speziell über die Schnittstelle generieren. Sie können es bereits in den Code einfügen und sicherstellen, dass dieser Berechtigungsnachweis niemals in TeamCity-Protokollen oder in der TeamCity-Benutzeroberfläche angezeigt wird. Das System kann diese Schlüssel buchstäblich von überall abschneiden. Die gesamte Oberfläche ist grob gesagt eine Art Dekoration.

Okay, wir haben einige unserer Parameter eingerichtet und die erforderlichen Parameter weitergeleitet, um beispielsweise die Version zu erstellen. Aber was ist, wenn wir weiter gehen wollen? Und wir wollten noch weiter gehen. Während der Montage werden viele verschiedene Schritte gestartet. Wir führen mehrere verschachtelte Bibliotheken aus, die aus völlig unterschiedlichen Repositorys erstellt werden. Und wir wollten nur neue Veränderungen herbeiführen. Das alles ist jetzt. Machen Sie sich keine Sorgen - sammeln Sie beispielsweise keine Hilfsbibliothek für Poolanforderungen, laden Sie sie nicht in das Maven-Repository hoch und fügen Sie der Poolanforderung keine zusätzlichen Gesten hinzu.

Wir haben gerade die Kettenbaugruppe eingerichtet. Ich werde bis zum Ende zeigen, wie offensichtlich und unpraktisch es meiner persönlichen Meinung nach ist, dies über die Benutzeroberfläche zu tun. Und da urteilen Sie schon selbst.
So sieht die Kettenbaugruppe in der Schnittstelle aus.

Im Code sieht es ungefähr so aus. Wir geben einfach genau an, welche Konfiguration abhängig ist und was zu tun ist, wenn eine der Konfigurationen nicht funktioniert hat oder vom Benutzer von außen abgebrochen wurde. In diesem Fall möchte ich nicht, dass die Assembly überhaupt gestartet wird. Denn worum geht es, wenn wir nicht alle abhängigen Bibliotheken gesammelt haben?
Um den gleichen Geist herum werden alle anderen Dinge getan. Das gesamte Projekt in TeamCity umfasst buchstäblich 500 Codezeilen.

Es stellt sich heraus, dass Sie einige interessante Parameter über alle Abhängigkeiten weiterleiten können. Ich habe aus einem bestimmten Grund Verkettung gezeigt. Ketten sind praktisch, aber in der Benutzeroberfläche schwer vorzubereiten. Und TeamCity dokumentiert keine so wichtige Funktion wie das Weiterleiten über Parameter. Wofür ist das? Angenommen, wir möchten in unserem Build in Gradle oder anderswo an ein bestimmtes Feld gebunden sein und dieselbe Adresse an das Release-Ticket weiterleiten. Und wir möchten dies einmal tun und nicht für jede verschachtelte Assembly.

TeamCity hat einen nicht so offensichtlichen und vollständig nicht dokumentierten Parameter - reverse.dep (umgekehrte Abhängigkeit). Es wirft alle Parameter, die nach dem Sternchen stehen, in alle verschachtelten Builds.

Am Ausgang kommen wir zu einer so einfachen Struktur. Sie können es komplizieren und das Verschachteln so tief machen, wie Sie es sich vorstellen oder brauchen. Und um sicherzugehen, dass in all diesen Abhängigkeiten, in all diesen Konfigurationen alle unsere Parameter, die wir bei jedem Schritt der Assembly erwarten, weitergeleitet werden. Bereit, Ihre Fragen zu beantworten. Danke an alle!