Lorsque la Release Candidate de Linux 5.8 a été récemment mise à l’essai, la grande nouvelle n’était pas tant ce qu’elle contenait, mais sa Taille. Comme Linus Torvalds lui-même c’est noté, «Bien que n’ayant pas vraiment toute chose qui se démarque… 5.8 semble être l’une de nos plus grandes sorties de tous les temps. »
Il est vrai que RC 5.8 propose plus de 14 000 commits sans fusion, quelque 800 000 nouvelles lignes de code et une centaine de nouveaux contributeurs. Cela aurait pu devenir aussi important simplement parce que peu de gens ont voyagé grâce à COVID-19, et nous avons tous été en mesure de faire plus de travail dans une fenêtre de publication que d’habitude. Mais du point de vue de ce contributeur et mainteneur chevronné du noyau Linux, ce qui est particulièrement frappant à propos de la version 5.8 RC, c’est que sa taille sans précédent n’était tout simplement pas un problème pour ceux qui la maintiennent. Cela, je dirais, est parce que Linux a le meilleur processus de flux de travail de tous les projets logiciels au monde.
Que signifie avoir le meilleur processus de flux de travail? Pour moi, cela se résume à un ensemble de règles de base que les développeurs du noyau Linux ont établies au fil du temps pour leur permettre de produire des progrès constants et fiables à grande échelle.
Un facteur clé est git
Cela vaut la peine de commencer par un peu d’histoire de Linux. Au début du projet (1991–2002), les gens envoyaient simplement des correctifs directement à Linus. Puis il a commencé à extraire des correctifs des sous-responsables, et ces personnes prenaient des correctifs à d’autres. Il est rapidement devenu évident que cela ne pouvait pas évoluer. Tout était trop difficile à suivre et le projet risquait constamment de fusionner du code incompatible.
Cela a conduit Linus à explorer divers systèmes de gestion du changement, y compris BitKeeper, qui a adopté une approche inhabituellement décentralisée. Alors que d’autres systèmes de gestion des changements utilisaient un protocole d’extraction / modification / enregistrement, BitKeeper a donné à tout le monde une copie de l’ensemble du dépôt et a permis aux développeurs d’envoyer leurs modifications à fusionner. Linux a brièvement adopté BitKeeper en 2002, mais son statut de solution propriétaire s’est avéré incompatible avec la croyance de la communauté dans le développement open source, et la relation s’est terminée en 2005. En réponse, Linus a disparu pendant un moment et est revenu avec git, qui a pris la gestion décentralisée du changement dans une nouvelle direction puissante et a été la première instanciation significative du processus de gestion qui fait si bien fonctionner le développement Linux aujourd’hui.
Voici sept bonnes pratiques – ou principes fondamentaux – qui sont essentiels au flux de travail du noyau Linux:
Chaque commit ne doit faire qu’une seule chose
Un principe central de Linux est que tous les changements doivent être fractionnés en petites étapes. Chaque commit que vous soumettez ne doit faire qu’une seule chose. Cela ne signifie pas que chaque commit doit être de petite taille. Une simple modification de l’API d’une fonction utilisée dans un millier de fichiers peut rendre la modification massive, mais elle est toujours acceptable car elle fait partie de l’exécution d’une tâche. En obéissant toujours à cette unique injonction, vous facilitez grandement l’identification et l’isolement de tout changement qui s’avère problématique. Cela permet également au réviseur de correctifs de ne se préoccuper que d’une seule tâche accomplie par le correctif.
Les validations ne peuvent pas interrompre la construction
Non seulement tous les changements doivent être divisés en incréments les plus petits possibles, mais ils ne peuvent pas non plus casser le noyau. Chaque étape doit être pleinement fonctionnelle et ne pas provoquer de régressions. C’est pourquoi une modification apportée au prototype d’une fonction doit également mettre à jour chaque fichier qui l’appelle, pour empêcher la construction de se rompre. Chaque étape doit donc fonctionner comme un changement autonome, ce qui nous amène au point suivant:
Tout le code est bissectable
Si un bogue est découvert à un moment donné, vous devez savoir quel changement a causé le problème. Essentiellement, une bissectrice est une opération qui vous permet de trouver le moment exact où tout s’est mal passé.
Vous faites cela en allant au milieu de l’endroit où le dernier commit fonctionnel connu existe, et le premier commit connu pour être rompu, et testez le code à ce stade. Si cela fonctionne, vous passez au point médian suivant. Si ce n’est pas le cas, vous revenez au point central dans l’autre sens. De cette façon, vous pouvez trouver le commit qui rompt le code de dizaines de milliers de commits possibles en seulement une douzaine de compilations / tests. Git aide même à automatiser ce processus avec le git bisect Fonctionnalité.
Surtout, cela ne fonctionne bien que si vous respectez les règles précédentes: que chaque commit ne fasse qu’une seule chose. Sinon, vous ne saurez pas lequel des nombreux changements dans la validation du problème a causé le problème. Si un commit rompt la construction ou ne démarre pas et que la bissectrice arrive sur ce commit, vous ne saurez pas dans quelle direction prendre la bissectrice. Cela signifie que vous ne devriez jamais écrire un commit qui dépend d’un commit futur, comme appeler une fonction qui n’existe pas encore, ou changer les paramètres d’une fonction globale sans changer tous ses appelants dans ce même commit.
Ne jamais rebaser un référentiel public
Le processus de flux de travail Linux ne vous permettra pas de rebaser une branche publique utilisée par d’autres. Une fois que vous avez rebasé, les commits qui ont été rebasés ne correspondent plus aux mêmes commits dans les référentiels basés sur cette arborescence. Une arborescence publique qui n’est pas une feuille dans une hiérarchie d’arbres ne doit pas rebaser. Sinon, cela cassera les arbres inférieurs de la hiérarchie. Lorsqu’un référentiel git est basé sur un autre arbre, il se construit au-dessus d’un commit dans cet arbre. Un rebase remplace les commits, supprimant éventuellement un commit sur lequel d’autres arbres sont basés.
Git fusionne correctement
Réussir la fusion est loin d’être acquis. D’autres systèmes de gestion du changement sont un cauchemar pour fusionner le code de différentes branches. Cela se termine souvent par des conflits difficiles à résoudre et nécessite une énorme quantité de travail manuel pour les résoudre. Git a été structuré pour faire le travail sans effort, et Linux en profite directement. C’est en grande partie pourquoi la taille de la version 5.8 n’était pas vraiment un gros problème. le 5.8-rc1 la version en moyenne 200 commits par jour, avec 880 fusions totales de 5.7. Certains responsables de la maintenance ont remarqué une charge de travail un peu plus importante, mais rien n’était trop stressant ou ne causerait de burn-out.
Conservez des journaux de validation bien définis
Malheureusement, cela peut être l’une des meilleures pratiques les plus essentielles qui sont ignorées par de nombreux autres projets. Chaque validation doit être autonome, et cela inclut son journal de validation. Tout ce qui est nécessaire pour comprendre la modification apportée doit être expliqué dans le journal de validation de la modification. J’ai trouvé que certains de mes journaux de modifications les plus longs et les plus descriptifs concernaient des commits sur une seule ligne. En effet, un seul changement de ligne peut être une correction de bogue très subtile, et cette correction de bogue devrait être décrite en détail dans le journal des modifications.
Quelques années après avoir soumis un changement, il est très peu probable que quiconque sache pourquoi ce changement a été effectué. UNE git blame peut montrer quels commits ont changé le code d’un fichier. Certains de ces commits peuvent être très anciens. Peut-être avez-vous besoin de supprimer un verrou ou d’apporter une modification à un code et ne savez pas précisément pourquoi il existe. Un journal des modifications bien écrit pour ce changement de code peut aider à déterminer si ce code peut être supprimé ou comment il peut être modifié. Il y a eu plusieurs fois que j’étais heureux d’avoir écrit des journaux de modifications détaillés sur le code car je devais supprimer du code, et la description du journal des modifications m’a fait savoir que mes modifications étaient correctes.
Exécutez des tests et une intégration continus
Enfin, une pratique essentielle consiste à exécuter des tests continus et une intégration continue. Je teste chacune de mes pull requests avant de les envoyer en amont. Nous avons également un repro appelé linux-suivant qui récupère tous les changements que les mainteneurs ont sur une branche spécifique de leurs référentiels et les teste pour s’assurer qu’ils s’intègrent correctement. Effectivement, linux-suivant exécute une branche testable de tout le noyau qui est destinée à la prochaine version. Il s’agit d’un dépôt public afin que tout le monde puisse le tester, ce qui arrive assez souvent – les gens publient même maintenant des rapports de bogue sur le code qui se trouve dans linux-suivant. Mais le résultat est que le code qui a été dans linux-suivant pendant quelques semaines, il sera très probablement bon d’entrer dans le réseau principal.
Meilleures pratiques illustrées
Toutes ces pratiques permettent à la communauté Linux de publier un code incroyablement fiable selon un calendrier régulier de 9 semaines à une telle échelle (moyenne de 10 000 commits par version et plus de 14 000 pour la dernière version).
Je voudrais signaler un autre facteur qui a été la clé de notre succès: la culture. Il y a une culture d’amélioration continue au sein de la communauté du noyau qui nous a conduit à adopter ces pratiques en premier lieu. Mais nous avons aussi une culture de confiance. Nous avons une voie claire par laquelle les gens peuvent apporter leur contribution et démontrer au fil du temps qu’ils sont à la fois disposés et capables de faire avancer le projet. Cela crée un réseau de relations de confiance qui ont été la clé du succès à long terme du projet.
Au niveau du noyau, nous n’avons pas d’autre choix que de suivre ces pratiques. Toutes les autres applications s’exécutent au-dessus du noyau. Tout problème de performance ou bogue dans le noyau devient un problème de performance ou un bogue pour les applications supérieures. Tous les chemins d’erreur doivent sortir paisiblement; sinon, tout le système sera compromis. Nous nous soucions de chaque erreur car les enjeux sont si élevés, mais cet état d’esprit servira bien tout projet logiciel.
Les applications peuvent avoir le luxe de simplement planter en raison d’un bogue. Cela ennuiera les utilisateurs, mais les enjeux ne sont pas aussi élevés. Les logiciels de qualité ne doivent pas prendre les bogues à la légère. C’est pourquoi le workflow de développement Linux est considéré comme la norme d’or à suivre.
À propos de l’auteur: Steven Rostedt (@srostedt) est un contributeur du noyau Linux et un ingénieur Open Source chez VMware. Vous pouvez en savoir plus sur le travail de Steven à blogs.vmware.com/opensource ou @VMWopensource sur Twitter