18 April 2024

11 mins de lecture

La prévision des résultats de build : un gain de temps et de ressources

Une build, qu'est-ce que c'est au juste ?

Savez-vous comment on crée un jeu vidéo ? Le développement d'un jeu mobilise une quantité de rôles différents : des développeurs pour rédiger le code, des concepteurs pour créer les scénarios et les personnages, des graphistes pour la partie visuelle, etc. Pour finir, tous les éléments ainsi créés sont compilés afin de produire une « version » jouable, que les professionnels du secteur désignent souvent par l'anglicisme « build ». 

Mais que représente au juste une « build » dans le contexte du développement de jeux ?

[LA FORGE Studio] Build Outcome Prediction - Saving Time and Resources - image 1
[Image 1]

Compiler une build, c'est un peu comme créer de l'art avec des dominos : il faut les assembler précautionneusement pour les abattre tous ensemble, en provoquant une réaction en chaîne dans laquelle chaque élément entraîne le suivant. Dans le contexte du développement de jeux, le code, les graphismes et les sons représentent les dominos. De même que les dominos suivent un chemin bien précis qui détermine la façon dont ils doivent tomber, il existe également des dépendances entre les composants d'un jeu. Un élément fautif peut suffire à interrompre toute la réaction en chaîne. Or, pour placer des milliers de dominos comme pour compiler un jeu vidéo complexe contenant des millions de fichiers sources, il faut beaucoup de temps et d'efforts.  

Qu'est-ce que la prévision des résultats de build ?

Il s'agit d'une analyse permettant de prévoir le résultat d'une compilation de logiciel en comparant la build voulue aux précédentes avant de lancer le processus à proprement parler. La prévision des résultats de build vise à fournir préventivement aux développeurs une analyse de la réussite ou de l'échec d'une compilation.

[LA FORGE Studio] Build Outcome Prediction - Saving Time and Resources - image 2
[Image 2]

Imaginez-vous en train de cueillir des champignons avec un panier à la contenance limitée. Votre but est de ramasser un maximum de champignons comestibles. Pour optimiser le processus, vous faites appel à votre connaissance des champignons afin de filtrer préventivement les vénéneux. Vous identifiez les caractéristiques communes comme la volve, les lamelles blanches, le chapeau rouge et les odeurs spécifiques associées aux champignons vénéneux. Ce filtrage préventif ne garantit pas que tous les champignons de votre panier sont comestibles ni que tous les champignons écartés sont vénéneux, mais il constitue une approche plus rapide et économique que d'envoyer tous les champignons en laboratoire pour analyse toxicologique.

Il en va de même pour la prévision des résultats de build, qui consiste à déterminer le résultat d'une compilation en fonction d'indicateurs précoces avant de l'effectuer. Comme pour les champignons vénéneux, les builds réussies ou non présentent certaines caractéristiques communes ; des corrélations trop complexes pour être identifiées manuellement, mais que les techniques d'apprentissage automatique peuvent isoler et analyser.

Avantages

La prévision des résultats de build peut fluidifier le développement en améliorant la fiabilité des compilations grâce à l'immédiateté de la prévision. 

Le développement moderne de logiciels procède par petites itérations incrémentielles accompagnées de tests fréquents afin de détecter les défauts au plus tôt. Toutefois, cette approche implique des volumes de calcul importants et donc des surcoûts non négligeables.

La prévision des résultats de build peut donner lieu à trois stratégies d'exécution de build visant à réduire sensiblement ces coûts, à anticiper les échecs potentiels et à éviter qu'une build dysfonctionnelle ne contamine l'environnement de compilation.  

1. Saut de build

Les développeurs (ou le système de build) peuvent décider de ne pas exécuter certaines tâches ou étapes de compilation s'ils estiment que le résultat sera identique à une build déjà réussie. Le but est ici de gagner du temps et des ressources en évitant de répéter un processus qui produira en toute logique des résultats identiques. 

La prévision des résultats de build peut faire office d'indicateur pour les builds à sauter. En fonction des prévisions, nous décidons s'il faut ou non sauter la compilation de certaines modifications. Si la prévision indique une haute probabilité de build réussie sans modification critique ou à haut risque, il est alors possible de sauter la build pour gagner du temps et des ressources.

[LA FORGE Studio] Build Outcome Prediction - Saving Time and Resources - Figure 1
[Légende : le nombre d'exécutions est ici réduit de 8 à 5.]

2. Compilation par lots 

La compilation par lots consiste à regrouper plusieurs modifications ou commits (validations) et à les compiler collectivement au lieu d'avoir une exécution par changement. Cette stratégie vise avant tout à gagner en efficacité et en temps en réduisant le nombre d'exécutions. Au lieu de créer une build distincte à chaque changement, les développeurs attendent d'avoir effectué un certain nombre de modifications pour lancer la compilation. Il est ainsi possible de traiter collectivement ces modifications y compris dans les tests, ce qui est très utile pour fluidifier les processus pendant les périodes intenses.

Pour la compilation par lots, l'outil de prévision des résultats de build peut servir à prendre des décisions éclairées sur les modifications à inclure dans un lot. Au lieu de toutes les regrouper sans distinction, cet outil peut servir à identifier les modifications susceptibles d'entraîner un échec de compilation. Grâce à un système de priorités, il est ainsi possible de réduire les risques d'inclure des modifications potentiellement problématiques dans un lot.

[LA FORGE Studio] Build Outcome Prediction - Saving Time and Resources - Figure 2
[Légende : le nombre d'exécutions est ici réduit de 8 à 6, sans saut de build.]

3. Contrôle préalable de build

Le contrôle préalable (preflight) consiste à compiler les modifications à risque en local avant de les intégrer au pipeline principal. Une interruption du pipeline principal entraîne en effet l'échec de toutes les autres tâches de compilation jusqu'à tant que le coupable soit corrigé. Les commits ultérieurs ne peuvent donc pas recevoir de retour, ce qui force leurs auteurs à s'atteler à une autre tâche (une gymnastique mentale jamais facile) ou à se tourner les pouces. Une build dysfonctionnelle peut en outre contaminer l'environnement de compilation. Le but du contrôle préalable est d'éviter que l'échec d'une tâche ne bloque d'autres demandes à faible risque. 

Grâce à la prévision des résultats de build, il est possible d'imposer un contrôle préalable des builds à haut risque d'échec. Cette approche augmente la stabilité du pipeline principal et donc l'efficacité des processus de développement.

[LA FORGE Studio] Build Outcome Prediction - Saving Time and Resources - Figure 3
[Légende : le nombre d'exécutions n'est pas réduit, mais le nombre d'échecs dans le pipeline principal est réduit de 3 à 1.]

4. Hybride

Nous conseillons par ailleurs d'associer les approches ci-dessus, comme illustré dans le tableau. Si l'outil de prévision anticipe l'échec d'une build, celle-ci doit être compilée en local (contrôle préalable) avant d'être intégrée à la branche principale. S'il prévoit que plusieurs builds vont aboutir, nous les compilons par lots pour économiser des exécutions. Nous pouvons ainsi réduire à la fois le nombre d'exécutions et d'interruptions du pipeline de build avec une garantie de fiabilité.   

[LA FORGE Studio] Build Outcome Prediction - Saving Time and Resources - Figure 4
[Légende : le nombre d'exécutions est réduit de 8 à 6 et le nombre d'échecs dans le pipeline principal est réduit de 3 à 1.]

Comment fonctionne la prévision des résultats de build ? 

Les recherches actuelles sur la prévision des résultats de build [citer BuildFast] s'appuient sur l'ingénierie des caractéristiques pour représenter une build sous trois aspects clés : données de build actuelles, données de build précédentes et données de build historiques. 

Ces approches ont beau être très prometteuses, les spécificités inhérentes aux jeux vidéo posent de nouveaux défis pour la prévision des résultats de build. Les travaux antérieurs sur la prévision des résultats de build étaient axés sur des projets lourds en code. De ce fait, de nombreuses caractéristiques adoptées par ces études sont spécifiques à ce code, par exemple le nombre de lignes modifiées dans le code source. Les jeux vidéo, quant à eux, sont plus axés sur les éléments de données et leurs modifications que sur le code source et ses modifications. Ces éléments jouent un rôle crucial dans l'expérience de jeu. Le moteur compile les éléments avec le code source en respectant l'ordre imposé par les dépendances. Par conséquent, si les éléments de données sont corrompus ou si les dépendances ne sont pas respectées, les modifications de données entraîneront un échec de build.

Pour tenir compte des changements de données propres aux jeux vidéo, nous explorons les aspects suivants des builds. 

Contexte

Les soumissions de modifications ont généralement pour but d'intégrer de nouvelles fonctionnalités ou de corriger des bugs. Ce contexte s'applique transitivement aux builds qui en découlent. Nous déduisons le contexte d'une build à partir des métadonnées de son ensemble de modifications, par exemple le message de commit, les types de fichiers et l'activité de build antérieure.

Pertinence

Dans le cadre du développement, un ensemble de builds peut se rapporter à une seule tâche ; par exemple lorsqu'une erreur de compilation initiale se produit et que les échecs de builds suivants tentent de la corriger, ou lorsqu'une tâche importante est décomposée en une série de changements incrémentaux. Les caractéristiques qui exploitent le statut ou le contexte d'une build précédente doivent donc être limitées au contexte lorsque les builds antérieures et actuelle font partie de la même tâche. De ce fait, nous proposons des fonctions qui suggèrent au modèle quand les caractéristiques de la build précédente sont pertinentes pour la prévision actuelle, et quand elles doivent être ignorées.

Dépendance

[LA FORGE Studio] Build Outcome Prediction - Saving Time and Resources - image 3
[Légende : exemple de diagramme de dépendances multidisciplinaire, les nœuds verts représentant les fichiers de données, orange les nœuds frontaliers et roses les fichiers de code. Les diagrammes de dépendances des jeux vidéo peuvent contenir des millions de nœuds.]

Il est plus risqué de modifier un fichier dont dépendent un grand nombre d'autres fichiers qu'un fichier en bout de chaîne. Par exemple, modifier une fonction dans une bibliothèque très utilisée propagera cette modification à ses nombreux points d'utilisation. C'est donc plus risqué que de modifier un bref script qui appelle une fonction de cette même bibliothèque. De ce fait, nous proposons des fonctions qui quantifient l'impact du changement actuel sur les dépendances.

Dans le développement de jeux vidéo, l'interaction entre le code et les fichiers de données définit les fonctions du jeu, gère ses assets et détermine l'expérience du joueur. Des changements transfrontaliers ont lieu lorsqu'une modification de code met à jour un fichier de code dont dépendent des fichiers de données.

[LA FORGE Studio] Build Outcome Prediction - Saving Time and Resources - Figure 5
[Légende : exemple de modification transfrontalière. Les nœuds impactés désignent ceux qui sont dépendants du nœud modifié.]

Nous constatons que les changements transfrontaliers ont un impact nettement plus important que les autres, et qu'ils entraînent donc beaucoup plus d'échecs de build. De ce fait, nous proposons des fonctions qui indiquent si la modification actuelle traverse une frontière. 

RavenBuild

En complément du travail existant, nous proposons RavenBuild, qui décrit les builds à partir de trois aspects indépendants des types de fichiers : (1) les caractéristiques de contexte qui caractérisent l'intention et le contexte de la modification soumise ; (2) les caractéristiques de pertinence qui comparent la build actuelle et son prédécesseur immédiat pour aider à déterminer si le modèle doit prendre en compte les informations de la build précédente ; et (3) les caractéristiques de dépendance qui évaluent l'impact de la modification sur d'autres fichiers dans le diagramme de dépendances.

Résultats

[LA FORGE Studio] Build Outcome Prediction - Saving Time and Resources - Figure 6
[Figure 6]

Par rapport à la référence du secteur (BuildFast), RavenBuild améliore de 19,8 points de pourcentage le score F1 dans la classe d'échec, de 24,4 le rappel de la classe d'échec et de 19,4 l'AUC. 

Synthèse

La prévision des résultats de build offre un potentiel important de réduction des coûts de production grâce à diverses stratégies telles que le saut de build, la compilation par lots et le contrôle préalable. Les techniques d'apprentissage automatique peuvent identifier efficacement les points communs entre toutes les builds réussies d'une part et toutes les builds échouées de l'autre ; mais il est essentiel pour cela d'intégrer les caractéristiques inhérentes au système de build. La prise en compte du contexte, de la pertinence et de la connaissance des dépendances améliore la précision et l'efficacité des prévisions, d'où une réduction des coûts de production.