Je m’appelle Eduard Matsukov, je fais Taximeter - une application pour les pilotes Yandex.Taxi. Je suis engagé dans l'infrastructure et tout ce qui y est lié. Il y a quelque temps, j'ai fait un rapport - j'ai parlé de l'expérience de l'amitié TeamCity avec notre projet et avec les développeurs en général. Une partie distincte du rapport est consacrée à ce que Kotlin a à voir avec cela.
- Presque chaque jour, ils viennent à moi personnellement et à nos développeurs avec des questions. Et où obtenir l'assemblage? Et où trouver une telle branche? Pourquoi quelque chose est-il tombé? Où est le problème dans mon code? Pourquoi quelque chose ne fonctionne pas correctement? Pour ce faire, nous avons beaucoup d'infrastructures auto-écrites dans le projet, des plugins, divers hacks et astuces que nous utilisons. D'une part, pour faciliter la vie du développeur, d'autre part, pour mettre en œuvre des tâches métier spécifiques.


Et à un moment donné, bien sûr, nous utilisons également CI et TeamCity. Nous avons été confus - nous avons appris à TeamCity à être amis avec Kotlin et amené, nous pouvons dire, l'ensemble du CI et de l'ensemble à un tout nouveau niveau.
Mais d'abord, un peu d'histoire - pour comprendre comment nous en sommes arrivés là et pourquoi ce niveau j'appelle un canon séparé. TeamCity existe à Yandex depuis de nombreuses années. Nous devions vivre sur ce serveur partagé, où tout le backend, tout le frontend et, plus récemment, toutes les applications mobiles sont hébergées. Il y a environ deux ans, nous nous sommes tous réunis. Et chaque développeur configure chaque projet non pas comme il le souhaite, mais comme il le peut ou dans la mesure où il comprend à quel point il veut comprendre le système. Et il n'y a personne qui sait tout et sait comment. Peu de gens veulent s'embêter, étudier séparément les modèles, les jokers TeamCity. Par conséquent, tout le monde scie, qui est quoi.
Nous vivions sur ce serveur unique et l'année dernière, nous avons eu un accident à TeamCity. Environ une semaine était un temps d'arrêt complet. Les assemblées n'étaient pas collectées, les tests se plaignaient constamment. Quelqu'un a inventé, collecté localement.

Cela est dû au fait que notre serveur TeamCity était, en gros, une solution à hauteur de genou qui est soudainement devenue un excellent service. Il est utilisé par des milliers de développeurs sur Yandex. Bien sûr, il y avait une sorte de tolérance aux fautes, mais elle a également refusé. La prochaine fois que TeamCity a été mis à jour après le redémarrage, il s'est avéré que plusieurs disques durs s'étaient tout simplement effondrés, et nous n'avons pas pu remonter. Je devais sortir.
Nous devons tirer des conclusions de tout ce qui s'est passé. Et nous avons, bien sûr, tiré ces conclusions: nous avons analysé pourquoi cela s'est produit et comment nous assurer que cela ne se reproduise plus.
Tout d'abord, il est important que nous montions très longtemps et rétablissions notre service. Par service, j'entends à la fois un processus technique et en partie un processus métier pour la livraison banale des releases, pour le montage des demandes de pool. Nous avons perdu beaucoup d'artefacts, y compris les versions, nous avons perdu beaucoup de temps sur les demandes de pool, sur le fait que les tests ne pouvaient pas faire leur travail correctement. Et bien sûr, nous avons passé pas mal de temps à restaurer le projet à partir de zéro, à reconfigurer toute la structure, tout le système de construction. Et puis nous avons réalisé qu'il était temps de changer quelque chose et de configurer notre propre serveur.
Nous y sommes allés longtemps. Pour ne pas dire qu'un seul accident a conduit à cette conclusion. En général, nous avons décidé qu'il était temps d'aller à la montagne, de faire tout cela nous-mêmes. Nous avons commencé un déploiement de service. Cela se fait extrêmement rapidement: quelques jours et vous avez terminé. Lorsque vous déployez tout cela vous-même et que vous pouvez creuser à l'intérieur, en administrer un peu, alors des fonctionnalités intéressantes sont frappantes. L'un d'eux - le nouveau TeamCity vous permet de configurer le contrôle de version.

Le versioning est très primitif, mais en même temps très fiable, beau et cool. Tout ce qui est stocké dans TeamCity concernant votre ou tout autre projet peut être téléchargé en toute sécurité sur Git, et vous pouvez y vivre avec bonheur. Mais il y a quelques problèmes.
Le premier problème est que toutes les personnes ont l'habitude de travailler avec TeamCity exclusivement via l'interface, et cette habitude est difficile à éliminer. Il y a un petit hack de vie ici: vous pouvez simplement interdire tout changement de l'interface et forcer tout le monde à réapprendre. Notre équipe compte 2000 développeurs. Pas un bon moyen, n'est-ce pas?
En fait, les inconvénients s'arrêtent là. Le plus important est que les gens doivent réapprendre quelque chose de nouveau. Il faut donc leur donner du terrain afin de tirer une conclusion personnelle sur la raison pour laquelle cela est nécessaire. Et il est alors nécessaire que TeamCity, grâce au versionnage, ne permette pas d'appliquer des modifications qui cassent le système d'une manière ou d'une autre. TeamCity se replie sur la dernière révision stable.

Dans TeamCity, vous pouvez démarrer chaque projet pour ce versioning et le configurer de manière assez flexible.

Un peu de programme éducatif. Tous les projets dans TeamCity sont organisés dans un arbre. Il existe une sorte de racine commune, et plus loin vient une structure si simple. Chaque projet est en haut de ce graphique. Il peut agir comme un certain ensemble de configurations qui construisent quelque chose et comme parent pour d'autres projets.

Dans Git, vous pouvez expédier tout à la fois ou une pièce spécifique. Par exemple, si des collègues du backend avec le frontend ne veulent pas utiliser le versioning, s'il vous plaît, vous ne pouvez pas compter sur eux et sécuriser simplement votre projet personnel.

Vous pouvez mettre en place un système hiérarchique assez complexe, auquel notre équipe est finalement parvenue. Nous avons une grosse racine commune et quelques petites racines. Backend, développement mobile, frontend, Yandex.Food - ils vivent tous chacun dans leur propre référentiel séparé. Dans le même temps, les informations sur tous ces projets sont stockées dans un grand référentiel partagé - à la racine.
Après avoir enfin connecté ce versioning, installez-le avec tous vos collègues, où et comment vivra, qui sera engagé dans le support - après tout cela, vous devez faire un choix difficile.

TeamCity ne prend en charge que deux formats de configuration. Avec XML, je soupçonne que personne ne voudra travailler, nous avons donc choisi le deuxième format. Il vous permet de faire ces configurations sur un script Kotlin.

eamCity crée un projet Maven, un semblant de tout projet ordinaire. Vous pouvez faire l'une des deux choses suivantes: soit télécharger vers votre projet - Android, backend, cela n'a pas d'importance - soit le laisser en tant que projet autonome. Ensuite, vous aurez un référentiel indépendant avec un projet indépendant.

Quel est le plus de cette approche? Personnellement, moi et ces gars qui traitons notre infrastructure sur le backend et le frontend ont été immédiatement corrompus par quelque chose. Et même ceux qui ne connaissent pas Kotlin, qui en ont entendu parler pour la première fois, sont allés et ont commencé à lui enseigner.

Ces deux lignes créent l'ensemble du projet. C'est le dialecte de l'API TeamCity. L'API change chaque version principale. Il y a 2018-2, 2018-1, 2017, etc. Bientôt, espérons-le, le 2019e sera publié.
La deuxième ligne déclare simplement le projet.

Voici le projet lui-même. C'est du vrai code. Voilà à quoi ressemble notre référentiel racine maintenant. Rien de plus, rien de compliqué. Le seul travail manuel qui est requis ici est de créer manuellement l'UUID vous-même. TeamCity exige que chaque objet, chaque projet ait son propre identifiant unique. Vous pouvez y écrire n'importe quoi. J'utilise simplement le surnom standard de l'équipe uuidgen.
Ici commence l'aventure dans le Kotlin DSL. Je pense que c'est un langage complètement simple pour le mastering. En le téléchargeant sur IDEA, Eclipse ou tout autre IDE, vous pouvez obtenir toute la documentation, la mise en évidence, la saisie semi-automatique, des conseils. En fait, beaucoup d'entre eux manquent dans l'interface. Par conséquent, mon expérience personnelle dit que travailler avec le code est beaucoup plus pratique, plus simple et plus intuitif. Nous sommes toujours développeurs.

Quelque chose comme ça ressemble à une vraie configuration qui fonctionne maintenant en même temps, prenant en charge les configurations TeamCity elles-mêmes. Autrement dit, TeamCity construit ses propres configurations dans son propre environnement. Si tout va bien et que tout s'est mal passé, il l'envoie calmement en mémoire et réplique les modifications apportées à PostgreSQL. La base est déjà connectée au service lui-même. Et ici, ce sera un péché de ne pas utiliser toutes les fonctionnalités de Kotlin.

Dans ce cas, contrairement à XML, ces configurations peuvent être décrites en utilisant le polymorphisme, l'héritage - toutes les fonctionnalités du langage Kotlin sont autorisées. Le seul point important est que tout cela peut éventuellement se transformer en chaos qui existait avec nous avant que nous introduisions le versioning des configs sur le script Kotlin.

Mais, curieusement, ce chaos est devenu beaucoup moins. Parce qu'avant, il n'était pas tout à fait évident de savoir comment faire ce que je voulais, comment réaliser telle ou telle fonctionnalité? À partir du code, dans ma pratique, il est beaucoup plus facile de comprendre comment implémenter une fonctionnalité.
Les aventures les plus intéressantes commencent ici: comment implémenter certaines choses et comment, en principe, faciliter l'interaction du projet avec TeamCity?
Tout le monde ici présent sous une forme ou une autre prépare un communiqué, participant à son montage, dans la publication. Nous publions nos sorties sur différents canaux sur Google Play.


Nous avons la bêta, il y a des expériences, il y a stable. Nous utilisons un plugin spécial avec un robot qui publie des commentaires avec un rapport sur la construction de la version dans le ticket de version. Et tout cela est mis en place avec une si belle fenêtre. Il apparaît dès que vous essayez de créer une version. Ces questions ne peuvent être évitées.

À partir de l'interface TeamCity, cela ressemble à ceci. Pour comprendre immédiatement quoi, où, où et comment, vous devez lire chaque paramètre, vous devez expérimenter. De la documentation, en plus de ce qui est visible à l'écran, rien d'autre ne peut être glané.

En code, cela ressemble à ceci. Au moins jusqu'à présent, pendant six mois, personne n'est encore venu et a demandé - comment puis-je créer une fonctionnalité? Le plus souvent, le code est intuitivement clair.

En même temps, certaines choses se font tout simplement, mais cachées derrière plusieurs couches de l'interface. Nous devons marcher, aller et venir.

Voici un exemple de la façon dont la sécurité est implémentée dans TeamCity. Dans ma pratique, pour la plupart des gens, TeamCity semble être un système froid assez simple qui ne prend pas en charge l'intégration, par exemple, avec les services de sécurité. Par conséquent, tous les jetons, toutes les clés, toutes les informations d'identification avec nous sont le plus souvent cachés. Pourquoi pas?
En fait, TeamCity est sûr. Il sait comment créer son propre fichier spécial sur son serveur, qui s'appelle - credential json, comme indiqué. Et il crée une telle clé pour chaque jeton, pour chaque identifiant, que nous générons spécialement via l'interface. Vous pouvez déjà le mettre dans le code et être sûr que ces informations d'identification n'apparaîtront jamais dans les journaux TeamCity ou dans l'interface TeamCity. Le système peut littéralement couper ces clés de partout. L'ensemble de l'interface est, en gros, une sorte de décoration.

D'accord, nous avons configuré certains de nos paramètres, effectué un transfert des paramètres requis, par exemple, pour créer la version. Mais si on veut aller plus loin? Et nous voulions aller plus loin. Pendant l'assemblage, de nombreuses étapes différentes sont lancées. Nous exécutons plusieurs bibliothèques imbriquées qui s'appuient sur des référentiels complètement différents. Et nous voulions juste apporter de nouveaux changements. Tout cela est maintenant. Ne vous embêtez pas - par exemple, ne collectez pas de bibliothèque auxiliaire pour les demandes de pool, ne la téléchargez pas dans le référentiel maven, n'ajoutez pas de gestes supplémentaires à la demande de pool.

Nous venons de mettre en place l'ensemble chaîne. Je vais montrer à la fin à quel point il est évident et peu pratique de le faire à partir de l'interface, à mon avis personnel. Et là déjà jugez par vous-même.
Voici à quoi ressemble l'assemblage de chaîne dans l'interface.

Cela ressemble à ceci dans le code. Nous indiquons simplement exactement quelle configuration est dépendante et que faire si l'une des configurations n'a pas fonctionné ou a été annulée par l'utilisateur de l'extérieur. Dans ce cas, je ne veux pas du tout que l'assemblage démarre. Car à quoi ça sert si on n'a pas collecté toutes les bibliothèques dépendantes?
Dans le même esprit, toutes les autres choses se font. Et l'ensemble du projet dans TeamCity prend littéralement 500 lignes de code.

Il s'avère que vous pouvez transmettre un paramètre intéressant à travers toutes les dépendances. J'ai montré l'enchaînement pour une raison. Les chaînes sont pratiques, mais difficiles à préparer dans l'interface. Et TeamCity ne documente pas une caractéristique aussi importante que la transmission via des paramètres. À quoi ça sert? Supposons que, dans notre build à Gradle ou ailleurs, nous voulons être liés à un champ spécifique, transmettre la même adresse au ticket de sortie. Et nous voulons le faire une fois, et non pour chaque assemblage imbriqué.

TeamCity a un paramètre pas si évident et complètement non documenté - reverse.dep (dépendance inverse). Il jette tous les paramètres qui viennent après l'astérisque dans toutes les générations imbriquées.

En sortie, nous obtenons une structure aussi simple. Vous pouvez le compliquer et faire une imbrication aussi profonde que votre imagination ou vos besoins. Et pour être sûr que dans toutes ces dépendances, dans toutes ces configurations, tous nos paramètres que nous attendons à chaque étape du montage seront transmis. Prêt à répondre à vos questions. Merci à tous!