Génie Logiciel Cours 4: produire du bon code
Transcription
Génie Logiciel Cours 4: produire du bon code
Génie Logiciel Cours 4: produire du bon code David Baelde [email protected] MPRI 29 novembre 2013 Le problème C’est quoi du bon code ? Critères Le problème C’est quoi du bon code ? Critères I Pas de crash, fuite mémoire, comportement non défini, etc. I Respect de la spécification fonctionnelle Le problème C’est quoi du bon code ? Critères I Pas de crash, fuite mémoire, comportement non défini, etc. I Respect de la spécification fonctionnelle I Efficacité : temps, espace, réactivité I Facilité à corriger et adapter Le problème C’est quoi du bon code ? Critères I Pas de crash, fuite mémoire, comportement non défini, etc. I Respect de la spécification fonctionnelle I Efficacité : temps, espace, réactivité I Facilité à corriger et adapter Debugging is twice as hard as writing the code in the first place. Therefore, if you write the code as cleverly as possible, you are, by definition, not smart enough to debug it. — Brian Kernighan Différentes pistes Méthodologie I Limiter le couplage, favoriser la purité. I Tester systématiquement, d’abord en isolation. Différentes pistes Méthodologie I Limiter le couplage, favoriser la purité. I Tester systématiquement, d’abord en isolation. I Relire et faire relire le code, systématiquement. Différentes pistes Méthodologie I Limiter le couplage, favoriser la purité. I Tester systématiquement, d’abord en isolation. I Relire et faire relire le code, systématiquement. I Conseils généraux du type “réfléchissez”. . . Différentes pistes Méthodologie I Limiter le couplage, favoriser la purité. I Tester systématiquement, d’abord en isolation. I Relire et faire relire le code, systématiquement. I Conseils généraux du type “réfléchissez”. . . Aujourd’hui Quelques outils et techniques utilisables en pratique : 1. Garanties statiques 2. Outillage de l’exécution Garanties statiques Éviter le pire Sans faire tourner le code on peut/doit déja faire plein de choses Choisir un langage discipliné I Déclarations de variables : éviter les typos I Typage statique : garantir des invariants simple plus de types plus d’invariants exprimables I Utiliser des énumérations plutôt que des nombres magiques ! Éviter le pire Sans faire tourner le code on peut/doit déja faire plein de choses Choisir un langage discipliné I Déclarations de variables : éviter les typos I Typage statique : garantir des invariants simple plus de types plus d’invariants exprimables I Utiliser des énumérations plutôt que des nombres magiques ! Profiter au maximum du compilateur Même sur un langage avec typage fort et statique, le compilateur n’est pas forcément très contraignant par défaut. Recommandé en C++ : -pedantic, -Wall, -Werror, -Wextra, etc. En plus du compilateur Deux outils faciles à utiliser I I Lint, e.g., cpplint : vérifier le respect de conventions et bonnes pratiques (Google) Recherche d’erreurs simples communes : memory leaks, unchecked error, trivial test, library misuse, etc. I I cppcheck (cf. page Foung bugs sur leur wiki) Clang static analyzer, PVS studio, etc. En préparant ce cours, avec ces outils et grep j’ai trouvé des bugs dans GTA et trois logiciels à moi (C++ et OCaml) Méthodes formelles De la science. . . Model-checking, vérification déductive, interprétation abstraite, génération de code certifié, etc. . . . aux outils mûrs I I Why, Frama-C, etc. Chez Microsoft I I Outils MSR : SLAM, Boogie, Z3. . . Tout code écrit passe par des outils de vérification. . . . pas forcément complets ni corrects ! I I I correct : remonte tous les bugs (et peut-être de faux positifs) complet : remonte de vrais bugs (mais pas forcément tous) Sparse : check annotations in the Linux kernel Et si on ne peut pas / ne sait pas utiliser ces outils ? Programmation par contrats Une “métaphore” pour la logique de Hoare : pre-conditions, post-conditions, invariants, etc. Une méthodologie de conception : design by contract Support I Dans le langage : Eiffel, SpeC# I Extension (commentaires) : JML Outils I (Preuve de programme) I Génération de documentation I Génération de tests unitaires I Vérifications à runtime Outillage de l’exécution Assertions À défaut de formellement prouver la spécification, on peut souvent l’exécuter. I Détection d’anomalies au plus tôt. I Une forme de commentaire actif. Assertions À défaut de formellement prouver la spécification, on peut souvent l’exécuter. I Détection d’anomalies au plus tôt. I Une forme de commentaire actif. La fonction assert Prend un booléen et lève une erreur s’il est faux. let add ?(needs_check=true) x rules kb = assert (needs_check || not (mem_equiv x kb)) ; if not (needs_check && mem_equiv x kb) then add (fresh_statement x) kb Souvent prédefinie, avec un moyen d’effacer l’assertion : ocamlc -noassert ..., g++ -DNDEBUG ..., etc. Assertions — Bon usage Impératifs I Si assert lève une exception, attention à ne pas la récupérer let main () = try ... with _ -> eprintf "Oops!\n" ; main () I L’effacement des assertion ne doit pas affecter le comportement du programme Assertions — Bon usage Impératifs I Si assert lève une exception, attention à ne pas la récupérer let main () = try ... with _ -> eprintf "Oops!\n" ; main () I L’effacement des assertion ne doit pas affecter le comportement du programme Au cas par cas I Quand est-ce qu’une assertion est trop coûteuse ? Attention à l’optimisation prématurée, souvent non justifiée Envisager un système d’assertions multi-niveaux I Faut-il distribuer un logiciel avec les assertions désactivées ? Plutôt non : profiter au maximum de tests précis. Envisager de les changer en gros avertissements non fatals. Autres outillages Malgré tous ces efforts, il restera toujours des bugs. Une fois qu’on a un bug, il faut : reproduire ; comprendre et minimiser ; corriger. Tracer Un système de log enrichit le traditionnel debug au printf : I Disponible chez l’utilisateur, configurable sans recompiler I Sauvegarde dans un fichier à joindre aux rapports de bug I Messages datés, taggés, avec indication de priorité : erreur, avertissement, information, debug I Penser aux infos utiles au debug : version, plugins, plateforme Si les logs deviennent ingérables, inventer son propre outil : analyse statistique, graphiques, graphes, inspection à chaud, etc. Conclusion À retenir I Ecrire du code facile à comprendre et à adapter I Systématiquement éviter les erreurs simples I Provoquer les bugs, le plus tôt possible Séances suivantes I Test I Débuguage et d’analyse de l’exécution