Joel on Software

Joel on Software   Joël à propos de logiciel

 

D'autres articles de "Joel on Software" en Français

D'autres articles de "Joel on Software" en Anglais

Contacter l'auteur (En Anglais uniquement)

 

Des générations quotidiennes de l'application sont vos amies


Par Joël Spolsky
Traduit par Laurent Prud'hon
Vérifié par Trinh Vinh-An
27 janvier 2001

En 1982, ma famille a été livrée du tout premier IBM PC en Israël. En fait, nous sommes descendus au magasin et nous avons attendu jusqu'à ce que notre PC soit livré du port. D'une manière ou d'une autre, j'ai convaincu mon père de prendre la version complète, avec deux lecteurs de disquettes, 128 Ko de mémoire, et à la fois une imprimante matricielle (pour des brouillons rapides) et une imprimante Brother qualité courrier Daisy Wheel, qui fait exactement le même bruit qu'une mitrailleuse quand elle fonctionne, mais en plus fort. Je pense que nous avions presque tous les accessoires disponibles : le PC DOS 1.0, le manuel de référence technique à 75 dollars avec le code source complet du BIOS, Macro Assembleur, et l'extraordinaire moniteur IBM monochrome avec quatre-vingts colonnes et... des lettres minuscules ! Le tout coûtant environ 10000 dollars en comptant les taxes d'import qui étaient alors ridicules en Israël. Extravagant !

Ceci étant, "tout le monde" savait que le BASIC est un langage pour enfants qui vous oblige à écrire du code spaghetti et qui transforme votre cerveau en camembert. Alors nous avons déboursé 600 dollars pour IBM Pascal, qui était fourni sur trois disquettes. La première passe du compilateur était sur la première disquette, la seconde passe sur la seconde disquette, et l'éditeur de liens sur la troisième disquette. J'ai écrit un simple programme "Hello, world" et je l'ai compilé. Temps total écoulé : 8 minutes.

Hmm. C'est long. J'ai écrit un script batch pour automatiser le processus et le raccourcir à 7 minutes et demie. Mieux. Mais lorsque j'ai essayé d'écrire des programmes plus longs comme mon extraordinaire version d'Othello qui me bat toujours, j'ai passé le plus clair de mon temps à attendre la fin des compilations. "Ouais", m'a dit un programmeur professionnel, "nous avions installé une planche à abdominaux dans le bureau, et nous faisions des abdos pendant les compilations. Après quelques mois de programmation, j'avais des abdos en béton."

Un jour, un programme non identifié appelé Compas Pascal est apparu du Danemark, que Philippe Kahn a acheté et a renommé Borland Turbo Pascal. Turbo Pascal était vraiment stupéfiant, puisqu'il faisait à peu près la même chose qu'IBM Pascal, à part qu'il tournait dans environ 33 Ko de mémoire en comptant l'éditeur de texte. Ce n'était pas peu surprenant. Le fait que vous pouviez compiler un petit programme en moins d'une seconde était encore plus surprenant. C'est comme si une société dont vous n'aviez jamais entendu parler introduisait un clone de la Buick LeSabre pouvant rouler à 1 000 000 km/h et faire le tour du monde avec si peu de carburant qu'une fourmi pourrait le boire sans être malade.

Brusquement, je suis devenu beaucoup plus productif.

C'est alors que j'ai appris le concept de la boucle LEI. LEI signifie " Lire, Evaluer, Imprimer " et décrit ce qu'un interpréteur LISP fait toute sa vie : il "lit" vos instructions, les évalue, et imprime le résultat. Un exemple de boucle LEI est montré ci-dessous : j'ai saisi quelque chose, l'interpréteur LISP le lit, l'évalue, et imprime le résultat.

REP Loop

À une échelle un peu plus grande, lorsque vous écrivez votre code, vous êtes dans une version macroscopique de la boucle LEI appelée boucle Editer-Compiler-Tester. Vous éditez votre code, le compilez, le testez, et voyez s'il fonctionne bien.

Une observation cruciale ici est que vous devez parcourir la boucle encore et encore pour écrire un programme, et il en découle que plus la boucle Editer-Compiler- Tester est rapide, plus vous serez productif, jusqu'à une limite naturelle de compilation instantanée. C'est la raison formelle, science-de-l'-information-nelle pour laquelle les programmeurs veulent du matériel vraiment rapide et les développeurs de compilateurs vont faire tout ce qu'ils peuvent pour avoir des boucles Edition-Compilation-Test super rapides. Visual Basic y parvient en réalisant l'analyse lexicale et syntaxique de chaque ligne en même temps que vous la tapez de manière que la compilation finale puisse être super-rapide. Visual C++ y parvient en proposant des compilations incrémentales, des headers précompilés, et une édition de liens incrémentale.

Mais aussitôt que vous commencez à travailler dans une équipe plus grande avec de multiples développeurs et testeurs, vous rencontrez à nouveau le même cycle en plus grand (c'est fractal, mon pote !). Un testeur trouve un bug dans le code et le signale. Le programmeur corrige le bug : combien de temps est nécessaire avant que le testeur obtienne une version corrigée du code ? Dans certaines sociétés de développement, le cycle Signaler-Corriger-Retester peut prendre une ou deux semaines, ce qui signifie que l'ensemble de la société fonctionne de manière improductive. Pour conserver un fonctionnement harmonieux de l'ensemble du processus de développement, vous devez vous concentrer sur l'obtention d'un cycle Signaler-Corriger-Retester resserré.

Une bonne façon de le faire est à l'aide de générations quotidiennes de l'application. Une génération quotidienne est une génération automatique, quotidienne et complète de l'ensemble de l'arborescence du code source.

Automatique -parce que vous configurez le code pour qu'il soit compilé à heure fixe tous les jours, en utilisant des jobs cron (sous UNIX), le service de planification (sous Windows).

Quotidienne -ou encore plus fréquente. Il est tentant de générer des versions en continu, mais vous ne pouvez probablement pas le faire, à cause de problèmes de gestion du code source dont je vais parler dans une minute.

Complète - il y a des chances pour que votre code ait plusieurs versions. Des versions en plusieurs langues, plusieurs systèmes d'exploitation, une version haut de gamme/bas de gamme. La génération quotidienne doit les générer toutes. Elle doit générer chaque fichier à partir de rien, en ne s'appuyant pas sur les capacités de régénération incrémentale des compilateurs qui peuvent être imparfaites.

Voici quelques-uns des nombreux avantages des générations quotidiennes :

  1. Lorsqu'un bug est corrigé, les testeurs ont rapidement la nouvelle version et peuvent retester pour voir si le bug a bien été corrigé.
  2. Les développeurs peuvent se sentir plus en sécurité par rapport au fait qu'un changement qu'ils ont apporté ne puisse casser une des 1024 versions du système qui est produit, sans avoir effectivement une machine OS/2 sur leur bureau pour tester.
  3. Les développeurs qui font un check-in de leurs modifications juste avant la génération quotidienne savent qu'ils ne vont pas importuner tous les autres en enregistrant quelque chose qui "casse la compilation" -- c'est-à-dire, quelque chose qui empêche quiconque de compiler. C'est l'équivalent de l'Ecran Bleu de la Mort pour une équipe de développement, et ça arrive fréquemment lorsqu'un programmeur oublie d'ajouter un nouveau fichier qu'il a créé dans le référentiel. La génération fonctionne bien sur sa machine, mais lorsque quelqu'un d'autre fait un check-out, il obtient des erreurs d'édition de liens et est stoppé brutalement dans son travail.
  4. Des groupes externes comme le marketing, les sites de clients bêta, et ainsi de suite qui ont besoin d'utiliser le produit peu mature peuvent récupérer une génération qui est connue pour être à peu près stable et continuer à l'utiliser pendant un moment.
  5. En conservant une archive de toutes les générations quotidiennes, lorsque vous découvrez une nouvelle anomalie vraiment étrange, et que vous n'avez aucune idée de ce qui peut en être la cause, vous pouvez utiliser une recherche dichotomique sur l'archive pour mettre le doigt sur le moment où l'anomalie est apparue dans le code. Avec un bon système de gestion de versions, vous pourrez probablement retrouver quel check-in est à l'origine du problème.
  6. Lorsqu'un testeur reporte un problème que le programmeur pensait corrigé, le testeur peut dire dans quelle génération il a détecté le problème. Ensuite, le programmeur regarde à quel moment il a fait un check-in de la correction et en déduit si c'est vraiment corrigé.

Voici comment les mettre en pratique. Vous avez besoin d'un serveur de génération quotidienne, qui sera probablement l'ordinateur le plus puissant sur lequel vous pourrez mettre la main. Écrivez un script qui réalise un check-out de l'ensemble du code source depuis le référentiel (vous utilisez un système de gestion de versions, n'est-ce pas ?) et ensuite génère en partant de rien chaque version du code que vous livrez. Si vous avez un installateur ou un programme de configuration, générez-les aussi. Tout ce que vous livrez à des clients devrait être produit par le processus de génération quotidienne. Placez chaque génération dans son propre répertoire, dont le nom commence par la date. Exécutez votre script à l'heure fixée chaque jour.

  • Il est essentiel que tout ce qui est nécessaire pour générer une version finale soit fait par le script de génération quotidienne, depuis un check-out du code jusqu'à déposer les éléments au bon endroit sur un serveur Web pour les mettre à disposition du public (même si pendant le processus de développement, ce sera un serveur de test bien sûr). C'est la seule manière de s'assurer qu'il n'y a rien à propos du processus de génération qui soit seulement "documenté" dans la tête d'une personne. Vous ne vous retrouverez ainsi jamais dans une situation dans laquelle vous ne pouvez pas finaliser un produit parce que seule Shaniqua sait comment créer l'installeur, et elle a été renversée par un bus. Dans l'équipe Juno, la seule chose que vous deviez savoir pour générer une version complète en partant de zéro était la localisation du serveur de génération, et comment double-cliquer sur l'icône "Génération quotidienne".
  • Il n'y a rien de pire pour votre intégrité que lorsque vous êtes en train d'essayer de livrer le code, et qu'il y a un tout petit bug, donc vous corrigez ce tout petit bug directement sur le serveur de génération quotidienne et vous livrez. C'est une règle d'or, vous ne devriez livrer que du code qui a été produit par génération quotidienne propre et complète, qui a commencé par un check-out complet.
  • Configurez vos compilateurs au niveau de warning maximum (-W4 dans le monde Microsoft, -Wall dans le pays gcc) et pour qu'ils s'arrêtent s'ils rencontrent le moindre warning.
  • Si une génération quotidienne est cassée, vous courez le risque de bloquer l'ensemble de l'équipe. Arrêtez tout et continuez à re-générer jusqu'à ce que ce soit corrigé. Quelquefois, vous pouvez avoir de multiples compilations quotidiennes.
  • Votre script de génération devrait signaler les échecs, par email, à l'ensemble de l'équipe de développement. Il n'est pas très difficile de filtrer les logs sur "erreur" ou "warning" et d'inclure ça aussi dans le mail. Le script peut aussi ajouter un rapport d'état à une page HTML visible de tout le monde de manière à ce que les programmeurs et les testeurs puissent déterminer rapidement quelle génération a été effectuée avec succès.
  • Une règle suivie dans l'équipe Excel, avec grand succès, était que quiconque cassait le processus de génération devenait responsable du baby sitting des générations jusqu'à ce que quelqu'un d'autre le casse. En plus de servir d'incitation intelligente à conserver le processus de génération en ordre de marche, ça a permis à tout le monde à tour de rôle d'exercer le travail d'administrateur des générations, de telle sorte que chacun a appris comment l'application était générée.
  • Si votre équipe travaille dans un seul fuseau horaire, un bon moment pour lancer les générations est pendant le repas de midi. De cette façon, chacun fait un check-in de son dernier code juste avant le repas, la génération s'effectue pendant qu'ils mangent, et lorsqu'ils reviennent, si le processus de génération est cassé, tout le monde est dans le coin pour essayer de le réparer. Aussitôt que la génération fonctionne, chacun peut faire un check-out de la dernière version sans peur d'être importuné par une génération qui ne fonctionne pas.
  • Si votre équipe travaille dans deux fuseaux horaires, planifiez la génération quotidienne de manière que les gens dans un fuseau horaires n'importunent pas les gens dans l'autre fuseau. Dans l'équipe Juno, les gens de New-York faisaient des check-in à 7 heures du soir heure de New-York. S'ils cassaient le processus de génération, l'équipe d'Hyderabad, Inde, arrivait au travail (à environ 8 heures du soir heure de New-York) et était complètement bloquée pour la journée. Nous avons commencé à faire des générations quotidiennes environ une heure avant que chaque équipe rentre à la maison, et entièrement résolu ce problème.

Pour plus d'informations :

  • Une discussion à propos des outils pour les générations quotidiennes.
  • Faire des générations quotidiennes est suffisamment important pour faire partie des 12 points pour améliorer le code.
  • Il y a un tas de choses intéressantes à propos des générations faites (de manière hebdomadaire) par l'équipe Windows NT dans le livre de G. Pascal Zachary Showstopper. .
  • Steve McConnell écrit à propos des générations quotidiennes ici.


Cet article est paru en version originale anglaise sous le titre Daily Builds Are Your Friend  

Joël Spolsky est le fondateur de Fog Creek Software, une petite société éditrice de logiciel située à New York. Il est diplômé de l'Université de Yale et a travaillé comme programmeur et manager chez Microsoft, Viacom et Juno.


Le contenu de ces pages représentent l'opinion d'une personne.
Contenu protégé par le copyright ©1999-2005 par Joël Spolsky. Tous droits réservés.

FogBUGZ | CityDesk | Fog Creek Software | Joel Spolsky