Qualité Developpement Henocque Esil Info.key

Transcription

Qualité Developpement Henocque Esil Info.key
Qualité en
Développement
par Laurent Henocque
Enseignant Chercheur LSIS-Polytech Marseille/IRM
http://laurent.henocque.com
mis à jour en Novembre 2012
mardi 20 novembre 12
1
Licence Creative Commons
Cette création est mise à disposition selon le Contrat
Paternité-Partage des Conditions Initiales à
l'Identique 2.0 France disponible en ligne
http://creativecommons.org/licenses/by-sa/2.0/fr/
ou par courrier postal à Creative Commons, 559
Nathan Abbott Way, Stanford, California 94305,
USA.
mardi 20 novembre 12
2
Objectifs
• Ce cours a pour projet de donner les bases de
techniques de travail reconnues comme
nécessaires pendant tout le cycle de vie du
logiciel, et
• d'apprendre les méthodes qui permettent
d'affronter systématiquement et de résoudre les
problèmes.
mardi 20 novembre 12
3
Plan
• Concepts fondamentaux de qualité logicielle,
• notamment les notions de contrats, d'invariants et une
discussion sur la notion de test.
• Comment l’activité de programmation peut être
organisée, dans un objectif de qualité.
• Considérations techniques sur la qualité.
• Aspects humains (psychologiques notamment)
mardi 20 novembre 12
4
Qualité en
programmation
Notions fondamentales
mardi 20 novembre 12
5
Le contrat
• Principe fondamental dans toutes les activités
industrielles ou plus généralement économiques,
le contrat est aussi un fondement de toutes les
étapes de l'élaboration d'un logiciel, de sa
spécification jusqu'à son abandon.
• Bien sûr, en fonction du point auquel on se situe,
la nature et les effets des différents contrats seront
variables.
mardi 20 novembre 12
6
Le contrat
• Le contrat garantit une communication sans
défaut, par un examen exhaustif de tous les cas
nécessaires
• un bon contrat lève toute ambiguïté entre ses
parties.
• Le contrat est un support fondamental de la
simplicité des solutions mises en oeuvre pour le
respecter.
• En effet, il permet de travailler en monde clos, et
de ne pas anticiper des évolutions improbables.
mardi 20 novembre 12
7
Documents contractuels
• Réponses aux questions suivantes :
• "quoi" : quelles sont les fonctionnalités à
implanter,
• "comment ": comment accède t'on à ces
fonctionnalités,
• "quand" : quelles sont les limites hors
desquelles ces fonctionnalités ne sont pas
accessibles (pas implantées).
• Ces contrats lient dans tous les cas des "clients" et
des "fournisseurs".
mardi 20 novembre 12
8
Trois niveaux de contrat en
informatique
• Le plus haut niveau permet la communication
entre acheteur du logiciel et prestataire, c'est le
cahier des charges (spécification).
• Le niveau suivant lie les membres d'une équipe
d'informaticiens: le document de conception.
• Enfin, avec la granularité nécessaire, le dernier
niveau lie les programmes (et programmeurs)
entre eux : les invariants
mardi 20 novembre 12
9
La spécification : contrat entre
client et fournisseur
• Le client admet que ses besoins y sont exprimés
de façon correcte et complète, et donc accepte
d'avance toute solution conforme.
• définis par exemple au moyen d'UML:
diagrammes de cas d'utilisation, et séquence
système
• Le prestataire sait de son côté que les solutions
qu'il envisage sont réalisables (dans les délais,
ceux ci pouvant apparaître comme un besoin
dans la spécification).
mardi 20 novembre 12
10
Vision du développement
agile
• Une partie importante des projets informatiques est
aujourd'hui réalisée en développement agile
• en itérant de façon très rapide des prototypes,
destinés à recaler le cahier des charges selon un
mécanisme de boucle de feedback
• Chaque itération adresse les points identifiés comme
présentant le plus fort risque pour la bonne fin du
projet (technologiques notamment, mais pas seulement)
• Cette approche est rendue nécessaire pour des projets
difficiles ou impossibles à spécifier d'avance
mardi 20 novembre 12
11
(Mots clé Scrum)
• Product Backlog : la liste des 'user stories' (un besoin est
formulé sur l'espace d'un post it
• Sprint Backlog : les 'user stories' sélectionnées pour le
sprint courant (d'après leurs story points, et leur valeur)
• Sprint: un cycle
• Daily Scrum: la réunion quotidienne où l'on répond aux
trois questions
• qu'ai je fait depuis hier
• que dois-je faire aujourd'hui
• quels points de blocages sont rencontrés?
mardi 20 novembre 12
12
La conception : contrat liant
les membres de l'équipe
• La conception décrit de manière détaillée
l'ensemble des solutions techniques devant être
mises en oeuvre pour implanter ce qui a été
spécifié.
• Il est formellement impossible de faire plus, ou
moins, que ce que la conception a décrit.
mardi 20 novembre 12
13
Contrat entre programmes
Chaque élément logiciel s'engage sur les points suivants :
• quoi : quelle est la fonctionnalité implantée par ce
programme
• programme de test, manuel d'utilisation
• comment : selon quelle interface de programmation
(noms de fonction, types)
• programme de test, charte, manuel de référence
• quand : quelles sont les données pour lesquelles son
fonctionnement est garanti
• dans le code: invariants de classe, pré-conditions,
manuel de référence, commentaires javadoc
mardi 20 novembre 12
14
Que faire quand un appel
contredit les pré-conditions?
La communauté des développeurs est tiraillée entre
deux approches contradictoires
• La programmation défensive vise à permettre au
programme de survivre aux appels de fonction
sortant de son domaine de définition
• La programmation 'offensive' (néologisme récent)
vise à donner la possibilité au développeur
• d'être informé au plus près de l'erreur ('fail
fast')
• d'être dans l'obligation absolue d'intervenir
immédiatement (arrêt brutal du programme)
mardi 20 novembre 12
15
Approche offensive avec
ASSERT
• Supposons qu'on implémente la division réelle
y = f(x,z) = x/z
• La valeur z=0 est hors du domaine de définition de
la fonction.
float divise(float x, float z)
{
assert (z!=0);
return x/z;
}
• assert provoque l'arrêt du programme au plus tôt,
et réalise donc 'fail fast' et l'obligation de correction
immédiate
mardi 20 novembre 12
16
ASSERT : une vision
conditionnelle
• Historiquement (ci dessous en C), assert est actif
en mode debug, et retiré en production
• Aujourd'hui assert reste souvent dans le code
distribué (envoi de mail aux développeurs)
mardi 20 novembre 12
17
A l’inverse: l’approche
défensive
• ‘Défensif’ signifie que le programme se ‘défend’
contre les erreurs d’utilisation et cherche à
continuer autant que possible.
• Cela possède plusieurs inconvénients
mardi 20 novembre 12
18
Approche pseudo 'défensive'
moderne: les Exceptions
• Les langages de programmation modernes (C++,
Java) permettent de gérer les exceptions
• Il s'agit d'un mécanisme de contrôle particulier,
mais la prise en charge de ces exceptions rentre
dans le contrat au sens propre.
• Les exceptions font partie de la fonctionnalité /
des services offerts à l’utilisateur
mardi 20 novembre 12
19
Le ‘Comment’ : Interfaces de
Programmation Normalisées
• On définit habituellement des chartes et guides de style
pour les types et signatures de fonctions et méthodes.
• les fonctions du module graphique débutent par
"Gr",
• les symboles globaux commencent par une
majuscule,
• les objets statiques sont en majuscules,
• aucun nom de variable n’a moins de six caractères
etc…
• Vérifier ce 'comment' est réalisé par le compilateur
mardi 20 novembre 12
20
Principe de
l’Utilisateur
Parfait
Fondements de la programmation Offensive ou
Fail Fast
mardi 20 novembre 12
21
Principe de l'utilisateur
parfait
• Tout programme s'engage à se comporter comme
un utilisateur parfait de ses ressources (les
fonctions qu'il appelle),
• c'est à dire à ne jamais appeler une fonction dans des
conditions qui la mettent hors de son domaine de
définition.
• Tout programme qui fournit un service au
système s'engage à fonctionner correctement
lorsque ses éléments de calculs sont valides.
mardi 20 novembre 12
22
Traduction technique
•
Aucune fonction ne doit s'attendre à gérer un cas
ou un autre élément de programme fournirait des
données incorrectes.
•
Aucune fonction ne doit tester les arguments de
son calcul pour leur correction.
mardi 20 novembre 12
23
Utilisation d'invariants
• Un invariant est une propriété logique qui est
toujours vraie pendant l'exécution d'une partie
d'un programme,
• soit un pré-requis ou une condition
• (condition sur les données en entrée nécessaire pour le
déroulement d’un programme),
• soit implicite du fait de la nature du programme
• (la définition et la vérification des invariants implicites
est un outil de base dans la preuve formelle de
programmes).
mardi 20 novembre 12
24
Défensif ou
offensif???
La discussion qui n'en finit pas
mardi 20 novembre 12
25
Modèle de la Programmation
Offensive ‘Assertive’
• Une fonction qui implante un algorithme ne teste
jamais l'appartenance de ses arguments au
domaine de définition.
• Les cas d’erreur doivent être captés par des
invariants, de manière à :
• informer les développeurs au plus près de la
source de l’erreur quand elle se produit
• obliger à la correction de l'erreur
• documenter le source
mardi 20 novembre 12
26
Programmation Défensive
• Le modèle dit de programmation ‘défensive’ vise
à permettre la continuation d’un programme
même en cas d’erreur.
• cas rares : la fonction ne fait rien (e.g. chgt. de
couleur non prise en charge en ihm)
• vue moderne : on lance une exception
• Une couche défensive peut toujours être ajoutée
à une application Assertive.
• L’inverse aussi, mais aboutit à du code inutile.
mardi 20 novembre 12
27
Pour l'offensif
• plus facilement débuggé
• plus facilement maintenu
• ne coûte rien en production
• peut être complété par un code défensif
• offre une garantie absolue de fonctionnement par
la couverture des tests
• offre une documentation vivante et testée:
toujours correcte
mardi 20 novembre 12
28
Et le défensif?
• utile dans des situations très spécifiques sans
danger (affichage d'une couleur inexistante...)
• irréaliste dans le cas général
• très souvent on ne sait pas comment poursuivre
l'exécution
• provoque des erreurs en cascade difficiles à
remonter
mardi 20 novembre 12
29
Défensif Dangereux
• Ou l’on ne veut surtout pas que le programme
s’arrête - combien de temps?
mardi 20 novembre 12
30
Défensif Paresseux
• Où la paresse l’emporte
mardi 20 novembre 12
31
Défensif Moderne :
Exceptions
• Ou l’on se dit - lançons une exception,
l’utilisateur/programmeur saura quoi en faire.
mardi 20 novembre 12
32
Offensif
• On ne teste pas les domaines. On les asserte
mardi 20 novembre 12
33
Impact sur la performance
• Dans de très nombreuses situations, les
algorithmes garantissent que les conditions
d'appel des fonctions sont satisfaites.
mardi 20 novembre 12
34
Difference entre assert et
exceptions
• Une assertion signale un bug devant être pris en
charge par un humain
• Les assertions documentent des situations qui
sont impossibles, et offrent un mécanisme qui
prévient le développeur aussi tôt que possible
• Une exception signale une erreur pouvant être
prise en charge par un programme
• Les exceptions offrent un flux de contrôle
différent du flux standard, mais qui réalise une
fonctionnalité utile
mardi 20 novembre 12
35
Commentaire final
• Les invariants de domaine fournissent une
documentation vivante intégrée au programme utile pour la maintenance
• Des tests défensifs inutiles dans un programme
ne peuvent jamais être enlevés
• Par contre si nécessaire, on peut toujours
compléter les API avec des versions défensives
mardi 20 novembre 12
36
Le Assert
Historique
Génèse de la programmation Offensive ou Fail
Fast
mardi 20 novembre 12
37
Le code C/C++ de la macro
« assert »
• En C/C++, l’outil de base pour la vérification d’invariants
dans les programmes est la macro « assert »
#ifndef NDEBUG
#define assert (test) \
if(!(test)) { \
printf ("assertion failed %s line %d in
file %s\n", #test, __LINE__, __FILE__ ); \
abort();
#else
#define assert (test) /*ignore*/
#endif
mardi 20 novembre 12
38
Exemple: definition de 1/x
mardi 20 novembre 12
39
Test de 1/x en C/C++
mardi 20 novembre 12
40
Compiler Assert en C/C++
• Compiler avec les assertions:
CC -o test test.cc
• Compiler sans les assertions:
CC -o test -DNDEBUG test.cc
mardi 20 novembre 12
41
Comparaison: utiliser assert
en Java
• En Java, 'assert' est une instruction du langage,
pas une primitive compilée conditionnellement
• L'option 'java -ea' permet de lancer une instance
de la JVM qui teste les assert présents dans le
code
• Par défaut, les assert sont ignorés (mais pas
retirés: ils peuvent même être activés par
programme - quoique techniquement délicat)
mardi 20 novembre 12
42
Différents types
d'invariants
mardi 20 novembre 12
43
Invariants de compatibilité
système
• Ces invariants permettent de valider le respect
par l'architecture matérielle et logicielle de
conditions nécessaires au programme
mardi 20 novembre 12
44
Invariants de compatibilité de
bibliothèques
• On vérifie que les types définis par deux
bibliothèques distinctes sont compatibles
mardi 20 novembre 12
45
Invariants d’étape dans les
algorithmes
• décrit une condition connue comme devant être
vraie en un point d’un algorithme
• Par exemple un pointeur non nul à la sortie d'une
boucle
mardi 20 novembre 12
46
Exemple
// tab est un tableau d’entiers positifs
int Max=-1;
int MaxI=-1;
for (int i=0; i<N;i++){
assert(tab[i]>=0);
if (tab[i]>Max){Max=tab[i];MaxI=i;}
}
assert(Max>-1);
assert(MaxI>=0);
assert(MaxI<N);
tab[MaxI]--; // toujours valide
mardi 20 novembre 12
47
Variants de boucle
• Un tel invariant s’appelle un « variant » parce
qu’il décrit le fait que deux itérations successives
d’une boucle modifient la valeur d’une variable
de contrôle d’une manière telle que l’on sait que
le programme va s’arrêter.
mardi 20 novembre 12
48
Exemple de variant de boucle
mardi 20 novembre 12
49
Invariants de classe
• Ces invariants décrivent des conditions vraies de
toutes les instances d’une classe à tout moment
de leur existence compris entre
• la fin de leur construction et
• le début de leur destruction
mardi 20 novembre 12
50
Exemple
mardi 20 novembre 12
51
Organisation de
l'activité
mardi 20 novembre 12
52
Compiler et exécuter dès le
début de son activité
• Les outils de génération de code sont la première
aide du programmeur.
• compiler aussi tôt que possible, avec tous les
fichiers include des bibliothèques que l'on va
utiliser.
• linker avec les bibliothèques que l'on doit utiliser
par la suite.
• exécuter le programme de façon à pouvoir le
tester.
mardi 20 novembre 12
53
Sauver le temps
• Ne pas programmer de fonctions inutiles."
• Communiquer l'information.""
• Messageries, aide et manuel de référence en
ligne, cvs.
• Réduire le temps d'accès à l'information."
• utilisation d'outils
mardi 20 novembre 12
54
Sauver le temps
• Documenter ses programmes.
• Protéger ses programmes.
• assert permet de presque totalement supprimer les
recours au débugger.
• Réduire la charge des machines.
• dans des projets importants la progression vers le but
s'accompagne d'une montée en charge du système.
• prendre les décisions qui s'imposent pour que la
compilation et les tests se fassent en un temps
acceptable.
mardi 20 novembre 12
55
Savoir automatiser
• Bien utiliser les outils disponibles pour gagner du
temps et des efforts rébarbatifs est fondamental
dans l'activité de développement.
• La mise en oeuvre d'un automatisme annexe doit
prendre un temps négligeable au regard du
problème posé (disons que cela se compte en
minutes en général).
mardi 20 novembre 12
56
Exemple: un shell pour l'appel
récursif d'une commande dans
les sous répertoires
mardi 20 novembre 12
57
Avoir une démarche produit
• documenter
• tester
• assurer la compatibilité ascendante de ses
programmes
• assurer la portabilité
• permettre la ré-entrance
• séparer les algorithmes et les interfaces homme
machine
mardi 20 novembre 12
58
Principes de documentation
• Les invariants constituent le fondement de la
documentation interne.
• La structure logique d'un programme (tests et
boucles) parle d'elle même au lecteur lui même
programmeur.
• Une documentation intégrée redondante est inutile.
mardi 20 novembre 12
59
Principes de documentation
• Quand une expression évaluée dans un test n'est
pas suffisamment explicite pour le comprendre,
un commentaire est nécessaire.
• Lorsqu'un programme possède un effet de bord
non évident, cela doit être documenté.
• Un invariant qui ne peut raisonnablement pas
être testé doit être mentionné en commentaire.
mardi 20 novembre 12
60
La ligne de compilation avec
tests unitaires
Un exemple de makefile pour une bibliothèque
d'outils - application au langage C++
mardi 20 novembre 12
61
mardi 20 novembre 12
62
mardi 20 novembre 12
63
mardi 20 novembre 12
64
mardi 20 novembre 12
65
mardi 20 novembre 12
66
Organiser
L'accès à
L'Information
mardi 20 novembre 12
67
Structurer
•
•
Décider que chaque classe (C++) est décrite dans un jeu de fichiers
spécifiques, quelle qu'en soit la complexité.
•
avantages: la règle est facile à suivre
•
grouper par classes reflète la structure logique interne des
classes dans les fichiers (c'est le choix du langage Java).
Ou alors, grouper dans un fichier unique les programmes relevant
de l'impression, ou de la trace, pour toutes les classes.
•
•
avantages: les programmes de trace ont des traits communs
faisant que leur présence groupée dans un fichier unique permet
d'en programmer rapidement de nouveaux "par l'exemple".
Quelle que soit l'approche, on aura dans certains cas besoin
d'informations orthogonales.
mardi 20 novembre 12
68
Accéder
• L'organisation en répertoires n'offre pas tous les points de vue
nécessaires pour disposer de toutes les informations utiles.
• Il faut des outils pour trouver une information aussi
rapidement que possible.
• ex: consulter le source d'une méthode de sérialisation
• ex: retrouver la déclaration d'une fonction
• Sous Unix, les outils de base "grep", "sed" et "awk" sont
précieux pour concevoir des programmes de recherche
d'information dans des sources. Ils doivent être utilisés en
l'absence de meilleur outil.
• Les environnements de développement modernes (Visual,
Eclipse) offrent de multiples possibilités
mardi 20 novembre 12
69
Exemple: un shell d'extraction
de source
mardi 20 novembre 12
70
Ne pas dupliquer
mardi 20 novembre 12
71
Classe, Fonction ou Macro?
• Il y a des cas ou un fragment de code qui ne
correspond pas à une unité identifiable du
langage doive être répétée
• Dans ce cas on doit utiliser le macro processeur
mardi 20 novembre 12
72
Ex: décl/init de variable
locale
mardi 20 novembre 12
73
Ex : action locale répétée
mardi 20 novembre 12
74
Ex : comparaisons en cascade
mardi 20 novembre 12
75
Ex Comparaisons (2)
mardi 20 novembre 12
76
Ne maintenir qu'un seul
source
mardi 20 novembre 12
77
Apports de la compilation
conditionnelle
• permettre la compilation sur toutes les plate
formes,
• ne jamais oublier de version,
• réduire le nombre des fichiers source utilisés,
• utilisation optimale des ressources de chaque
environnement,
• éviter l'oubli des conditions dans lesquelles la
variabilité apparaît.
mardi 20 novembre 12
78
Aspects
techniques
Distinguer les différents types de paramètres
mardi 20 novembre 12
79
Paramètres machine
• Les paramètres machine sont ceux qui sont liés à
l'architecture physique de la machine.
• mots de 32 bits ?
• nombre de registres internes au processeur? Un
"garbage collector " en dépendra certainement.
• Le pré processeur C permet de prendre en compte des
symboles définis automatiquement par le compilateur,
ou explicitement par la commande de compilation, pour
s'adapter aux variations d'architectures physique.
• Le symbole correspondant s'appelle ARCH sous Unix.
Sa valeur lors d'une compilation est connue.
mardi 20 novembre 12
80
Exemple
mardi 20 novembre 12
81
Paramètres système
• Le système d'exploitation pose également des
conditions sur l'exécution des programmes.
• Par exemple, le nombre de fichiers qu'il est
possible d'ouvrir simultanément est variable,
comme le nombre de processus, ou de threads
qu'il est possible d'exécuter à un moment
donné.
mardi 20 novembre 12
82
Paramètres de
configuration
• Paramètres transmis par l'environnement
qui permettent l'exécution du programme
mardi 20 novembre 12
83
Les variables d'environnement
mardi 20 novembre 12
84
Paramètres d'exécution
• Les données qui peuvent varier d'une exécution à
une autre et qui ne dépendent ni de la machine,
ni du système, ni de la configuration sont les
paramètres d'exécution.
mardi 20 novembre 12
85
Passage de ces paramètres
mardi 20 novembre 12
86
Parser Argv
mardi 20 novembre 12
87
Parser Argv (2)
mardi 20 novembre 12
88
Parser Argv (3)
mardi 20 novembre 12
89
Constantes
• La bonne manière de déclarer les constantes est la
dernière:
mardi 20 novembre 12
90
Gestion de la
mémoire
mardi 20 novembre 12
91
Mémoire statique
• espace associé au code du programme, et sous
Unix il en est très proche physiquement.
• réservé par la déclaration d'une variable globale
mardi 20 novembre 12
92
Mémoire Statique
mardi 20 novembre 12
93
Réentrance
mardi 20 novembre 12
94
Réentrance en action
mardi 20 novembre 12
95
Classe "Utility"
mardi 20 novembre 12
96
Mémoire automatique
• espace alloué sur la pile d'exécution
mardi 20 novembre 12
97
Adresses invalides
mardi 20 novembre 12
98
Mémoire dynamique
• Espace total disponible pour le programme (hors
pile d'exécution liée à la mémoire automatique).
• Cet espace est égal lors du lancement du
programme à celui strictement nécessaire au
chargement dans la mémoire vive du code
programme et des données statiques.
• Un programme peut ensuite demander
explicitement de la mémoire à l'aide de la
fonction "sbrk".
mardi 20 novembre 12
99
Panorama de la mémoire
mardi 20 novembre 12
100
Conventions générales pour
l'allocation de mémoire
• En aucun cas une fonction ne peut renvoyer
l'adresse d'un espace alloué automatiquement.
mardi 20 novembre 12
101
Allocation de mémoire (2)
• Lorsqu'une fonction retourne un pointeur, il faut
savoir de façon non ambiguë (documentée) si le
pointeur désigne une zone allouée par la
fonction, ou bien une zone accessible par l'un de
ses paramètres, et donc allouée antérieurement.
• Il faut éviter d’avoir un mécanisme mixte :
valeur allouée dans certains cas, non allouée
dans d'autres.
mardi 20 novembre 12
102
Allocation de mémoire (3)
Lorsqu'une fonction prend un pointeur en paramètre, elle
n'effectue jamais de duplication des données.
• faisabilité : la fonction appelée ne dispose pas toujours des
informations permettant une copie pertinente (copie
profonde / de surface).
• économie : de temps d'exécution/espace plus importants.
• sécurité : moins de risque prolifération de zones non
libérées
La fonction appelante sait exactement dans quelles
conditions la copie est nécessaire, en fonction de ses propres
traitements, et peut la réaliser elle même avant l'appel.
mardi 20 novembre 12
103
Distinguer les fonctions faisant
des copies si nécessaire
mardi 20 novembre 12
104
Aspects Humains
mardi 20 novembre 12
105
Eviter de généraliser et
d'abstraire
• 1 le goût de résoudre un "problème" difficile,
• 2 le goût d'une certaine esthétique des
programmes,
• 3 la croyance que l'on se protège d'avance contre
des évolutions futures du besoin client.
• 4 la croyance que le même programme puisse
servir dans un autre projet
• 5 l'impression d'améliorer la qualité du logiciel
mardi 20 novembre 12
106
Savoir déboguer
• les programmes corrects mais qui implantent un
algorithme faux,
• les programmes qui implanteraient un
algorithme correct, s'ils ne contenaient des
erreurs.
• la combinaison des deux
mardi 20 novembre 12
107
Aspects psychologiques du
debug
• décontraction (éviter le blocage)"
• effort calme et patient de mémoire :
• passer les symboles et les programmes en revue, en
répétant mentalement leur rôle.
• demander l'aide d'une personne extérieure :
• lui expliquer le rôle des éléments du programme
fautif et la logique générale du programme suffira
souvent à lui permettre de trouver l'erreur. Souvent, le
fait d'expliquer permet au programmeur de faire
effectivement l'effort calme et patient en question ci
dessus, et de trouver l'erreur lui même.
mardi 20 novembre 12
108
Aspects statistiques
• Lorsqu'un programme "plante", les instructions
erronées sont en général très proches de l'endroit
où le programme s'arrête effectivement.
• L'utilisation des invariants a pour but de cerner le
point d'erreur au plus près
mardi 20 novembre 12
109
Isoler les conditions
d'apparition du bug
• Pour réduire les conditions d'erreur à leur plus
simple expression il suffit en général de
supprimer des portions du programme de façon
itérative tant que l'erreur est maintenue.
• Il est en général inutile de chercher la cause de
l'erreur tant qu'on n'a pas procédé à cette
réduction à la séquence minimale.
mardi 20 novembre 12
110
savoir procéder par différences
élémentaires
• Après avoir isolé les conditions du bug, faire
varier de manière indépendante tous les
paramètres du programme, et considérer que
ceux qui ne changent pas le comportement du
programme ne sont pas concernés.
mardi 20 novembre 12
111
Principes de
Capitalisation
Capitaliser=Réutiliser
mardi 20 novembre 12
112
Spécifier
• Les besoins auxquels répond un module (une
gestion de liste par exemple) doivent être
clairement définis.
• Pour garantir leur réutilisation ils doivent être
universels, donc indépendants de toute spécificité
applicative.
• Si de telles spécificités existent cependant, elles
sont décrites à part en s'appuyant sur le noyau
fondamental.
mardi 20 novembre 12
113
Concevoir
• Pour garantir la réutilisation, la conception doit
prévoir une interface de portabilité
(indépendance des architectures matérielle et
système), et doit obéir aux différents principes
généraux, dont celui de l'utilisateur parfait.
mardi 20 novembre 12
114
Programmer
• Les outils de base font l'objet de modules indépendants,
groupés dans une ou plusieurs bibliothèques.
• Ces bibliothèques sont accessibles à l'ensemble des
membres de l'équipe, et font l'objet d'une rigoureuse
gestion de versions.
• Les programmes eux mêmes sont protégés des
malversations par des contrôles d'invariants dans leur
version de développement.
• On ne doit jamais conduire un utilisateur (programmeur)
à utiliser un débugger pour naviguer dans des sources
inconnus à la recherche de l'origine d'une erreur.
mardi 20 novembre 12
115
Documenter
• De bons documents de spécification et de
conception constituent la documentation de base.
• Il faut les compléter par un "manuel de
l'utilisateur" qui décrit notamment des cas
d'utilisation détaillés et des exemples.
• Un manuel de référence si possible généré
automatiquement est nécessaire
• Le code est documenté en interne par ses
invariants
mardi 20 novembre 12
116
Livrer
• Un module doit être disponible aux développeurs
sous deux versions.
• La première, de développement, effectue tous les
tests de domaines nécessaires par des contrôles
d'invariants, et garantit de ne jamais "planter"
sans dire pourquoi.
• La seconde est une version de déploiement
débarrassée des contrôles d'invariants
mardi 20 novembre 12
117
Fin du chapitre
• Questions?
mardi 20 novembre 12
118