TD08 : Livraison du Projet
L'objectif de ce TD est de produire une version de votre projet dans l'objectif de la livrer à un client : vos enseignants, mais aussi d'autres étudiants qui vont devoir évaluer votre travail ! Réciproquement, vous allez devoir vous-même évaluer le travail d'une autre équipe.
Commençons par lister les objectifs généraux qui définissent un excellent projet :
- rendre un code fonctionnel, c'est-à-dire sans bugs, ni fuite mémoire ;
- rendre un code interopérable, qui respecte rigoureusement les interfaces définies ;
- rendre un code suffisamment testé, afin d'éviter toute regression fonctionnelle lors de son cycle de vie ;
- rendre du code propre et suffisamment bien commenté, afin de faciliter sa prise en main par de nouveaux développeurs, sa maintenance et son évolution vers de nouvelles fonctionnalités.
Afin de réaliser au mieux les objectifs de cette évaluation croisée, nous vous proposons quelques exercices préliminaires, qui vous servirons à améliorer votre code, mais aussi à évaluer la qualité d'un autre projet. Voici le questionnaire qui va nous servir de grille d'évaluation.
Exercice 0 : débogage intégré à VS Code
Afin d'illustrer notre propos, nous allons considérer la bibliothèque queue déjà étudiée.
- Récupérez ce projet sur GitHub et placez-vous dans la branche dans la branche
bugtofix :
git switch bugtofix
. - Compilez ce projet avec CMake dans le sous-répertoire
build
. - Lancez l'exécution des tests :
make test
. Vous devez constater que le testtest_queue_pop_tail
échoue ! - Consultez le fichier
CMakeLists.txt
pour trouver la commande à lancer dans un terminal pour reproduire ce bug. - Vérifiez que votre programme se compile bien avec le flag
-g
, nécessaire au bon fonctionnement du débogueur.
Vous avez fait le plus dur ou presque, c'est-à-dire isoler le bug avec un test !
Il faut maintenant comprendre plus en détail le problème pour le corriger. Dans
cette situation, il convient d'utiliser un débugueur comme gdb
en ligne de
commande. Il est également possible de lancer une session de debug graphique &
interactive dans VS Code, ce qui est plus confortable...
- Pour ce faire, il faut préparer un fichier launch.json
dans le sous-répertoire
.vscode/
. Récupérez ce fichier et copiez dans le sous-répertoire.vscode/
. - Au CREMI, vous pouvez générer automatiquement le fichier
launch.json
pour un test donné en utilisant le scriptmklaunch.sh
à la racine du projet (là où se trouve le fichierCMakeLists.txt
) :
$ cd queue
$ /net/ens/vscode/debug/mklaunch.sh test_queue_pop_tail
- Pour lancer la session de debug dans VS Code, il suffit de taper sur la touche
F5
. - Identifiez la fonction et la ligne de code qui provoque l'erreur... Il n'est pas demandé de la corriger.
- Relancez une session de debug en mettant un breakpoint à l'entrée de cette fonction. Puis avancez pas à pas, en regardant l'évolution des variables en mémoire.
- Pensez à utiliser cet outil puissant par la suite !
Exercice 1 : couverture de code
Pour qu'un jeu de tests soit efficace, il faut qu'il soit le plus exhaustif possible. On peut alors se poser la question suivante : quelle est la proportion de code source qui est exécuté lorsque je lance mon jeu de tests ? C'est précisément ce que l'on appelle en génie logiciel la couverture de code ou code coverage en anglais.
L'outil gcov intégré à gcc et cmake permet de répondre simplement à cette question. Afin d'illustrer notre propos, nous allons mettre en oeuvre cet outil sur l'exemple de la bibliothèque queue déjà étudiée.
- A l'aide de Git, récupérez la dernière version de queue et placez-vous
dans la branche coverage :
git switch coverage
. - Dans le fichier
CMakeLists.txt
, ajoutez l'option de compilation--coverage
et vérifiez que vous avez la ligneinclude(CTest)
en plus deenable_testing()
. - Recompilez le projet dans le sous-répertoire
build
. Vérifiez que l'option--coverage
est bien utilisée lors de la compilation, en tapant la commandemake VERBOSE=ON
. - Afin de calculer la couverture de code, il faut obligatoirement commencer
par lancer l'exécution des tests en faisant
make ExperimentalTest
(oumake test
). Puis, dans un deuxième temps, lancez la commandemake ExperimentalCoverage
pour afficher la couverture de code. Cela devrait afficher le résultat ci-dessous (LOC = Lines of Code). Interprétez-le.
Covered LOC: 211
Not covered LOC: 25
Total LOC: 236
Percentage Coverage: 89.41%
- Dans le sous-répertoire
Testing/CoverageInfo
, vous trouverez les résultats détaillés sur la couverture de votre code. Par exemple dansqueue.c.gcda##queue.c.gcov
, vous avez l'analyse du fichierqueue.c
, dont voici un extrait ci-dessous. La colonne de gauche indique le nombre de fois, où chaque ligne de code est exécutée. En particulier,#####
indique une ligne de code qui n'est jamais exécutée et-
signifie que cette ligne est ignorée car elle ne contient pas d'instructions.
-: 150:
36: 151:void queue_clear(queue *q)
-: 152:{
36*: 153: assert(q);
36: 154: element_t *e = q->head;
36: 155: while (e)
-: 156: {
#####: 157: element_t *tmp = e;
#####: 158: e = e->next;
#####: 159: free(tmp);
-: 160: }
36: 161: q->head = q->tail = NULL;
36: 162: q->length = 0;
36: 163:}
-: 164:
- Que se passerait-il si il y avait un bug dans les lignes 157-159 ? Que faudrait-il faire pour remédier à ce problème ?
- En analysant la couverture de code de
queue.c
, trouvez une fonction qui n'est pas du tout testée... Danstest_queue.c
, corrigez le problème en décommentant le test correspondant. Vérifiez alors que vous arrivez à améliorer la couverture de code. Notez qu'il n'est pas vraiment possible d'atteindre une couverture de 100%, car nous ne testons pas en général les cas d'erreur, comme par exemple le passage d'arguments invalides ! - Analysez la couverture de code dans votre projet et complétez vos tests ! Pour
chaque ligne
#####
qui n'est pas couverte par vos tests, posez-vous les questions suivantes. Est-ce que ce code est atteignable ? Si c'est du code mort, il faut peut-être le supprimer, sinon c'est qu'il faut certainement compléter vos tests.
Dans VSCode, vous pouvez installer l'extension
Gcov Viewer
qui permet de visualiser la couverture de code (Ctrl+Shift+P Gcov Viewer: Show
).
Exercice 2 : détecter une fuite mémoire
L'outil valgrind (utilisé par cmake) permet de détecter simplement des fuites mémoire (ou memory leak en anglais). Afin d'illustrer notre propos, nous allons mettre en oeuvre cet outil sur l'exemple de la bibliothèque queue déjà étudiée.
- A l'aide de Git, récupérez la dernière version de queue et placez-vous
dans la branche memcheck :
git switch memcheck
. - Dans le fichier
CMakeLists.txt
, vérifiez que vous avez déjà la ligneinclude(CTest)
et recompilez le projet dans le sous-répertoirebuild
. - Lancez la commande
make ExperimentalMemCheck
, qui exécutent les tests à travers l'outil valgrind pour détecter de possibles fuites mémoire et afficher le bilan ci-dessous :
-- Processing memory checking output:
5/8 MemCheck: #5: test_queue_pop_tail .............. Defects: 1
6/8 MemCheck: #6: test_queue_length ................ Defects: 1
MemCheck log files can be found here: ( * corresponds to test number)
Testing/Temporary/MemoryChecker.*.log
Memory checking results:
Memory Leak - 2
- En fonction des tests qui échouent, recherchez dans le code
queue.c
une fuite mémoire... Afin d'obtenir une analyse plus détaillée, il est toujours possible de lancer manuellement le test avec la commandevalgrind
et l'option--leak-check=full
. Par exemple :
$ valgrind --leak-check=full ./test_queue pop_tail
Memcheck, a memory error detector
Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
Using Valgrind-3.16.1 and LibVEX; rerun with -h for copyright info
Command: ./test_queue pop_tail
HEAP SUMMARY:
in use at exit: 2,400 bytes in 100 blocks
total heap usage: 201 allocs, 101 frees, 2,824 bytes allocated
2,400 (24 direct, 2,376 indirect) bytes in 1 blocks are definitely lost in loss record 2 of 2
at 0x483C7F3: malloc (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
by 0x10A1C6: queue_push_head (queue.c:46)
by 0x109793: test_pop_tail (test_queue.c:112)
by 0x109FF5: main (test_queue.c:223)
LEAK SUMMARY:
definitely lost: 24 bytes in 1 blocks
indirectly lost: 2,376 bytes in 99 blocks
possibly lost: 0 bytes in 0 blocks
still reachable: 0 bytes in 0 blocks
suppressed: 0 bytes in 0 blocks
ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)
- En résumé, on détecte une fuite mémoire correspondant à une allocation
dynamique avec
malloc()
à la lignequeue.c:46
, qui n'est a priori pas libérée par unfree()
. Après une enquête rapide, trouvez l'origine du problème et corrigez la ligne problématique dansqueue.c
. Vérifiez qu'il n'y a plus de fuite mémoire avec valgrind. - Détectez les éventuelles fuites mémoire dans votre projet et corrigez-les !
Exercice 3 : interopérabilité
En génie logiciel, l’interopérabilité est la capacité d'un système, dont les interfaces sont clairement spécifiées, à fonctionner correctement avec d’autres systèmes existants ou futurs.
Dans le contexte de notre projet, cela consiste principalement à respecter
rigoureusement la séparation imposée par les interfaces de la bibliothèque
game : game.h
, game_aux.h
et game_ext.h
. En pratique, les exécutables du
projet (tests ou game_text
) doivent se limiter strictement aux fonctions
spécifiées par ces interfaces et ne pas avoir d'autres dépendances. Cela
garantit que votre bibliothèque est réutilisable dans d'autres projets, et à
l'inverse que vos exécutables peuvent utiliser d'autres bibliothèques.
- Vérifiez que vos exécutables (
game_text
et tests) compilent et fonctionnent correctement avec la bibliothèque libgame.a fournies par vos enseignants. Si votre exécutable est correctement liée à cette bibliothèque, une mentionCopyright
doit s'afficher dans votre terminal au lancement du jeu. Sinon corrigez le problème. - A l'inverse, vérifiez que l'exécutable game_text.o peut se
lier à votre bibliothèque game sans problème. De même, une mention
Copyright
doit s'afficher dans votre terminal au lancement du jeu. Sinon corrigez le problème. - Dans le contexte de l'évaluation croisée, vous allez devoir vérifier que le projet d'une autre équipe est interopérable avec votre propre projet, comme illustré sur la figure ci-dessous.
Nota Bene : Pour tester l'interopérabilité de libgame.a
, il suffit de
compiler le projet cible et de remplacer directement dans le répertoire build
le fichier libgame.a
par une autre version avant de recompiler les exécutables
avec la commande make
. Attention, de ne pas faire un make clean
avant, ce
qui aurait pour effet de supprimer la nouvelle version de libgame.a
!
Exercice 4 : du code propre
- En guise d'introduction, regardez la vidéo Commenter et nettoyer son code.
- Appliquez au mieux ces principes à votre projet, afin de livrer un code qui soit le plus propre possible : commentaires, indentation, nommage cohérent des variables et des fonctions, pas de constantes magiques, fonctions de longueur raisonnable, pas de code mort ou de duplication inutile, ...
Exercice 5 : livraison du projet et évaluation croisée
Afin d'évaluer chaque projet, nous nous appuyons sur ce questionnaire. Lisez-le attentivement afin d'améliorer votre propre projet avant sa livraison. Appuyez-vous notamment sur les exercices préliminaires de ce TD.
Ce travail se déroule en deux étapes, bien séparées :
- Livraison (travail en équipe) : Dans un premier temps, vous utiliserez
l'activité Moodle VPL Livraison pour effectuer le rendu final de votre
projet, incluant la V1, les extensions de la V2, les tests et le programme
game_text
. Votre dépôt doit contenir à sa racine un fichierCMakeLists.txt
prêt à compiler votre code source sans erreurs, un fichierREADME.md
bien documenté. En outre, il ne doit pas contenir de fichiers superflux ou temporaires. - Evaluation Croisée (travail individuel) : Dans un deuxième temps, chaque
étudiant va se voir affecté l'évaluation d'un autre projet, sous forme d'une
archive
.zip
générée automatiquement à partir du rendu effectué à l'étape précédente. Afin d'évaluer ce projet, il vous faudra télécharger son archive.zip
sur Moodle, le compiler, le tester et rendre dans Moodle vos réponses au questionnaire fourni. Notez que vous serez vous-même évalué sur la pertinence de vos réponses à ce questionnaire.
Les modalités de rendu de ces activités sont précisés sur Moodle.