Evolution du CI dans l'équipe de développement mobile

Aujourd'hui, la plupart des produits logiciels sont développés en équipe. Les conditions d’un développement réussi d’une équipe peuvent être représentées sous la forme d’un simple diagramme.

Evolution du CI dans l'équipe de développement mobile

Une fois que vous avez écrit votre code, vous devez vous assurer qu'il :

  1. Работает.
  2. Cela ne casse rien, y compris le code écrit par vos collègues.

Si les deux conditions sont remplies, alors vous êtes sur la voie du succès. Pour vérifier facilement ces conditions et ne pas s'écarter de la voie rentable, nous avons imaginé l'intégration continue.

CI est un workflow dans lequel vous intégrez votre code dans le code produit global aussi souvent que possible. Et vous n'intégrez pas seulement, mais vous vérifiez également en permanence que tout fonctionne. Comme vous devez vérifier beaucoup et souvent, cela vaut la peine de penser à l’automatisation. Vous pouvez tout vérifier manuellement, mais vous ne devriez pas le faire, et voici pourquoi.

  • Chers gens. Une heure de travail de n'importe quel programmeur coûte plus cher qu'une heure de travail de n'importe quel serveur.
  • Les gens font des fautes. Par conséquent, des situations peuvent survenir lorsque des tests ont été exécutés sur la mauvaise branche ou qu'un mauvais commit a été compilé pour les testeurs.
  • Les gens sont paresseux. De temps en temps, lorsque je termine une tâche, la pensée surgit : « Qu'y a-t-il à vérifier ? J'ai écrit deux lignes - tout fonctionne ! Je pense que certains d’entre vous ont aussi parfois de telles pensées. Mais vous devriez toujours vérifier.

Comment l'intégration continue a été mise en œuvre et développée au sein de l'équipe de développement mobile d'Avito, comment ils sont passés de 0 à 450 builds par jour et comment les machines de build s'assemblent 200 heures par jour, explique Nikolai Nesterov (nesterov) participe à tous les changements évolutifs de l'application Android CI/CD.

L'histoire est basée sur l'exemple d'une commande Android, mais la plupart des approches sont également applicables sur iOS.


Il était une fois une personne qui travaillait dans l’équipe Avito Android. Par définition, il n’avait besoin de rien de l’intégration continue : il n’y avait personne avec qui s’intégrer.

Mais l'application s'est développée, de plus en plus de nouvelles tâches sont apparues et l'équipe s'est agrandie en conséquence. À un moment donné, il est temps d'établir plus formellement un processus d'intégration de code. Il a été décidé d'utiliser le flux Git.

Evolution du CI dans l'équipe de développement mobile

Le concept de flux Git est bien connu : un projet a une branche de développement commune, et pour chaque nouvelle fonctionnalité, les développeurs coupent une branche distincte, s'y engagent, poussent, et lorsqu'ils souhaitent fusionner leur code dans la branche de développement, ouvrent une branche. demande de tirage. Pour partager des connaissances et discuter des approches, nous avons introduit la révision du code, c'est-à-dire que les collègues doivent vérifier et confirmer le code de chacun.

Chèques

Voir le code avec vos yeux, c'est cool, mais pas suffisant. C’est pourquoi des contrôles automatiques sont introduits.

  • Tout d'abord, nous vérifions Assemblage ARK.
  • Beaucoup Tests juin.
  • Nous considérons la couverture du code, puisque nous effectuons des tests.

Pour comprendre comment ces vérifications doivent être exécutées, examinons le processus de développement dans Avito.

On peut le représenter schématiquement ainsi :

  • Un développeur écrit du code sur son ordinateur portable. Vous pouvez exécuter des contrôles d'intégration ici - soit avec un hook de validation, soit simplement exécuter des contrôles en arrière-plan.
  • Une fois que le développeur a poussé le code, il ouvre une pull request. Pour que son code soit inclus dans la branche de développement, il est nécessaire de passer par une revue de code et de collecter le nombre de confirmations requis. Vous pouvez activer les vérifications et les builds ici : jusqu'à ce que toutes les builds soient réussies, la pull request ne peut pas être fusionnée.
  • Une fois la pull request fusionnée et le code inclus dans le développement, vous pouvez choisir un moment qui vous convient : par exemple, la nuit, lorsque tous les serveurs sont libres, et effectuer autant de vérifications que vous le souhaitez.

Personne n’aimait exécuter des analyses sur son ordinateur portable. Lorsqu'un développeur a terminé une fonctionnalité, il souhaite la pousser rapidement et ouvrir une pull request. Si à ce moment de longues vérifications sont lancées, cela n'est pas seulement très agréable, mais cela ralentit également le développement : pendant que l'ordinateur portable vérifie quelque chose, il est impossible de travailler normalement dessus.

Nous avons beaucoup aimé effectuer des contrôles la nuit, car il y a beaucoup de temps et de serveurs, on peut se déplacer. Mais, malheureusement, lorsque le code de fonctionnalité entre en développement, le développeur est beaucoup moins motivé pour corriger les erreurs trouvées par CI. Je me surprenais périodiquement à penser, en regardant toutes les erreurs trouvées dans le rapport du matin, que je les corrigerais un jour plus tard, car il y a maintenant une nouvelle tâche intéressante dans Jira que je veux juste commencer à faire.

Si les contrôles bloquent une pull request, alors il y a suffisamment de motivation, car jusqu'à ce que les builds deviennent verts, le code ne sera pas développé, ce qui signifie que la tâche ne sera pas terminée.

En conséquence, nous avons choisi la stratégie suivante : nous effectuons le maximum de contrôles possible la nuit, et lançons les plus critiques d'entre eux et, surtout, les plus rapides sur une pull request. Mais nous ne nous arrêtons pas là : en parallèle, nous optimisons la rapidité des contrôles afin de les transférer du mode nuit vers les pull request checks.

À cette époque, toutes nos builds étaient terminées assez rapidement, nous avons donc simplement inclus la build ARK, les tests Junit et les calculs de couverture de code comme bloqueur pour la pull request. Nous l’avons activé, y avons réfléchi et abandonné la couverture du code parce que nous pensions que nous n’en avions pas besoin.

Il nous a fallu deux jours pour mettre en place complètement le CI de base (ci-après le temps estimé est approximatif, nécessaire à l'échelle).

Après cela, nous avons commencé à réfléchir plus loin : vérifions-nous vraiment correctement ? Exécutons-nous correctement les builds sur les demandes d’extraction ?

Nous avons commencé le build sur le dernier commit de la branche à partir de laquelle la pull request a été ouverte. Mais les tests de ce commit ne peuvent que montrer que le code écrit par le développeur fonctionne. Mais ils ne prouvent pas qu’il n’a rien cassé. En fait, vous devez vérifier l’état de la branche de développement après la fusion d’une fonctionnalité.

Evolution du CI dans l'équipe de développement mobile

Pour ce faire, nous avons écrit un simple script bash prémerge.sh :

#!/usr/bin/env bash

set -e

git fetch origin develop

git merge origin/develop

Ici, toutes les dernières modifications apportées par develop sont simplement extraites et fusionnées dans la branche actuelle. Nous avons ajouté le script premerge.sh comme première étape dans toutes les versions et avons commencé à vérifier exactement ce que nous voulons, c'est-à-dire l'intégration.

Il a fallu trois jours pour localiser le problème, trouver une solution et écrire ce script.

L'application s'est développée, de plus en plus de tâches sont apparues, l'équipe s'est agrandie et premerge.sh a parfois commencé à nous décevoir. Le développement comportait des changements contradictoires qui ont interrompu la construction.

Un exemple de la façon dont cela se produit :

Evolution du CI dans l'équipe de développement mobile

Deux développeurs commencent simultanément à travailler sur les fonctionnalités A et B. Le développeur de la fonctionnalité A découvre une fonctionnalité inutilisée dans le projet answer() et, comme un bon boy-scout, l'enlève. Parallèlement, le développeur de la fonctionnalité B ajoute un nouvel appel à cette fonction dans sa branche.

Les développeurs terminent leur travail et ouvrent une pull request en même temps. Les builds sont lancées, premerge.sh vérifie les deux demandes d'extraction concernant le dernier état de développement - toutes les vérifications sont vertes. Après cela, la pull request de la fonctionnalité A est fusionnée, la pull request de la fonctionnalité B est fusionnée... Boum ! Le développement s'interrompt car le code de développement contient un appel à une fonction inexistante.

Evolution du CI dans l'équipe de développement mobile

Quand ça ne va pas se développer, c'est catastrophe locale. L'équipe entière ne peut rien collecter et le soumettre pour test.

Il se trouve que je travaillais le plus souvent sur des tâches d'infrastructure : analytique, réseau, bases de données. Autrement dit, c'est moi qui ai écrit ces fonctions et classes que d'autres développeurs utilisent. Pour cette raison, je me suis retrouvé très souvent dans des situations similaires. J'ai même accroché cette photo pendant un moment.

Evolution du CI dans l'équipe de développement mobile

Comme cela ne nous convenait pas, nous avons commencé à explorer les options permettant d’éviter cela.

Comment ne pas interrompre le développement

La première option: reconstruisez toutes les demandes d'extraction lors de la mise à jour du développement. Si, dans notre exemple, la pull request avec la fonctionnalité A est la première à être incluse dans le développement, la pull request de la fonctionnalité B sera reconstruite et, par conséquent, les vérifications échoueront en raison d'une erreur de compilation.

Pour comprendre combien de temps cela prendra, prenons un exemple avec deux PR. Nous ouvrons deux PR : deux builds, deux séries de contrôles. Une fois le premier PR fusionné dans le développement, le second doit être reconstruit. Au total, deux PR nécessitent trois séries de contrôles : 2 + 1 = 3.

En principe, ça va. Mais nous avons regardé les statistiques, et la situation typique dans notre équipe était de 10 PR ouverts, puis le nombre de contrôles est la somme de la progression : 10 + 9 +... + 1 = 55. C'est-à-dire accepter 10 PR, vous devez reconstruire 55 fois. Et c'est dans une situation idéale, lorsque tous les contrôles réussissent du premier coup, lorsque personne n'ouvre de pull request supplémentaire pendant que ces dizaines sont en cours de traitement.

Imaginez-vous comme un développeur qui doit être le premier à cliquer sur le bouton « fusionner », car si un voisin fait cela, vous devrez alors attendre que toutes les constructions soient à nouveau exécutées... Non, ça ne marchera pas , cela ralentira sérieusement le développement.

Deuxième manière possible : collecter les demandes d'extraction après la révision du code. Autrement dit, vous ouvrez une pull request, collectez le nombre requis d'approbations auprès de vos collègues, corrigez ce qui est nécessaire, puis lancez les builds. S’ils réussissent, la demande d’extraction est fusionnée dans le développement. Dans ce cas, il n'y a pas de redémarrages supplémentaires, mais le retour est fortement ralenti. En tant que développeur, lorsque j'ouvre une pull request, je veux immédiatement voir si cela va fonctionner. Par exemple, si un test échoue, vous devez le corriger rapidement. Dans le cas d’un build retardé, les retours ralentissent, et donc tout le développement. Cela ne nous convenait pas non plus.

En conséquence, il ne restait que la troisième option - vélo. Tout notre code, toutes nos sources sont stockés dans un référentiel sur le serveur Bitbucket. En conséquence, nous avons dû développer un plugin pour Bitbucket.

Evolution du CI dans l'équipe de développement mobile

Ce plugin remplace le mécanisme de fusion des demandes d'extraction. Le début est standard : le PR s'ouvre, tous les assemblys sont lancés, la revue de code est terminée. Mais une fois la révision du code terminée et que le développeur décide de cliquer sur « fusionner », le plugin vérifie par rapport à quel état de développement les vérifications ont été exécutées. Si le développement a été mis à jour après les builds, le plugin ne permettra pas à une telle pull request d'être fusionnée dans la branche principale. Il s'agira simplement de redémarrer les builds d'un développement relativement récent.

Evolution du CI dans l'équipe de développement mobile

Dans notre exemple avec des modifications contradictoires, ces builds échoueront en raison d'une erreur de compilation. En conséquence, le développeur de la fonctionnalité B devra corriger le code, relancer les vérifications, puis le plugin appliquera automatiquement la pull request.

Avant d'implémenter ce plugin, nous avions en moyenne 2,7 évaluations par demande d'extraction. Avec le plugin, il y a eu 3,6 lancements. Cela nous convenait.

Il est à noter que ce plugin présente un inconvénient : il ne redémarre la build qu'une seule fois. Autrement dit, il existe encore une petite fenêtre par laquelle des changements contradictoires peuvent se développer. Mais la probabilité que cela se produise est faible, et nous avons fait ce compromis entre le nombre de démarrages et la probabilité d’échec. En deux ans, il n'a tiré qu'une seule fois, ce n'était donc probablement pas en vain.

Il nous a fallu deux semaines pour écrire la première version du plugin Bitbucket.

Nouveaux chèques

Pendant ce temps, notre équipe a continué à s’agrandir. De nouveaux chèques ont été ajoutés.

Nous avons pensé : pourquoi faire des erreurs si elles peuvent être évitées ? Et c'est pourquoi ils ont mis en œuvre analyse de code statique. Nous avons commencé avec Lint, qui est inclus dans le SDK Android. Mais à cette époque, il ne savait pas du tout comment travailler avec le code Kotlin, et nous avions déjà 75 % de l'application écrite en Kotlin. Par conséquent, ceux intégrés ont été ajoutés aux peluches Vérifications Android Studio.

Pour ce faire, nous avons dû faire beaucoup de perversion : prendre Android Studio, le packager dans Docker et l'exécuter sur CI avec un moniteur virtuel, pour qu'il pense qu'il fonctionne sur un vrai ordinateur portable. Mais ça a marché.

C'est aussi à cette époque que nous avons commencé à beaucoup écrire essais d'instruments et mis en œuvre test de capture d'écran. C'est à ce moment-là qu'une capture d'écran de référence est générée pour une petite vue distincte, et le test consiste à prendre une capture d'écran de la vue et à la comparer avec la norme directement pixel par pixel. S'il y a une différence, cela signifie que la mise en page s'est mal passée quelque part ou que quelque chose ne va pas dans les styles.

Mais les tests d’instrumentation et les tests de capture d’écran doivent être exécutés sur des appareils : sur des émulateurs ou sur des appareils réels. Étant donné qu’il existe de nombreux tests et qu’ils sont exécutés fréquemment, une ferme entière est nécessaire. Démarrer votre propre ferme demande trop de main-d'œuvre, nous avons donc trouvé une option toute faite : Firebase Test Lab.

Laboratoire de tests Firebase

Il a été choisi parce que Firebase est un produit Google, ce qui signifie qu'il doit être fiable et peu susceptible de mourir. Les prix sont raisonnables : 5 $ par heure de fonctionnement d'un appareil réel, 1 $ par heure de fonctionnement d'un émulateur.

Il a fallu environ trois semaines pour implémenter Firebase Test Lab dans notre CI.

Mais l'équipe a continué à grandir et Firebase, malheureusement, a commencé à nous décevoir. A cette époque, il n’avait aucun SLA. Parfois, Firebase nous faisait attendre que le nombre requis d'appareils soit libre pour les tests et ne commençait pas à les exécuter immédiatement, comme nous le souhaitions. Faire la queue a duré jusqu'à une demi-heure, ce qui est très long. Des tests d'instrumentation ont été effectués sur chaque PR, les retards ont vraiment ralenti le développement, et la facture mensuelle s'est ensuite accompagnée d'une somme rondelette. En général, il a été décidé d'abandonner Firebase et de travailler en interne, l'équipe s'étant suffisamment agrandie.

Docker + Python + bash

Nous avons pris Docker, y avons inséré des émulateurs, écrit un programme simple en Python, qui démarre au bon moment le nombre requis d'émulateurs dans la bonne version et les arrête si nécessaire. Et bien sûr, quelques scripts bash : que serions-nous sans eux ?

Il a fallu cinq semaines pour créer notre propre environnement de test.

En conséquence, pour chaque pull request, il y avait une longue liste de contrôles bloquant la fusion :

  • Assemblage ARK ;
  • Tests juin ;
  • Peluche;
  • Vérifications Android Studio ;
  • Tests d'instruments ;
  • Tests de capture d'écran.

Cela a évité de nombreuses pannes possibles. Techniquement, tout a fonctionné, mais les développeurs se sont plaints du fait que l'attente des résultats était trop longue.

Combien de temps est trop long ? Nous avons téléchargé les données de Bitbucket et TeamCity dans le système d'analyse et avons réalisé que temps d'attente moyen 45 minutes. Autrement dit, un développeur, lors de l'ouverture d'une pull request, attend en moyenne 45 minutes les résultats de la construction. À mon avis, c’est beaucoup et on ne peut pas travailler comme ça.

Bien entendu, nous avons décidé d’accélérer toutes nos builds.

Accélérons

Étant donné que les builds restent souvent dans une file d'attente, la première chose que nous faisons est acheté plus de matériel — le développement extensif est le plus simple. Les builds ont cessé de faire la queue, mais le temps d'attente n'a que légèrement diminué, car certains contrôles eux-mêmes prenaient très longtemps.

Supprimer les chèques trop longs

Notre intégration continue pourrait détecter ces types d’erreurs et de problèmes.

  • Ne va pas. CI peut détecter une erreur de compilation lorsque quelque chose ne se construit pas en raison de modifications contradictoires. Comme je l'ai déjà dit, personne ne peut rien assembler, le développement s'arrête et tout le monde devient nerveux.
  • Bug de comportement. Par exemple, lorsque l'application est créée, mais qu'elle plante lorsque vous appuyez sur un bouton, ou que le bouton n'est pas enfoncé du tout. C'est mauvais car un tel bug peut atteindre l'utilisateur.
  • Bug dans la mise en page. Par exemple, un bouton est cliqué mais s'est déplacé de 10 pixels vers la gauche.
  • Augmentation de la dette technique.

Après avoir examiné cette liste, nous avons réalisé que seuls les deux premiers points sont critiques. Nous voulons d’abord détecter ces problèmes. Les bugs dans la mise en page sont découverts au stade de la révision de la conception et peuvent ensuite être facilement corrigés. Le traitement de la dette technique nécessite un processus et une planification distincts, nous avons donc décidé de ne pas le tester sur une pull request.

Sur la base de ce classement, nous avons bouleversé toute la liste des contrôles. Charpie barrée et a reporté son lancement du jour au lendemain : juste pour pouvoir produire un rapport sur les nombreux problèmes qu'il y avait dans le projet. Nous avons convenu de travailler séparément avec la dette technique, et Les contrôles Android Studio ont été complètement abandonnés. Android Studio dans Docker pour exécuter des inspections semble intéressant, mais pose beaucoup de problèmes de support. Toute mise à jour vers les versions d'Android Studio signifie une lutte contre des bugs incompréhensibles. Il était également difficile de prendre en charge les tests de capture d'écran, car la bibliothèque n'était pas très stable et il y avait des faux positifs. Les tests de capture d'écran ont été supprimés de la liste de contrôle.

En conséquence, il nous restait :

  • Assemblage ARK ;
  • Tests juin ;
  • Tests instrumentaux.

Cache distant Gradle

Sans contrôles lourds, tout s’est amélioré. Mais il n’y a pas de limite à la perfection !

Notre application était déjà divisée en environ 150 modules gradle. Le cache distant Gradle fonctionne généralement bien dans ce cas, nous avons donc décidé de l'essayer.

Le cache distant Gradle est un service qui peut mettre en cache des artefacts de construction pour des tâches individuelles dans des modules individuels. Gradle, au lieu de compiler le code, utilise HTTP pour accéder au cache distant et demander si quelqu'un a déjà effectué cette tâche. Si oui, il télécharge simplement le résultat.

L'exécution du cache distant Gradle est simple car Gradle fournit une image Docker. Nous avons réussi à le faire en trois heures.

Il suffisait de lancer Docker et d'écrire une ligne dans le projet. Mais même si le lancement peut être rapide, il faudra beaucoup de temps pour que tout fonctionne correctement.

Vous trouverez ci-dessous le graphique des échecs de cache.

Evolution du CI dans l'équipe de développement mobile

Au tout début, le pourcentage de cache miss était d'environ 65. Après trois semaines, nous avons réussi à augmenter cette valeur à 20 %. Il s'est avéré que les tâches collectées par l'application Android ont d'étranges dépendances transitives, à cause desquelles Gradle a manqué le cache.

En connectant le cache, nous avons considérablement accéléré la construction. Mais en plus de l'assemblage, il y a aussi des tests d'instrumentation, et ils prennent beaucoup de temps. Il n’est peut-être pas nécessaire d’exécuter tous les tests pour chaque demande d’extraction. Pour le savoir, nous utilisons l’analyse d’impact.

Analyse d'impact

Sur une pull request, nous collectons git diff et trouvons les modules Gradle modifiés.

Evolution du CI dans l'équipe de développement mobile

Il est logique d'exécuter uniquement des tests d'instrumentation qui vérifient les modules modifiés et tous les modules qui en dépendent. Cela ne sert à rien de lancer des tests sur les modules voisins : le code n'y a pas changé et rien ne peut casser.

Les tests d'instrumentation ne sont pas si simples, car ils doivent être situés dans le module Application de niveau supérieur. Nous avons utilisé des heuristiques avec analyse de bytecode pour comprendre à quel module appartient chaque test.

La mise à niveau du fonctionnement des tests d'instrumentation afin qu'ils testent uniquement les modules concernés a pris environ huit semaines.

Les mesures visant à accélérer les inspections ont donné de bons résultats. De 45 minutes on est passé à environ 15 minutes. C’est déjà normal d’attendre un quart d’heure pour un build.

Mais maintenant, les développeurs commencent à se plaindre de ne pas comprendre quelles versions sont lancées, où voir le journal, pourquoi la version est rouge, quel test a échoué, etc.

Evolution du CI dans l'équipe de développement mobile

Les problèmes de retour ralentissent le développement, nous avons donc essayé de fournir des informations aussi claires et détaillées que possible sur chaque PR et build. Nous avons commencé par des commentaires dans Bitbucket au PR, indiquant quelle version avait échoué et pourquoi, et avons écrit des messages ciblés dans Slack. En fin de compte, nous avons créé un tableau de bord PR pour la page avec une liste de toutes les builds en cours d'exécution et leur statut : en file d'attente, en cours d'exécution, en panne ou terminé. Vous pouvez cliquer sur la construction et accéder à son journal.

Evolution du CI dans l'équipe de développement mobile

Six semaines ont été consacrées à un feedback détaillé.

Plans

Passons à l'histoire récente. Après avoir résolu le problème des commentaires, nous avons atteint un nouveau niveau : nous avons décidé de créer notre propre ferme d'émulateurs. Lorsqu’il existe de nombreux tests et émulateurs, ils sont difficiles à gérer. En conséquence, tous nos émulateurs ont migré vers le cluster k8s avec une gestion flexible des ressources.

De plus, il existe d'autres projets.

  • Retourner les peluches (et autres analyses statiques). Nous travaillons déjà dans ce sens.
  • Exécutez tout sur un bloqueur de relations publiques tests de bout en bout sur toutes les versions du SDK.

Nous avons donc retracé l'histoire du développement de l'intégration continue dans Avito. Maintenant, je veux donner quelques conseils d'un point de vue expérimenté.

Conseils

Si je devais donner un seul conseil, ce serait celui-ci :

Soyez prudent avec les scripts shell !

Bash est un outil très flexible et puissant, il est très pratique et rapide pour écrire des scripts. Mais avec cela, vous pouvez tomber dans un piège et, malheureusement, nous y sommes tombés.

Tout a commencé avec de simples scripts exécutés sur nos machines de build :

#!/usr/bin/env bash
./gradlew assembleDebug

Mais, comme vous le savez, tout évolue et devient plus compliqué avec le temps - exécutons un script à partir d'un autre, passons-y quelques paramètres - à la fin, nous avons dû écrire une fonction qui détermine à quel niveau d'imbrication bash nous nous trouvons maintenant pour pour insérer les guillemets nécessaires, pour que tout démarre.

Evolution du CI dans l'équipe de développement mobile

Vous pouvez imaginer les coûts de main-d’œuvre nécessaires au développement de tels scripts. Je vous conseille de ne pas tomber dans ce piège.

Que peut-on remplacer?

  • N’importe quel langage de script. Écrire à Script Python ou Kotlin plus pratique car il s'agit de programmation, pas de scripts.
  • Ou décrivez toute la logique de construction sous la forme Tâches de graduation personnalisées pour votre projet.

Nous avons décidé de choisir la deuxième option, et maintenant nous supprimons systématiquement tous les scripts bash et écrivons de nombreuses tâches de graduation personnalisées.

Astuce n°2 : stockez l’infrastructure dans le code.

C'est pratique lorsque le paramètre d'intégration continue n'est pas stocké dans l'interface utilisateur de Jenkins ou TeamCity, etc., mais sous forme de fichiers texte directement dans le référentiel du projet. Cela donne la possibilité de version. Il ne sera pas difficile de restaurer ou de créer le code sur une autre branche.

Les scripts peuvent être stockés dans un projet. Que faire de l'environnement ?

Astuce n°3 : Docker peut vous aider en matière d'environnement.

Cela aidera certainement les développeurs Android ; iOS n’en a pas encore, malheureusement.

Ceci est un exemple de fichier Docker simple contenant jdk et android-sdk :

FROM openjdk:8

ENV SDK_URL="https://dl.google.com/android/repository/sdk-tools-linux-3859397.zip" 
    ANDROID_HOME="/usr/local/android-sdk" 
    ANDROID_VERSION=26 
    ANDROID_BUILD_TOOLS_VERSION=26.0.2

# Download Android SDK
RUN mkdir "$ANDROID_HOME" .android 
    && cd "$ANDROID_HOME" 
    && curl -o sdk.zip $SDK_URL 
    && unzip sdk.zip 
    && rm sdk.zip 
    && yes | $ANDROID_HOME/tools/bin/sdkmanager --licenses

# Install Android Build Tool and Libraries
RUN $ANDROID_HOME/tools/bin/sdkmanager --update
RUN $ANDROID_HOME/tools/bin/sdkmanager "build-tools;${ANDROID_BUILD_TOOLS_VERSION}" 
    "platforms;android-${ANDROID_VERSION}" 
    "platform-tools"

RUN mkdir /application
WORKDIR /application

Après avoir écrit ce fichier Docker (je vais vous dire un secret, vous n'êtes pas obligé de l'écrire, mais extrayez-le simplement depuis GitHub) et assemblé l'image, vous obtenez une machine virtuelle sur laquelle vous pouvez créer l'application et exécutez des tests Junit.

Les deux principales raisons pour lesquelles cela a du sens sont l’évolutivité et la répétabilité. En utilisant docker, vous pouvez rapidement lever une douzaine d'agents de build qui auront exactement le même environnement que le précédent. Cela rend la vie des ingénieurs CI beaucoup plus facile. Il est assez facile de pousser le SDK Android dans Docker, mais avec les émulateurs, c'est un peu plus difficile : vous devrez travailler un peu plus dur (ou télécharger à nouveau le SDK terminé depuis GitHub).

Conseil n°4 : n’oubliez pas que les inspections ne se font pas pour les inspections, mais pour les personnes.

Un retour rapide et, surtout, clair est très important pour les développeurs : qu'est-ce qui a échoué, quel test a échoué, où puis-je voir le journal de construction.

Conseil n°5 : Soyez pragmatique lors du développement de l’intégration continue.

Comprenez clairement les types d’erreurs que vous souhaitez éviter, la quantité de ressources, de temps et de temps informatique que vous êtes prêt à consacrer. Des contrôles trop longs peuvent par exemple être reportés du jour au lendemain. Et ceux d'entre eux qui détectent des erreurs peu importantes devraient être complètement abandonnés.

Conseil n°6 : utilisez des outils prêts à l'emploi.

De nombreuses entreprises proposent désormais du cloud CI.

Evolution du CI dans l'équipe de développement mobile

C'est une bonne solution pour les petites équipes. Vous n'avez besoin de rien prendre en charge, il vous suffit de payer un peu d'argent, de créer votre application et même d'exécuter des tests d'instrumentation.

Conseil n°7 : Dans une grande équipe, les solutions internes sont plus rentables.

Mais tôt ou tard, à mesure que l’équipe s’agrandit, les solutions internes deviendront plus rentables. Il y a un problème avec ces décisions. Il existe une loi des rendements décroissants en économie : dans tout projet, chaque amélioration ultérieure est de plus en plus difficile et nécessite de plus en plus d'investissements.

L'économie décrit toute notre vie, y compris l'intégration continue. J'ai construit un planning des coûts de main d'œuvre pour chaque étape de développement de notre Intégration Continue.

Evolution du CI dans l'équipe de développement mobile

Il est clair que toute amélioration devient de plus en plus difficile. En regardant ce graphique, vous comprendrez que l'intégration continue doit être développée en fonction de la croissance de la taille de l'équipe. Pour une équipe de deux personnes, passer 50 jours à développer une ferme d’émulateurs interne est une idée médiocre. Mais en même temps, pour une grande équipe, ne pas faire du tout d'intégration continue est aussi une mauvaise idée, à cause des problèmes d'intégration, de fixation de la communication, etc. cela prendra encore plus de temps.

Nous sommes partis de l’idée que l’automatisation était nécessaire parce que les gens coûtent cher, font des erreurs et sont paresseux. Mais les gens automatisent aussi. Par conséquent, les mêmes problèmes s’appliquent à l’automatisation.

  • L'automatisation coûte cher. N'oubliez pas l'horaire de travail.
  • En matière d’automatisation, les gens font des erreurs.
  • Parfois, il est très paresseux d’automatiser, car tout fonctionne ainsi. Pourquoi améliorer autre chose, pourquoi toute cette intégration continue ?

Mais j'ai des statistiques : des erreurs sont détectées dans 20 % des assemblages. Et ce n’est pas parce que nos développeurs écrivent mal le code. En effet, les développeurs sont convaincus que s'ils commettent une erreur, celle-ci ne finira pas en développement, mais sera détectée par des contrôles automatisés. En conséquence, les développeurs peuvent passer plus de temps à écrire du code et des choses intéressantes, plutôt que d'exécuter et de tester quelque chose localement.

Pratiquez l’intégration continue. Mais avec modération.

À propos, Nikolai Nesterov donne non seulement d'excellents rapports lui-même, mais est également membre du comité du programme. AppsConf et aide les autres à préparer des discours significatifs pour vous. L'exhaustivité et l'utilité du programme de la prochaine conférence peuvent être évaluées par sujets dans programme. Et pour plus de détails, rendez-vous sur Infospace les 22 et 23 avril.

Source: habr.com

Ajouter un commentaire