Qu'est-ce que le Release Engineering ?

Ou ma réponse longue à "tu fais quoi dans la vie ?"

S’il est une question à laquelle j’ai bien du mal à répondre depuis un an, c’est « qu’est-ce que tu fais dans la vie ? ».

Enfin, pas tout à fait, puisqu’à celle-ci je réponds fièrement que je suis release engineer chez Scality. Celle qui me donne du fil à retordre, par contre, est la question qui vient inévitablement ensuite : ça consiste en quoi ?

Que l’on se rassure : je sais très bien en quoi consiste mon travail ! Simplement, il est assez difficile de l’expliquer à n’importe qui en quelques minutes avec les mains, sans risquer de trop simplifier ou de ne pas assez en dire. Ce billet est là pour que je puisse garder sous le coude ma réponse à cette question, celle qui, au-delà de la rapide explication mondaine que personne ne retient jamais, décrit comment je vois mon métier et pourquoi il me plait.

Un "multiplicateur de force"

Pour commencer, j’emprunterai les mots que John O’Duinn (directeur de l’équipe release engineering chez Mozilla) a utilisés dans un Google TechTalk intitulé Release Engineering as Force Multiplier.

Le cas de Mozilla

Mozilla édite le célèbre navigateur web Firefox, qui compte parmi les principaux acteurs du "marché" des navigateurs web sur desktop, comme en atteste cette statistique datant de Décembre 2016 :

Navigateur Part d’utilisation
Google Chrome 56.43%
Microsoft Internet Explorer 7.7%
Mozilla Firefox 11.1%
Apple Safari 14.5%

Maintenant, mettons cette donnée en perspective en examinant l’effectif des entreprises qui éditent ces logiciels :

Entreprise Nombre d’employés
Google (Alphabet) 72 053
Microsoft 120 849
Mozilla Corporation 1000
Apple 116 000

Ne voyez-vous rien qui choque ? Mozilla est un David qui se bat à armes égales contre des Goliaths 72 à 120 fois plus grands que lui !

Le cas de Scality

On pourrait croire qu’il s’agit d’une simple singularité, et arguer que Firefox est lui-même un logiciel Open Source, donc que les stats précédentes ne tiennent pas compte du nombre réel de développeurs qui travaillent sur les produits, alors permettez-moi de vous montrer ce qu’il en est pour ma propre entreprise, qui édite un logiciel propriétaire de stockage objet distribué. Et commençons par le rapport Gartner d’octobre 2016 sur ce marché :

Gartner Magic Quadrant (Octobre 2016) sur les systèmes de stockage distribués
Le Gartner Magic Quadrant sur les systèmes de stockage distribués (Octobre 2016)

Sans équivoque markéteuse, Scality est l’un des trois leaders de ce marché, face à IBM et Dell EMC. Et en termes d’effectifs ?

Entreprise Nombre d’employés
Scality 210
Dell EMC 70 000
IBM 377 257 (en 2015)

Le moins que l’on puisse dire, c’est que Scality est dans une posture similaire à celle de Mozilla sur son marché, face à deux mastodontes qui font 350 à plus de 1000 fois sa taille !

Quel est leur secret ?

Pas de vantardise mal placée : ni les développeurs de Mozilla, ni ceux de Scality ne sont des super-héros. Par contre, ce que ces deux entreprises ont en commun et qui leur permet d’entrer (et rester) en compétition avec des produits portés par des armées d’ingénieurs, c’est une équipe de Release Engineering, dont le rôle principal est d’optimiser la capacité des équipes à livrer un produit de qualité, à un rythme aussi rapide et régulier que possible.

En somme, mon métier consiste à aborder la régularité et la qualité des releases comme un problème d’ingénierie à part entière : l’optimisation du système que constitue l’équipe de développement de mon entreprise. Ce faisant, le release engineering agit comme un levier, un multiplicateur de force, permettant à 10 personnes d’accomplir le travail d’un millier.

Cela n’a rien de nouveau ni de magique. En fait, le siècle précédent a vu le même phénomène se produire à de multiples reprises dans l’industrie, avec en particulier le Fordisme dans les années 1900, et surtout le Toyotisme dans les années 1960.

Voyons un peu comment ça se présente dans la réalité de l’édition de logiciels.

Un cas d'école

Pour bien se rendre compte des tenants et aboutissants de ce métier, examinons un cas d’école inspiré des deux dernières années d’existence de ma société. Encore une fois, je ne prétends pas couvrir la totalité des aspects du métier : ce qui suit est une vue partielle et partiale du Release Engineering. Mais j’estime qu’elle permet de bien sentir le domaine.

Identifions le problème : quand faire appel au RelEng ?

Je l’ai écrit plus haut : le release engineering est un métier d’optimisation. Si vous êtes développeur, vous connaissez probablement cette fameuse phrase que l’on attribue à Donald Knuth : premature optimization is the root of all evil. En ce sens, il ne convient d’optimiser que ce qui est optimisable : si l’optimisation n’a aucun problème à résoudre, alors elle ne sert à rien et risque même de faire plus de mal que de bien.

Pour ce qui est du release engineering, le problème qu’il cherche à résoudre est celui de la qualité et du rythme de sortie d’un logiciel. Ainsi, il convient de l’envisager dans une entreprise qui correspond à un ou plusieurs des critères suivants :

  • Qui ne fait pas confiance en la qualité de ses releases, au point qu’une mise en production devient source de stress ;
  • Qui subit de grosses irrégularités sur le rythme des sorties, parce que les ingénieurs qui développent le produit préfère attendre d’avoir suffisamment testé le produit pour avoir confiance en sa qualité, quitte à prendre un délai supplémentaire et imprévu par rapport à la date de sortie ;
  • Qui a un rythme de livraison trop bas, parce que les nouvelles fonctionnalités prennent un temps démesurément long à intégrer.

C’était complètement le cas de Scality il y a 2 ans : en 2015, l’entreprise n’a sorti qu’une nouvelle version de son produit principal (le Scality Ring), contenant seulement deux nouvelles fonctionnalités par rapport à la version précédente. Ça, c’est ce qu’on appelle une situation problématique, et c’est la raison pour laquelle Scality a monté une équipe RelEng fin 2015.

Pas d’optimisation sans mesure !

Voilà une autre maxime que les ingénieurs expérimentés martellent à tout bout de champ : pour optimiser quelque chose, il faut OBLIGATOIREMENT le mesurer. Il faut savoir que tel bout de code est responsable de la lenteur du programme et qu’il s’exécute en 100ms, pour se donner un objectif à atteindre (par exemple, réduire son temps d’exécution à 20 ou 5ms).

Alors quand il s’agit de code, c’est facile et bien joli : on mesure le temps d’exécution ou la quantité de mémoire consommée par telle ou telle fonction, mais quand on veut optimiser le rythme de parution des nouvelles fonctionnalités d’un produit donné, que diable faut-il mesurer ?

Il n’existe aucune réponse absolue à cette question, mais voici le raisonnement que nous avons tenu dans mon équipe.

L’approche linuxienne : porter la commande top sur la vie réelle

Chez Scality, nous sommes des développeurs. Pire que ça : nous sommes des développeurs système et réseaux. On développe un produit qui tourne sous Linux, principalement en C (avec des petits bouts de Rust), et on le teste avec Python.

En bons linuxiens que nous sommes, si nous voyons qu’un système a des problèmes de performances, on ouvre un terminal et on tape cette commande : top. Ce programme nous donne une vue décortiquée du système, en nous montrant les processus qui consomment le plus de CPU ou de mémoire.

De la même façon, face à un problème de productivité d’une entreprise, nous sommes tentés de taper top dans un terminal… Sauf que ni le terminal, ni la commande top n’existent sur le système que nous sommes en train d’étudier. Dans ces conditions, si nous avons besoin d’un outil comme top pour profiler une équipe d’ingénierie, et qu’il n’existe pas, eh bien qu’à celà ne tienne : construisons notre commande équivalente irltop !

Et c’est métaphoriquement ce que nous avons fait. Nous avons cherché des indicateurs de performances dans les données que nous possédions de notre entreprise (les statistiques de notre outil de tracking et de gestion de tickets), en empruntant notre méthode au Toyotisme des années 1960.

La règle des cinq zéros

Le toyotisme était la méthode de fonctionnement mise en place par Toyota dans ses usines automobiles afin de maximiser ses gains tout en minimisant les coûts de production. L’un des pilliers de cette méthodologie est la règle des cinq zéros :

  • Zéro défaut : le produit doit être d’une qualité irréprochable, parce que les problèmes de fabrication sont coûteux à gérer.
  • Zéro papier : dématérialiser l’information le plus possible dans l’entreprise.
  • Zéro panne : il coûte moins cher de payer des gens pour maintenir la chaîne de production que pour la réparer quand elle tombe en panne.
  • Zéro stock  et zéro délai : tout ce qui est produit doit être immédiatement facturé à un client. Il ne faut ni sur-produire — car le stockage est une dette, la somme de travail qui ne nous a ramené aucune valeur jusqu’à présent — ni sous-produire — car les délais d’attente sont source de mécontentement pour les clients)

Mais la chaîne de production et le stock, en ingénierie logicielle, à quoi correspondent-ils ?

Les tickets en cours (WIP) sont notre "stock"

Si l’on se fie à la définition du stock donnée plus haut, tout le travail duquel on n’a encore tiré aucune valeur est décrit chez nous dans des tickets (bug, fonctionnalité, amélioration, etc.). Chaque ticket pouvant être dans un de ces trois états :

  • Nouveau,
  • En cours,
  • Fermé.

Si l’on compte le nombre de tickets qui sont dans l’état "En cours", on obtient une mesure relativement fidèle à la quantité de travail que l’on n’a pas encore livré. Voici un graphique qui montre le nombre de tickets en cours chez Scality de sa naissance à fin 2015.

Nombre de tickets "en cours" en 2015. En pointillés : nombre de développeurs

Cela saute aux yeux : le nombre de tickets en cours a grimpé de façon exponentielle, alors que le nombre de développeurs, lui, a simplement augmenté de façon linéaire.

Une telle situation, dans une usine Toyota, ressemblerait à :

  • 4000 pneus à l’extérieur de l’usine, à côté d’un tas de 1000 pare-chocs avant,
  • 250 voitures à moitié finies qu’on a stockées là parce qu’on attend une pièce pour faire repartir leur ligne de production,
  • 170 voitures neuves dans un parking à l’extérieur, qui attendent d’être livrées aux concessionnaires.

Ça y est, nous tenons la métrique que nous cherchons. Celle que nous voulons minimiser dans notre optimisation.

Le bilan actuel

Je ne vais pas entrer dans le détail de la transformation qu’a subie l’entreprise depuis que l’on a commencé à suivre de près ce nombre de tickets en cours. Mais si je devais en résumer les traits marquants :

  • Nous avons adopté la philosophie Agile : les ingénieurs travaillent aujourd’hui en suivant une méthode Agile ou une autre, en suivant un cycle d’itérations régulier et court, itérations pendant lesquelles ils développent des fonctionnalités de taille limitée, qui représentent un gain immédiat de valeur ajoutée dans le produit.
  • Nous nous efforçons de pratiquer le Continuous Delivery en automatisant le plus de tâches possible, jusqu’à la livraison du logiciel.
  • Nous avons formalisé un workflow sur Git, nommé GitWaterFlow, que nous avons présenté fin 2016 à une conférence internationale (article en anglais).
  • Nous avons développé (et open-sourcé) Bert-E, un robot "assistant de merge", qui pilote et automatise la plus grosse partie de notre workflow (slides en anglais).
  • Nous avons développé (et open-sourcé) Eve, notre système d’intégration continue basé sur le framework BuildBot, afin de passer à l’échelle sur les tests automatisés des produits de l’entreprise (slides en anglais).

Il n’est pas exclu que je consacre d’autres billets à aborder certains de ces points en détail à l’avenir, mais pour l’instant contentons nous de conclure. Toutes ces mesures nous ont aidé à optimiser le rythme de production du produit. Nous sommes passés d’une sortie par an à une nouvelle version tous les deux mois, de deux nouvelles fonctionnalités par an à plus d’une cinquantaine (plus petites).

Quant au WIP, eh bien…

Nombre de tickets "en cours" jusqu’en 2016.

Voilà, c’est ça que je fais dans la vie.

D’autres questions ? ;)

9 commentaires

Si je peux me permettre une remarque (travaillant chez l’un des concurrents avec 1796 fois plus d’employés): la comparaison me semble déraisonnable au sens où Scality est très spécialisé dans son domaine là où IBM est tentaculaire et sur des dizaines de marchés très différents (cloud, IA, software, hardware avec de multiples latitudes - recherche fondamentale, appliquée, ingénierie, outsourcing de services financiers, de comptabilité voire de recrutement - et de multiples projets dans de domaines aux antipodes les uns des autres).

Typiquement, j’ai travaillé sur plusieurs projets, et tout fonctionne comme une startup: agile, intégration continue, release engineering, peu de QA dédié. C’est certain que la migration de certains outils traditionnels sur des projets millénaires est difficile (j’ai bossé un peu sur DB2, première base SQL au monde, code des années 70, tout centralisé sur des serveurs Clearquest moisis) mais de l’autre côté, j’ai vu la transition sans aucun soucis et par choix locaux des équipes de passer de RTC à Git + Zenhub par exemple.

Là je bosse sur un projet d’IA appliqué à la finance, on est 6 bientôt 7 et donc on est obligé d’être super flexible, presque full-stack, d’avoir un DevOps aux petits oignons, un workflow sans friction, etc. Et même plus que full-stack, on fait la R&D nous même, avec les publications et brevets qui vont avec, en dehors de toute chaîne de commande (où plutôt, elle intervient pour nous faciliter la tâche pour l’administratif et le côté législatif). Côté stakeholders, on fait de la démo et une livraison par itération ou toutes les deux itérations selon les besoins, avec une version QA accessibles à tout moment aux stakeholders et une milestone avec les stories sur 2 à 3 mois révisables toutes les semaines.

Sans parler des meetups et tech talks toutes les semaines où le Release Engineering et DevOps sont parmi les sujets les plus populaires.

J’aurais aussi pu mentionner que Microsoft ne fait pas que Edge / Internet Explorer.

Mais sinon, le sujet est très intéressant. :)

Chez nous on a plus d’états pour les tickets. Notamment on sépare l’implémentation des tests ainsi que l’état terminé de fermé. La fermeture se faisant uniquement en fin d’itération.

Chouette article, merci !

J’ai relu rapidement ton interview et il n’est pas fait mention du release engineering. As-tu changé de poste depuis ?

Comment se traduit cette activité au quotidien ? Consacres-tu entièrement ton temps à une v2 de irltop ?

+0 -0

Chouette article, merci !

J’ai relu rapidement ton interview et il n’est pas fait mention du release engineering. As-tu changé de poste depuis ?

Oui j’ai changé il y a un peu plus d’un an.

Comment se traduit cette activité au quotidien ?

Je parlerai de ça dans un autre billet sur Scrum. ;)

Consacres-tu entièrement ton temps à une v2 de irltop ?

Vayel

Attention, irltop c’est juste une métaphore. ;)

En fait une fois les indicateurs de performance (ou KPI dans le jargon) identifiés, ceux-ci ne bougent plus des masses, on se contente de les surveiller.

En ce moment ce qui consomme le plus de temps c’est le développement de Eve pour être capable de le faire tourner sur une infrastructure Kubernetes, de façon à obtenir, entre autres, la propriété d’autoscaling (à mon grand regret, d’ailleurs, puisque j’ai pris le lead sur Bert-E ces derniers mois et que je suis juste amoureux de ce projet), et une réflexion beaucoup plus large et ambitieuse sur l’outillage d’un projet étendu sur plusieurs dépôts Git indépendants (au lieu d’un seul repo de 2Go par exemple).

Ma plus grosse "crainte" c’est que ma vision diverge avec ce qui est humainement vendable dans ma société : j’ai des tonnes d’idées, d’architectures et de projets et trop peu de ressources pour les développer. Je vois en particulier un potentiel gigantesque dans les outils de build tirés de celui de Google (Bazel, ou Pants développé chez Twitter, ou Bucks développé chez Facebook) qui tournent tous autour de la même modélisation d’un projet, sauf que le contexte dans lequel ces outils sont développés (des mono-depôts gigantesques) n’incite pas les gens à sortir des frontières d’un unique dépôt Git…

Bref, pas mal de trucs qui me tiennent éveillés le soir. :)

+0 -0

et une réflexion beaucoup plus large et ambitieuse sur l’outillage d’un projet étendu sur plusieurs dépôts Git indépendants (au lieu d’un seul repo de 2Go par exemple).

Tu vois ça comment ?

Dans mon ancienne boite, on avait pas mal de dépôts pour différents composants (par exemple les dépendances statiques étaient stocké dans un dépôt, car il fallait souvent les patcher pour des infrastructures particulière non-supporter sans hack maison - genre compiler la dernière version de Boost sur HP-UX ou AIX). Ensuite, le système de build faisait appels à ces dépôts et pour chacun, on avait souvent un chemin de build pour (architecture, OS). Par exemple le dépôt des dépendances était déclinées selon toutes les plateformes supportées et les OS en combinaison (sans parler des différents stages mais qui sont globalement dupliqués à partir d’un prototype).

On avait un graphe de dépendances sur les composants (jusque sur les tests séparés en pas mal de catégories par composants: unitaire, régression, intégration, …), ce qui permettait lorsque l’on soumettait un build privé ou un commit de réduire la compilation et le build à la partie strictement nécessaire.

Au moment de réellement déployer en prod, on générait l’ensemble du flow et ça pouvait prendre jusqu’à 12h (d’où la nécessité pour le développement de partitionner autant que faire se peut l’ensemble du build, jusqu’à la séparation des composants en différents dépôts pour limiter le temps de clonage).

et une réflexion beaucoup plus large et ambitieuse sur l’outillage d’un projet étendu sur plusieurs dépôts Git indépendants (au lieu d’un seul repo de 2Go par exemple).

Tu vois ça comment ?

Je vais partir de la fin de ton post pour construire ma réponse.

Au moment de réellement déployer en prod, on générait l’ensemble du flow et ça pouvait prendre jusqu’à 12h (d’où la nécessité pour le développement de partitionner autant que faire se peut l’ensemble du build, jusqu’à la séparation des composants en différents dépôts pour limiter le temps de clonage).

KFC

Il existe des solutions pour avoir un build aussi court sur un dépôt monolithique :

  • créer un proxy/cache git local qui ne clone le repo qu’une seule fois et qui se contente de faire des fetch ensuite,
  • les fameux trois outils de build que je cite plus haut

Ces trois outils ont en commun un langage déclaratif dans lequel est écrite la description du projet, qui consiste à découper le projet en build-units.

Pour résumer et simplifier, chaque build unit se compose :

  • d’une adresse qui la référence
  • d’une ou plusieurs targets (compilation, compilation en mode debug, tests unitaires, fonctionnels, end to end, documentation…)
  • chaque target déclare exhaustivement ses entrées (dépendances + sources) et ses sorties
  • les entrées d’une target peuvent être les sorties d’une autre, c’est comme ça qu’on déclare les dependances.

Jusqu’ici on peut se dire que ça ressemble foutrement à des makefiles. Et en effet c’est ce qui les remplace, mais l’avantage d’utiliser une syntaxe déclarative propre permet de crawler tout le projet et de construire son arbre de dépendances en un clin d’oeil.

Partant de cette déclaration, construire une target revient à construire tout son arbre de dépendances + elle… et bien sûr stocker les artifacts à raison d’un conteneur par target.

Là où ça commence à devenir fou, c’est que du moment où une target doit être déclarée de façon exhaustive, on peut mettre ses articfacts en cache. Pire, on peut se servir du dépôt d’artifacts (au hasard un système objet Amazon S3) comme d’un cache partagé. Au moment de builder une dépendance, il est possible de savoir si ses artifacts sont déjà disponibles, et récupérer immédiatement le résultat le cas échéant.

Encore mieux, le dépôts d’artifacts est public : si un dev lance un build sur sa machine, étant donné qu’il a un accès en lecture seule sur le dépôt d’artifacts, il bénéficie du cache généré par la CI.

Je pense que la voie la plus prometteuse pour ce que je voudrais obtenir, est déjà de généraliser ce langage pour décrire des arbres qui s’étendent sur plusieurs dépôts :

  • pour une dépendance interne (dont on maîtrise le développement) on se contente d’utiliser son arbre de build comme s’il appartenait au dépôt coûrant,
  • pour une dépendance externe, il suffit de déclarer localement son arbre de build.

Reste ensuite pas mal de petites problématiques inhérentes au multi-repo, en particulier lorsque les composants suivent des cycles de vie indépendants : typiquement il faut être capable de déclarer des matrices de compatibilité.

L’autre enjeu est l’intégration d’un gatekeeping étendu sur ces repos : lorsqu’on fait une merge-request sur la libtruc, on veut que tous les composants qui ont une dépendance interne sur la libtruc soient testés avec la modification qui fait l’objet de la merge-request avant que celle-ci ne soit mergée, et du coup, gérer la possibilité d’un travail d’intégration (modifier les repos qui dépendent de libtruc pour qu’il continuent à fonctionner et merger la PR de libtruc ainsi que les PR d’intégration simultanément, dans une seule et même transaction). Ainsi, quand une merge-request finit par être mergée sur un dépôt, on a par construction la garantie que tous les projets qui en dépendent fonctionnent également.

De façon assez amusante, l’idée derrière ça est encore de réduire le WIP. Si tout le monde a une dépendance interne libtruc 2.0 alors tout le monde doit être immédiatement compatible avec la dernière révision de libtruc 2.0, parce qu’une version développée mais pas utilisée, c’est du travail produit dont on ne récupère pas de valeur, donc du WIP.

+1 -0
Connectez-vous pour pouvoir poster un message.
Connexion

Pas encore membre ?

Créez un compte en une minute pour profiter pleinement de toutes les fonctionnalités de Zeste de Savoir. Ici, tout est gratuit et sans publicité.
Créer un compte