L’industrialisation des projets d’application mobile
Historique
L’histoire des smartphones commence en 2008. Ces appareils ont cela de smart qu’ils ne sont plus vendus avec un panel de fonctionnalités dont on peut trouver la liste exhaustive dans un mode d’emploi. Désormais, il est possible d’accéder à un marché (un store) depuis lequel l’utilisateur peut, à sa convenance, ajouter des fonctionnalités à son appareil. De cette manière, son téléphone a autant de fonctionnalités qu’il le désire sans pour autant s’en encombrer d’autres, superflues, inutiles pour son utilisateur.
Mais cette révolution ne s’arrête pas là. Les stores sont désormais ouverts aux développeurs tiers. Un nouveau pan technologique est mis à disposition du grand public (des développeurs au moins). A partir de ce moment, n’importe qui peut prétendre avoir une place sur ce marché et se retrouver dans la poche du quidam.
Le temps à passé et ces concepts n’ont que peu évolué. Les utilisateurs de smartphone ont accès à quelque 3,5 millions d’apps sur le Play Store Android et 1,6 millions sur l’App Store d’Apple (octobre 2022). En revanche, la façon de produire ces applications a radicalement évolué. En 2015, la durée de vie d’une application était de 2 à 3 ans. Pour cause, les OS évoluaient très rapidement et la maintenance et l’évolution des applications étaient très complexes. Aujourd’hui, une application correctement conçue peut vivre, être maintenue et subir des évolutions majeures pendant 5 à 8 ans, voire davantage.
Beaucoup de facteurs entrent en compte pour ce calcul de durée de vie. Le principal étant l’architecture retenue pour la conception du projet, mais cela fera l’objet d’un autre article. Un autre aspect majeur est la maturité de l’industrialisation du-dit projet. Un développeur motivé peut intégralement produire son application, depuis le développement, jusqu’à sa publication sur les stores sans autres outils que sa plateforme de développement. Toutefois, cela est extrêmement chronophage. Le temps et les efforts investis se font au détriment d’autres aspects du projet tels que la qualité et la sécurité.
Nous allons voir ensemble les premières étapes de l’industrialisation d’un projet mobile pour optimiser son temps de production et assurer une maintenabilité à moyen terme.
Les bases
La gestion des versions
Le tout premier point à aborder lorsque que l’on souhaite faire passer son projet dans une dimension professionnelle, c’est la gestion des versions. Aujourd’hui il est impensable qu’un développeur réalise un projet, jour après jour, seul et sur son poste de travail uniquement.
> Problématique : “Le client demande à ce que tu mettes en pause le développement de cette fonctionnalité pour que tu te concentres sur la correction d’un problème sur l’application qui est actuellement sur les stores”.
Les développements d’une évolution étant engagés, il est impossible de supprimer ce qui a été fait, pour revenir à l’état de la version actuellement en production. Comment reprendre son travail par la suite ?
La réponse à cette question est simple : la gestion de version. Il existe aujourd’hui plusieurs solutions bien que la plus répandue soit Git. Ce logiciel en lignes de commande permet de travailler en parallèle sur plusieurs versions d’un même projet grâce au concept de branche. Ainsi, il est possible de travailler sur de futures évolutions en même temps que sur des correctifs urgents. Les branches peuvent finalement être fusionnées pour retrouver un projet comportant l’ensemble des développements effectués sur différentes branches.
Les dépôts distants
L’évolution naturelle de l’utilisation d’un outil de gestion de versions est la mise en place d’un dépôt distant.
> Problématique : “Un incendie s’est déclaré au travail, les ordis sont fichus » / “Je peux t’aider ?”
Les solutions de dépôt distants sont légions. Les plus connus étant GitHub, BitBucket et GitLab. C’est sur cette dernière que Webqam base ses projets. Un dépôt distant permet de synchroniser des projets versionnés. Cela répond à deux problématiques directes :
- Le code versionné ne se trouve plus uniquement sur une machine. Si un problème venait à arriver à un ordinateur de développement, le code source du projet serait toujours accessible sur ce dépôt distant.
- Le code versionné distant est accessible par plusieurs personnes. Ainsi plusieurs développeurs peuvent travailler sur différents aspects du projet avant de mettre en commun leur travail.
Les conventions d’utilisation de Git
Le développement collaboratif présente l’avantage d’augmenter la vitesse de production. Toutefois il faut que cela se fasse de manière correcte.
> Problématique : “J’ai travaillé sur A, tu as travaillé sur B. Et au final on a ni A ni B”
Evidemment, travailler à plusieurs sur un projet (qui n’est qu’un ensemble de fichiers textes finalement) peut conduire à ce que plusieurs personnes modifient le même fichier aux mêmes endroits mais pas avec les mêmes intentions. Cela conduit inéluctablement à des conflits. C’est le terme utilisé par Git lorsqu’une section de code est différente d’une branche à l’autre et que la fusion est impossible. Pour éviter les écueils classiques des conflits (perte de code, régression, …) il est important de mettre en place parmi les développeurs, les bonnes pratiques à respecter quant à la gestion des branches. Cela concerne leur nommage, leur utilisation, la façon de les fusionner dans le tronc commun du projet, etc…
Bien que des conventions générales existent, aucun outil ne permet de gérer cela mieux que la communication et l’entente entre les membres d’une équipe.
Les conventions d’utilisation des dépôts distants
Avoir plusieurs membres dans une équipe de développement, c’est autant de façon de voir les choses. Bien qu’il n’y ait jamais de vérité absolue sur comment résoudre un problème algorithmique, de conception ou de mise en forme, il est bon d’en discuter en groupe pour trouver un consensus sur la solution la plus performante et la plus maintenable.
> Problématique : “Moi, j’aurai pas fait comme ça”
Les outils de dépôt distant proposent très souvent des fonctionnalités permettant la revue de code. Cette étape intervient juste avant de fusionner les développements effectués sur une branche avec une autre. Il est alors possible de voir de manière synthétique les ajouts qui sont apportés au code source. Ce moment est crucial car cette synthèse peut être revue par plusieurs développeurs. C’est autant de paire d’yeux capables de déceler des améliorations possibles ou des erreurs qui auraient pu se glisser dans ce qui a été développé. C’est également une opportunité pour des développeurs de niveaux différents d’apprendre sur le travail des autres. Enfin, cela garantit une homogénéisation de la production : le contrôle du respect des conventions étant l’affaire de tous.
Une syntaxe sympathique
Le code source d’un projet informatique, quel qu’il soit, se résume finalement à un ensemble de fichiers texte. Et rien n’est plus libre qu’un curseur sur une page blanche. Mais en vue de mettre en place une démarche d’industrialisation, il est important d’apporter un peu de rigueur à cela.
> Problématique : “`f(x) = y` ou `(x) => { return y }`”
Quelles que soient les conventions retenues pour un projet, il est important de les appliquer tout au long de la durée de vie du projet. Cela le rend plus lisible, plus facile à reprendre. Pour cela, il existe des outils appelés linter. Grâce à eux, il est possible, à travers un fichier de configuration, de vérifier que certaines conventions de syntaxe soient respectées.
Il peut nous prévenir si on laisse dans le code destiné à la production des logs de debug. Ou si
> var x=4;
aurait pu s’écrire :
> let x = 4
Il en ressort une impression de qualité générale qui rend plus agréable la maintenance du projet au fil du temps.
Les tests unitaires
Un projet maintenu pendant des mois, voire des années, finit fatalement par régresser. Parce qu’il devient trop vaste, trop complexe, que les équipes se sont succédées pour le faire évoluer, des effets de bords finissent inévitablement par arriver.
> Problématique : « Ça marchait hier, ça. Non ?”
Pierre angulaire de la qualité de code : les tests unitaires. Souvent rébarbatifs à écrire, ils sont les garants de l’absence de régression. L’idée est d’écrire du code, pour tester du code. Avec un jeu de données prédéfini que l’on va injecter dans notre projet, on va venir vérifier le résultat produit. Puisque les données d’entrée sont connues, le résultat peut être connu à l’avance également. Il est primordial de jouer régulièrement ces tests afin de valider que les évolutions successives n’ont pas d’effet de bord sur le projet de base.
Il y a une réflexion à apporter sur ce qui est testé unitairement ou non. Il est inutile de vérifier qu’un texte apparaît de la bonne couleur après qu’on lui ait demandé de changer de couleur. Cela n’apporte aucune indication quant à une éventuelle régression. La pertinence de ces tests se fait sur des règles fonctionnelles :
- L’article se trouve bien dans le panier après avoir cliqué sur le bouton “acheter”
- La page de redirection est celle attendue
- L’ensemble des paramètres est correctement compilé à la soumission du formulaire
- …
Pour cela, il est important de concevoir une architecture dans laquelle les règles fonctionnelles (dites “métier”) sont circonscrites à une et unique strate. Ainsi, nous sauront facilement identifier les portions de code ou les tests seront les plus pertinents.
Couverture de test
Quelle que soit la taille de l’équipe dédiée à votre projet, la communication reste la base de tout. Mais pour échanger sur certains sujets, des mots, des images ou des schémas ne suffisent plus.
> Problématique : “Mais si, c’est hyper bien fait, je te jure !”
Rien de vaut des valeurs chiffrées. Pour les échanges autour du projet, la communication interne, les KPI… Pour cela, il est intéressant de se baser sur des outils d’analyse de code permettant de mettre une valeur sur la quantité de code testé. La couverture de test est un excellent indicateur. Cela représente la quantité de code qui est testé lors de l’exécution des tests unitaires. Une valeur importante nous rassure sur le fait que peu de régressions sont possibles sur un projet, ou qu’elles seront facilement identifiables quand elles se produiront. Il est très intéressant de voir surveiller cette valeur au fil du temps pour assurer un taux de couverture important au fil des évolutions.
Automatisation
Tous ces outils sont extrêmement pratiques et contribuent à assurer une qualité respectable d’un projet informatique. Toutefois, ce n’est en rien de l’industrialisation. Aujourd’hui, un projet développé en agence doit embarquer tous ces éléments et plus encore.
Ce qu’on a vu plus haut
Le concept d’intégration continue consiste à exécuter un ensemble de scripts à chaque fois qu’une version est mise à jour sur un dépôt distant. De cette manière, il est possible d’avoir un retour quasi instantané sur les constats des linters, sur les résultats des tests unitaires, et même sur la capacité du projet à être compilé. Phase finale d’un développement, la compilation permet d’obtenir un artefact exécutable sur machine (un logiciel, une application, etc…).
Nous touchons ici du doigt un nouvel aspect très intéressant de la production industrielle. L’artefact compilé n’est plus généré depuis la machine d’un développeur, mais bien par une machine tierce : la Plateforme d’Intégration Continue. Cette plateforme prend la forme d’un serveur sur lequel est exécutée la solution de dépôt distant. La différence est de taille car lors de l’étape de compilation, énormément de facteurs peuvent entrer en jeu. L’OS et sa version, les dépendances installées localement, etc… Dans le cas d’une compilation sur une machine dédiée, c’est cet artefact qui fait foi. Si la PIC ne peut pas compiler le projet, même s’il compile sur les machines de développement, c’est sur ces dernières que l’erreur est présente.
Nous arrivons à un moment où la qualité du code est évaluée automatiquement en continue, ou des rapports sur cette qualité peuvent être générés et des alertes levées en cas de problème, les artefacts livrés sont produits par une machine tierce. Tout cela sans intervention de la part d’un corps de métier spécialisé. C’est cela qui définit l’industrialisation.
Cas particulier des applications mobiles
Tout ce qui a été énoncé plus haut est vrai, quelle que soit la typologie de votre projet : web, client lourd monolithique, back-end découplé, application mobile… Mais dans le cas de ces dernières, il faut aller plus loin. Les contraintes imposées par les plateformes mobiles et les stores de Google et d’Apple sont plus importantes.
Par exemple, il est impossible de compiler une application iOS sur autre chose qu’une machine Apple. C’est extrêmement contraignant quant au choix de la machine servant de plateforme d’intégration continue. Pire encore, quand bien même l’automatisation de la compilation d’une application iOS est possible, il faut encore signer numériquement cette application afin de pouvoir l’installer sur des appareils de tests.
Ces deux postulats sont le point de départ de l’utilisation d’un outil supplémentaire : Fastlane.
Fastlane est un outil en ligne de commande, permettant d’automatiser tout ce qui touche à la compilation des applications mobiles, leur signature et bien plus encore.
La signature des applications mobiles
iOS et Android n’autorisent pas l’installation d’applications qui n’ont pas été préalablement signées par un développeur déclaré au préalable auprès de leurs services. Cette déclaration permet l’obtention d’un certificat, permettant la signature. Ce certificat, qui en plus a une durée de vie limitée, est assez complexe à obtenir et une fausse manipulation au moment de sa génération peut révoquer les certificats de tous les autres membres de l’équipe. Et une fois que tous les membres de l’équipe ont leur certificats, il en manque encore un pour la machine d’intégration continue…
Pour éviter ces opérations fastidieuses, fastlane propose une solution très simple à mettre en place. Un script qui automatise la génération d’un certificat et qui le stocke sur un dépôt distant. Ainsi, pour un même projet, tous les membres d’une équipe de développement et la PIC partagent le même certificat. Encore mieux, fastlane se charge de le renouveler automatiquement en cas d’expiration !
La génération (ou la récupération, s’il existe) de ce certificat est facilement intégrable dans les scripts qui sont exécutés par la PIC au moment de la synchronisation d’une version sur le dépôt distant. C’était la pierre manquante pour compléter une intégration continue d’un projet mobile. Mais nous pouvons encore aller plus loin !
Captures d’écrans
Soumettre une application sur les stores signifie se conformer a énormément de règles. Il y a des dizaines de formulaires à remplir pour justifier de l’âge à partir duquel un utilisateur peut se servir de l’application, ou pour déclarer quel type de données vont transiter par l’appareil…
La plus complexe de ces règles est sans doute de fournir des captures d’écrans à jour. Une application peut se voir refuser sa place sur le store si les captures d’écrans ne reflètent pas l’état actuel de l’application. Il est obligatoire de les fournir dans différentes résolutions et dans chaque langue concerné par l’application ! Imaginez un projet simple de 5 écrans, dont les captures doivent être fournies selon (au moins) 3 résolutions différentes, pour les 5 langues principales du continent européen. Cela fait 5 x 3 x 5 = 75 captures à générer, et vous n’avez fait qu’un seul OS.
Vous l’aurez compris, c’est une tâche indispensable mais extrêmement et chronophage. On ne peut se permettre de passer autant de temps à le faire manuellement à chaque mise à jour de l’application.
Une fois de plus, fastlane va venir à notre rescousse. Grâce à un autre de ses scripts, il est capable de simuler, sur des appareils virtuels, l’exécution de l’application et d’un parcours pré-programmé. Durant ce parcours, les captures d’écrans seront effectuées, enregistrées et renommées dans un répertoire, prêtes à être déposées sur les stores. Quand bien même, l’exécution de ce script est excessivement longue (parfois plus d’une heure), cela est réalisé automatiquement sur une machine distincte, ce qui n’impacte pas le temps de votre équipe de développement.
Déploiement continu
Le déploiement continu est l’étape suivant celle de l’intégration continue. Une fois l’artéfact généré, ont va le déployer sur un canal de diffusion dédié : directement sur les stores ou sur un dépôt réservés aux tests. Une fois encore, fastlane dispose d’un script pour s’acquitter de cette tâche.
Ainsi, à partir d’une action commune de la part d’un développeur (la synchronisation d’une branche sur un dépôt distant), les script sont exécutés, les tests effectués, les métriques validés, les artefacts générés. Et ce jusqu’à la mise à disposition sur les stores !
Une infrastructure mise en place de cette manière assure qu’un projet sera durable et de qualité supérieure.
Et si ???
On parlait de votre projet
Notre équipe d'experts sera ravie d'étudier avec vous les enjeux et le périmètre de votre projet. Contactez-nous dès maintenant pour en discuter, ce sera peut-être l’occasion de venir nous rencontrer au WebqamPlex (et de faire un tour de toboggan) !