Sensibilisation aux projets logiciels Les projets logiciels la réalité en chiffres les cycles de vie les problèmes la qualité logicielle Les errements de la pratique bonnes habitudes erreurs classiques Il s’agit d’une sensibilisation à la gestion des projets logiciels, essentiellement à destination de ceux qui débutent, et pour qui un logiciel pourrait se résumer à un simple codage dans un langage. Dans un premier temps, on aborde des questions générales sur les projets logiciels, pour mettre en évidence les problèmes qui sont arrivés dans le passé, et comment mieux formaliser la gestion d’un projet. Ensuite, on s’intéresse à la manière de gérer ses logiciels, quand on développe de façon isolée (le cas d’un étudiant en thèse, par exemple). La gestion de projet doit être évidemment proportionnée à la taille du projet, mais il y a des bonnes habitudes à prendre quand on commence à développer. Bibliographie: voir la liste de Bernard Pichon Les références indiquées dans le texte peuvent être trouvées dans « Stratégies de développement rapide » Steve McConnell, Microsoft Press
La réalité... Taux d’échec 50% des projets n’aboutissent jamais 25% n’apportent aucune valeur ajoutée aux utilisateurs Retard 2/3 des projets dépassent largement les délais les grands projets ont un retard de 25% à 50% 50% des cas, le planning est établi avant les spécifs. 1) Chartier-Kastler. Et même 70% d’après le DoD en 1988. 3) Jones, 94 4) En fait, le retard est en général proportionnel à la taille du projet. Les erreurs classiques sont les suivantes: 1) humaines manque de motivation, personnel sous-qualifié, personnes à problèmes insurmontables, héroïsme (prise de risques extrêmes), augmentation d’effectif sur un projet en retard, conditions de travail (bureau bruyant), friction entre développeurs et clients, exigences irréalistes, absence de soutien au projet. 2) procédures Planification insuffisante, ou trop optimiste, abandonnée sous la pression. Sous-estimation des étapes en amont du projet, négligence de la qualité (tests superficiels), défaillance de la sous-traitance. 3) produit Excès de spécifications, instabilité des fonctionnalités demandées, excès de zèle des programmeurs, surenchères (planning assoupli en échange de fonctionnalités nouvelles), développement axé recherche. 4) technologie Croyance aux techniques miracles, ou surestimation, changement d’outils en cours de route, mauvaise gestion de configuration.
... en chiffres Défauts la cause la plus fréquente de dépassement de planning à l’origine de 50% des abandons de projets Incompréhension 65% des projets ont des mésententes avec le client 10% sont annulés suite à des attentes irréalistes Efficacité 40% des erreurs sont générées par le stress 65% du temps à des activités contre-productrices 1) Jones 1994 2) Standish Group, 1994 3) Jones, 1991 4) Valette & Mac Garry, 1989 Les différents chiffres montrent tous les échecs des projets, et donc, inversement, les aspects importants dans un projet.
Des étoiles et des bugs Commission d’enquête pour Ariane 5: “le logiciel a été considéré correct tant qu’il ne s’était pas révélé défaillant” “s’assurer que les revues prennent en compte le bien- fondé des argumentations au lieu de contrôler que les vérifications ont été faites” “il faut une définition nette des responsabilités” Et d’autres... Les jeunes chercheurs/ingénieurs ont l’avantage d’une double compétence, ce qui aide à traduire les spécifications scientifiques en spécif. techniques. Autre avantage chez nous, l’absence de coûts salariaux, et parfois plus de liberté pour les délais. Ce qui n’empêche évidemment pas des erreurs manifestes, comme celles décrites ci-dessus, et qui concernent notre discipline.
Projet logiciel logiciel projet logiciel projet méthode de développement structure systématique produit logiciel code documentation associée qualité logicielle Un logiciel doit être geré! - comme un projet - comme un produit
Triangle des Bermudes Le niveau de qualité est un compromis Le niveau de qualité d’un logiciel est un compromis entre les performances, le temps pour les obtenir, et leur coût. En fait, le graphique ne montre absolument pas le sens dans lequel s’effectue le compromis : augmenter les performances se fait en augmentant coût ou délai, augmenter le délai augmente également le coût, mais augmenter le coût ne garantit ni la diminution du délai, ni l’obtention de meilleures performances!
Le cycle de vie Période entre l’idée du logiciel et sa mise en service Phases de développement Spécification des besoins Conception préliminaire Conception détaillée Codage : 15% du travail Tests unitaires Tests d’Intégration Validation Entouré par spécification et maintenance 1) le cycle de vie, c’est le cycle de développement + la phase de spécification et la phase de maintenance. 2) Cycle de développement Cycle de vie spécification+planification 20% 8% étudier le problème analyser les besoins spécifier actions et données conception+ développement 30% 12% décomposer le projet affiner les parties, les coder documenter la conception tests + validation 50% 20% vérifier les fonctions tester les performances optimiser opération + maintenance 60% formation des utilisateurs appliquer le logiciel maintenance corrective et évolutive portage du programme ailleurs
Expression des besoins Cycle en V Expression des besoins Maintenance Spécifications Validation (recette) Conception générale Tests d’intégration Il s’agit du cycle classique. C’est aussi le cycle en cascade, où les flèches vont dans les deux sens (on vérifie à chaque étape la conformité aux spécifications de l’étape précédente). Les flèches bleues montrent les tests qui correspondent aux phases initiales. Le risque essentiel est dû au temps qui sépare l’expression des besoins de la phase de validation: on peut s’apercevoir après de longs mois que le produit n’est pas ce que voulait réellement le client. Conception détaillée Tests unitaires Réalisation (codage)
Cycle en V, caricature ;-) Cahier des charges Maintenance Euphorie Promotion des autres Études Mise en œuvre Inquiétude Punition des innocents Développement Production Panique Recherche des coupables Source anonyme IBM, sans doute basée sur une longue expérience de la gestion de projet ;-) Tests
Différents cycles Programmer-corriger Cascade simple Cascade modifiée avec chevauchement avec sous-projets avec réduction des risques Spirale Les phases de spécification, conception, tests sont présentes Le cycle dépend du projet Prototypage évolutif Livraison par étape Livraison évolutive Conception selon planning Conception selon outils Logiciel standard Se référer à la bibliographie pour l’explication des différences entre tous ces cycles de vie. L’important est que le cycle de vie dépend du projet. On voit par la suite les critères qui conditionnent ce choix. 1) bidouillage 2) voir cycle en V 4) voir feuille suivante 5) on ne jette pas le prototype Le problème essentiel est celui du planning. Classiquement, on compte le nombre de « points de fonctions », correspondant à un certain nombre de lignes de codes (dépendant du langage). Suivant la productivité moyenne d’un développeur, on peut calculer le nombre d’années-hommes qui seront nécessaires. Malheureusement années et hommes ne sont pas permutables, et ce n ’est pas en augmentant le nombre de personnes que l’on diminue le temps nécessaire à un projet (par ex, il faut 9 mois pour fabriquer un enfant, quel que soient le nombre de femmes affectées au projet!). Une loi empirique, le principe de Brooks, dit même que quand un projet prend du retard, ajouter des développeurs ne fait qu’accroître le retard. La raison en est que toutes les tâches ne sont pas partageables. Alors, la communication entre les personnes devient très demandeuse en temps, et le nombre de canaux de communication entre n personnes est n(n-1)/2, et donc augmente avec le carré.
Modèle en spirale Raffinement itératif Première itération Commencer au centre de la spirale, planifier le projet, et recueillir les besoins initiaux. Effectuer une analyse de risques basée sur les besoins initiaux, prendre la décision appropriée, et continuer si c'est positif. Créer un prototype initial du système L'usager évalue ( et le développeur) le prototype Deuxième itération Le feedback de l'évaluation est utilisé pour raffiner les besoins et on planifie davantage le projet. Effectuer une analyse de risques basée sur les besoins révisés, prendre la décision appropriée, et continuer si c'est positif. Créer un deuxième prototype, basé sur le prototype initial ou en construire un à partir de zéro. L'usager évalue ( et le développeur) le deuxième prototype N-ième itérations Répéter la deuxième itération si désiré Après la dernière décision Développer (ingéniériser) le système D’après Ingéniérie du logiciel, Ecole polytechnique de Montréal
Comparaison des cycles On s’est limité ici à quatre des modèles décrits auparavant, pour les comparer, et de faciliter ainsi leur choix. Chaque modèle de cycle de vie est qualifié avec -1, 0, +1, correspondant à faible, correct et excellent, respectivement. Il s’agit d’un maximum, tout dépendant de la mise en œuvre. 1) les spécifications du produit sont mal comprises ou susceptibles d’être modifiées 2) application entièrement nouvelle ou bien caractéristiques inconnues 3) taux de défaut susceptible d’être généré 4) capacité de modif du produit en taille (et orientation non prévues initialement) 5) capacité à identifier et à contrôler les risques liés au planning et au produit 6) peut être soumis à un planning bien défini 7) temps nécessaire pour utiliser efficacement le modèle (planification+évaluation d’avancement+documentation+réalisation+annexe) 8) possibilité de modifications de certains aspects du produit en cours de projet 9) capacité à indiquer la progression du projet au client 10) capacité à indiquer la progression du projet à la hiérarchie 11) ne nécessite pas de hautes compétences du chef de projet et des développeurs
Pathologies des développeurs pervers médiocre bûcheur planificateur optimal 1) coder tout de suite 2) jeter logiciel et aller en 1 peu de temps sur conception logiciel fini à 90%, 90% du temps planning + conception pas le temps pour les tests planning + planning pas le temps pour coder un juste équilibre en tout ! Beaucoup de programmes de taille petite ou moyenne sont conçus par une seule personne. Le cycle de vie du logiciel dépend alors fortement de la personnalité du développeur. Ces styles sont décrits ci-dessus. Entre celui qui code sans conception préliminaire (et dont le programme termine à la poubelle), et celui qui fait de l’(aqua)planning sans coder, il y a une juste limite, qui est de consacrer le temps nécessaire à chaque étape du projet logiciel.
Les algorithmes Complets Non-ambigus Déterministes Finis Généraux Bien structurés Efficaces Ce qu’il faut garder en mémoire quand on écrit un algorithme: 1) toutes les actions sont définies exactement 2) ne doit permettre qu’une seule interprétation 3) toujours produire un résultat prédictible 4) ne doivent demander qu’un espace (disque) et un temps d’exécution finis 5) applicable à toute une classe de problèmes 6) écrits avec une structuration en bloc 7) autant que possible économes en ressources
Niveau (approximatif) de langage on développe à peu près le même nombre de lignes/mois (la productivité individuelle variant néanmoins de 1 à 10) donc développement plus ou moins rapide mais dépend de l’utilisation Tous les langages ne sont pas équivalents. Plutôt que de parler de langage de 3eme ou 4 eme génération, il est possible de comparer les langages entre eux, en considérant le nombre d’instructions assembleurs équivalentes à une instruction du langage. Les chiffres varient clairement avec le type de codage: se servir du C++ comme d’une version sécurisée de C ramène le niveau du C++ à celui du C: mieux vaut programmer bien avec un L3G que mal avec un L4G!. C, Fortran, Cobol, Pascal sont à peu près au niveau 3 (là où une fonction demanderait 300 instructions assembleurs, 100 sont nécessaires). Les SGBD (Oracle, dBase IV) ainsi que les langages visuels sont au niveau 10. Les macros Excel, utilisées par les utilisateurs finaux augmentent de façon spectaculaire la productivité. D’après Programming languages tables, Jones 1995 En effet, et c’est là le point-clé, les développeurs ont tendance à écrire à peu près le même nombre de lignes de programmation par mois, quelque soit le langage utilisé (Putnam et Myers, 1992).
Les tests Les mauvaises excuses pas le temps pas les moyens techniques pas l’argent Coût relatif des erreurs suivant la phase Surnommés “l’arlésienne du développement”, les tests sont souvent délaissés sous des prétextes divers: 1A) Le temps requis est grossièrement équivalent au temps de codage. Comme on a pu le voir, ce temps de codage est très réduit, pour autant que le temps nécessaire à l’analyse et à la conception ait été correctement appliqué. 1B) Comme ailleurs, la règle des 80/20 s’applique : seul 20% des tests poserait des problèmes techniques ou financier, alors que l’essentiel peut être réalisé assez facilement. Dans tous les cas, tout dépend du niveau de qualité requis, et un compromis doit être trouvé. 1C) Curieusement, on arrive à savoir ce que coûteraient les tests s’ils étaient faits, mais pas combien coûterait au projet les conséquences de l’absence de tests. Ce qui suit est un élément de réponse. 2) L’erreur est humaine, d’accord, mais il faut la corriger le plus tôt possible. Le tableau ci-dessus indique le coût relatif (et approximatif) dans les mauvais cas d’une erreur suivant le moment où elle est découverte et corrigée. Corriger le problème en aval coûte 100 fois plus cher que le traiter en amont!
Quels tests ? Tests statiques respect architecture respect structure unitaires (fonctions) d’intégration (modules) systèmes (logiciel) validation (logiciel) conception détaillée conception globale spécification cahier des charges Tests statiques respect architecture respect structure variables commentaires Tests dynamiques unitaires enchaînement performance stress 1) par les développeurs. Respect de la conception détaillée 2) Respect de la conception globale (interface entre modules) 3) Respect des spécifications (niveau de performance, correction, fiabilité) 4) par l’utilisateur final. Respect du cahier des charges
Gestion de code Version ensemble de modules + compilés + linkés gelés en configuration Domaine public: RCS ou SCCS gestion des versions travail collectif sauvegarde On peut rappeler néanmoins quelques règles, qui sont indispensables non seulement lorsque l’on travaille en équipe (cf l’équipier qui écrase par mégarde vos fichiers), mais aussi individuellement. Pour RCS, créer un répertoire RCS, puis après avoir édité un fichier ci -u fichier il devient alors interdit en écriture co -l fichier dernière version récupérée et écriture autorisée On peut mettre un numéro de version derrière les options (e.g. ci -u1.5) rcsdiff -r1 -r2 donne les différences entre les versions r1 et r2 rlog donne les commentaires (rentrés avec ci) On peut mettre dans le programme les chaînes $Id$ ou $Revision$ ou $Author$ $Date$. Ces chaînes sont substituées par leur valeur exacte lors du ci. On peut par exemple les mettre dans des chaînes de caractères dans le programme, et retrouver ainsi (même dans l’exécutable, par la commande strings) les versions associées à chaque module
La documentation Au minimum définition des besoins spécification logicielle description des interfaces sources tests (procédures+résultats) manuel utilisateur La règle ne doit pas se substituer à l’intelligence volume documentation volume du projet Ne pas oublier de documenter. Quand on reprend un programme 6 mois après l’avoir développé, on est content de retrouver sa description. 1) le minimum-minimorum, c’est d’enfouir dans le logiciel un minimum de documentation, une aide en ligne 2) Le mieux est l’ennemi du bien : ne pas confondre documentation et paperasserie.
Critères de qualité Aptitude à être utilisée en l’état sûreté efficacité commodité Aptitude à être transférée Aptitude à être maintenue testée comprise modifiée Boehm, 1976 1A) Autosuffisance + précision + exactitude + complétude + robustesse + cohérence 1B) Répétitivité + crédibilité + économie en moyens + accessibilité 1C) Robustesse + accessibilité + simplicité du dialogue 2) Indépendance du matériel + autosuffisance 3A) Répétitivité + crédibilité + autodescription + structuration 3B) Cohérence + autodescription + structuration + concision + lisibilité 3C) Structuration + extensibilité
II) Recettes Réutiliser des composants logiciels documentés re-testés! Écrire des commentaires significatifs Prototyper le programme Avoir un bon environnement de développement Utiliser des outils de génie logiciel (UML) Porter sur une autre architecture Éviter d’en faire trop! 4) environnement de développement éditeur compilateur débogueur référenceur profileur gestion de code 6) quand on a un programme qui a été bien testé, le porter sur une autre machine (autre compilateur + autre système d’exploitation + autre taille de mot-machine). Marche-t’il encore à 100% ?
Modularité Top-down Makefile entrée ... (programmes, fichiers) ... Sortie Gestion des modules avec RCS 1) La décomposition en sous-systèmes date de la préhistoire (pour manger un mammouth, le découper d’abord!). 2) Pour un projet de taille limitée, les outils disponibles sous Unix sont souvent suffisants. Par exemple, le make, qui est prévu à l’origine pour obtenir des versions exécutables à jour peut être détourné pour obtenir la mise-à-jour automatique d’un projet. Pour un projet classique : à partir de plusieurs fichiers d’entrée, plusieurs fichiers de sortie sont attendus, avec des étapes générant des fichiers intermédiaires, des graphiques, etc, eux-mêmes réalisés par programme. L’ensemble est géré par des Makefile si bien que la modification (non prévue, mais qui peut arriver) des fichiers d’entrée ne coûte que la commande “make” pour fournir des fichiers de sortie à jour. Toute modification de fichier, source de programme, étant automatiquement répercutée sur le résultat.
Écriture Header Utiliser la même trame C.IDENTIFICATION $Id: main.c,v 1.10 1996/08/30 15:18:53 Durand Exp$ C.TYPE program C.LANGUAGE FORTRAN C.AUTHOR C. Durand C.ENVIRONMENT Unix C.KEYWORDS magnitude, reddening C.PURPOSE Calcul du derougissement et de la magnitude absolue C.COMMENT 1.0 19-Feb-1992: Utiliser la même trame gérant l ’option -h avec une fonction usage() passage d ’argument sur la ligne de commande Nombre de lignes fonction: quelques dizaines module: quelques centaines Pour faciliter la lecture des logiciels, faire débuter les modules, voire les fonctions par un en-tête qui fournit le minimum de renseignements. Le faire de façon standardisée permet par la suite d’extraire les champs (automatiquement, par un programme écrit pour ça). Par exemple, rechercher tous les fichiers sources où il y a un mot-clé donné; ou bien élaborer un début de documentation
Variables et lisibilité Une variable a un type Une variable n’a qu’un type Une variable n’a qu’un sens Donner des noms significatifs Convention de nommage Éviter les variables globales « implicit none » éviter a=2; a=“oui”; éviter i=k; i=2*i+a; result=3; plutôt que i=3; gStarFlux (globale) 1) une légende (tenace) indique qu’une des raisons de la catastrophe de de la navette spatiale serait due au code fortran suivant: DO 30 I=1.1000 … 30 CONTINUE Le point à la place de la virgule, et l’absence de implicit none faisant croire au compilateur qu’il s’agit d’une variable DO30I qui est initialisée à la valeur 1.1, et la boucle exécutée une fois seulement!
Erreurs classiques utiliser un prototype option compilateur, tests initialiser pointeurs à 0, tester éviter a[i++]=b[i++] if (3==i) au lieu de (i==3) #idfef COMMENT allouer/désallouer souvent accès mémoire interdit passage d’argument dépassement de tableau mauvaise initialisation ordre d’évaluation affectation vs comparaison commentaires mal fermés fuite de mémoire erreurs aléatoires Il n’est pas possible de faire le tour de toutes les erreurs dues à l’imagination fertile des développeurs. On peut quand même donner les plus fréquentes. Surtout, renforcer le contrôle du compilateur. Tout ce qui est détecté à la compilation (là où l’on sait à quel endroit du code est l’erreur) est autant de problèmes en moins au moment de l’exécution, là où ils sont le plus difficile à détecter. 4) c’est aussi valable pour le passage d’arguments modifiés au retour: CALL SUB(i,i) redonne un résultat imprévisible. Ne pas oublier que l’impossible finit toujours par se produire. Toujours tester les flags d'erreurs en retour de procédure, les dépassements de tableau, les valeurs des pointeurs lors d’allocation mémoire
Conclusion La créativité... réussir une opération complexe construire un outil utile à soi-même et aux autres acquérir des nouvelles connaissances … n’exclue pas la méthode maîtriser ses objectifs et ses ressources être lié aux autres contraint à la rigueur Les 4 dimensions d’un projet logiciel les personnes les méthodes le produit les technologies Acte essentiellement créatif, le développement doit néanmoins se faire avec un minimum de rigueur.