Code Complete

478 vues

Publié le

Tout comme on fait attention au style d'écriture utilisé lorsque l'on rédige un livre, en plus d'appliquer les règles d'orthographe et de grammaire, il faut également appliquer des règles stylistiques lorsqu'on rédige du code.

Cette conférence présente plusieurs aspects à prendre en compte pour rédiger du code de qualité, allant de la structure globale d'un programme à la mise en page de son code, en passant par les noms des variables.

Publié dans : Ingénierie
0 commentaire
1 j’aime
Statistiques
Remarques
  • Soyez le premier à commenter

Aucun téléchargement
Vues
Nombre de vues
478
Sur SlideShare
0
Issues des intégrations
0
Intégrations
4
Actions
Partages
0
Téléchargements
7
Commentaires
0
J’aime
1
Intégrations 0
Aucune incorporation

Aucune remarque pour cette diapositive

Code Complete

  1. 1. Code Complete Sébastien Combéfis Lundi 29 février 2016
  2. 2. Ce(tte) œuvre est mise à disposition selon les termes de la Licence Creative Commons Attribution – Pas d’Utilisation Commerciale – Pas de Modification 4.0 International.
  3. 3. Contexte W. Strunk et E. B. White 1918 B. W. Kernighan et P. J. Plauger 1974 3
  4. 4. Qualité de code 4
  5. 5. “Always code as if the guy who ends up maintaining your code will be a violent psychopath who knows where you live.” — Martin Golding “Always code as if the guy who ends up maintaining your code will be a violent psychopath who knows where you live.” — Martin Golding
  6. 6. Cacher l’information Deux catégories de secrets Cacher la complexité pour le développeur Cacher les sources de changement pour faciliter les modifs Barrière au masquage d’information Distribution excessive de l’information Dépendance circulaire Confondre variable de classe avec variables globales 6
  7. 7. Identifier le changement Importance d’identifier le changement pour l’isoler 1 Identifier les éléments qui pourraient changer 2 Séparer les éléments identifiés dans une classe 3 Isoler les éléments identifiés du reste Exemples communs qui peuvent changer Règles business (facturation, taxe...) Dépendances hardware Entrée/sortie (format de fichiers produits) Fonctionnalités non standards des langages Zones avec des constructions difficiles Variable statuts 7
  8. 8. Couplage Il faut maintenir un couplage le plus faible possible Critères de couplage Minimiser le nombre de connexions vers d’autres modules Rendre les connexions visibles Pouvoir changer les connexions par flexibilité Types de couplage Simple-data-parameter (passage de paramètre primitif) Simple-object (un objet instancie un autre objet) Object-parameter Semantic 8
  9. 9. Code de qualité Focus sur la programmation orientée objet Analyse top-down Depuis la classe jusqu’aux instructions Classe Méthode Instruction 9
  10. 10. Trouver les objets du monde réel Identifier l’objet et ses attributs Déterminer ce qui peut être fait avec l’objet Identifier ce que l’objet peut faire à d’autre objets Déterminer ce qui sera visible de l’objet Définir l’interface publique de l’objet 10
  11. 11. Programmer avec des classes Abstract Data Type ADT Cacher les détails d’implémentation Rendre les changements indépendants du reste du programme Le programme est auto-documenté Le programme manipule des entités qui modélisent le monde réel 11
  12. 12. Manipuler les objets du monde getFuelLevel isOnGround startEngine startAutopilot
  13. 13. Abstraction Créer une bonne abstraction de l’objet représenté S’assurer que les détails d’implémentation soient bien cachés L’abstraction doit former un tout cohérent et consistent Le niveau d’abstraction doit être consistent Abstraction — “Le fait de voir une opération complexe sous une forme simplifiée” 13
  14. 14. Encapsulation Minimiser l’accès aux classes et à leurs membres Ne pas exposer les données de la classe Ne pas exposer des détails d’implémentation Diminuer au maximum le couplage entre classes public class GradeReport { private Grade[] grades; public double getGrade (String courseName) { /∗ ... ∗/ } private static class Grade { /∗ ... ∗/ } } 14
  15. 15. Composition ou héritage ? I HAS-A Une classe se compose à partir d’autres 7 ± 2 (composants) Surveillez le couplage IS-A Une classe est une spécialisation d’une autre 6 (niveaux d’héritage) Surveillez l’encapsulation Liskov Substitution Principle (LSP) Si q(x) est une propriété démontrable pour tout objet x de type T, Alors q(y) est vraie pour tout objet y de type S tel que S est un sous-type de T. 15
  16. 16. Composition ou héritage ? II Vehicle Car Wheel is-a has-a 16
  17. 17. Membres d’une classe Limiter le nombre de méthodes Limiter les appels de méthodes directs et indirects En général : limiter la collaboration avec d’autres classes Law of Demeter (LoD) Une méthode M d’un objet O ne peut invoquer que : 1 ses propres méthodes ; 2 les méthodes de ses paramètres ; 3 les méthodes des objets qu’elle instance ; 4 et les méthodes de ses objets composants. 17
  18. 18. Constructeurs Initialiser toutes les variables d’instance Interdire la création d’instances avec un constructeur privé Éviter les shallow copies des paramètres public class BookStore { private Books[] books; public BookStore (Books[] books) { this.books = books; } } 18
  19. 19. Deep or shallow copies ? public class Exam { private Course course; private Student[] students; public Exam (Course course, Student[] students) { this.course = course; this.students = students; } } public class Test { public static void main (String[] args) { Student[] students = /∗ ... ∗/ ; Exam exam = new Exam (/∗ ... ∗/, students); Arrays.fill (students, null); } } 19
  20. 20. Pourquoi une classe ? Modéliser un objet du monde réel Modéliser des objets abstraits Réduire ou isoler la complexité Limiter les impacts lors de modifications Cacher les données et détails d’implémentation Faciliter la réutilisation de code 20
  21. 21. Avoid God classes also known as The Blob Toute puissante et qui sait tout Passe son temps à appeler des get et set
  22. 22. Classes à éviter Éviter les classes God Éliminer les classes hors sujet Classes avec seulement des données Éviter les classes dont les noms sont des verbes Classes avec seulement des comportements 22
  23. 23. Programmer avec des routines Réduire la complexité Introduit des abstractions intermédiaire et compréhensibles Éviter la duplication de code Faciliter la réutilisation de code 23
  24. 24. Pourquoi rassembler des instructions ? Cohésion fonctionnelle Une routine = une opération Cohésion séquentielle Séquence d’instructions qui partagent des données Cohésion communicationnelle Opérations qui utilisent la même donnée Cohésion temporelle Opérations qui doivent avoir lieu en même temps 24
  25. 25. Choisir le bon nom Décrire ce que fait la routine Éviter les verbes vagues : process, handleOutput... Ne pas différencier rien que par un numéro : test1, test2... Ne pas hésiter sur la longueur du nom Utiliser les opposés à bon escient : get/put, start/stop... Fonction : décrire la valeur de retour Procédure : verbe fort + sujet pour décrire l’action 25
  26. 26. Longueur d’une routine Pas de convention globalement acceptée Doit tenir sur un écran ou une/deux page/s (50–150 lignes) Convention NASA pour développer un code critique 60 lignes de code maximum par routine 26
  27. 27. Paramètres d’une routine 39% des erreurs viennent de l’interface entre routines Cette interface se fait lors des appels de routines Bonnes pratiques par rapport aux paramètres Ordre des paramètres : input/modify/output Même ordre lorsque routines avec les mêmes paramètres Utiliser tous les paramètres Ne pas utiliser les paramètres comme variable de travail Documenter les hypothèses sur les paramètres Limiter le nombre de paramètres (environ 7) 27
  28. 28. Protégez-vous ! Données provenant de sources externes Valeurs des paramètres des routines
  29. 29. Gestion des erreurs ou assertion ? Gestion des erreurs À utiliser pour des situations particulières qui pourraient se produire Assertion À utiliser pour des situations qui ne surviendront jamais public Book getBook (int bookid) { for (int i = 0; i < books.length; i++) { if (books[i].getId() == bookid) { return books[i]; } } assert false; return null; } 29
  30. 30. Assertion Le code doit rester fonctionnel sans les assertions Vérification des préconditions et postconditions Peut être vu comme des commentaires exécutables 30
  31. 31. Gestion des erreurs Renvoyer une valeur neutre Passer la donnée erronée Renvoyer la même valeur que lors du dernier appel Afficher un message d’erreur Mécanisme d’exception pour communiquer des erreurs Correctness <> Robustness 31
  32. 32. One variable = One purposeOne variable = One purpose
  33. 33. Déclaration Initialisation lors de la déclaration ... dans le constructeur pour les variables d’instance Déclaration le plus proche de l’utilisation Utilisez les constantes 33
  34. 34. Span et durée de vie Le « span » mesure l’espacement de l’utilisation de la variable La durée de vie mesure le nombre d’instructions pour lesquelles la variable existe public void test() { int a = 0; int b = 0; int c = 0; b = a + 1; b = b / c; } Variable b Average span : (1 + 0)/2 = 0.5 Live time : 4 (les deux valeurs sont à minimiser) 34
  35. 35. Minimiser la portée Initialiser les variables utilisée dans une boucle juste avant Ne pas retarder l’initialisation d’une variable Grouper les instructions liées (avec les mêmes variables) Séparer les groupes d’instructions liées en routines Toujours commencer avec la visibilité la plus faible 35
  36. 36. Variable Le nom décrit contenu de la variable et la documente Longueur optimale entre 9 et 15 caractères Une variable utilisée pour une seule raison Éviter les variables avec plusieurs significations selon la valeur S’assurer que toutes les variables sont utilisées 36
  37. 37. Choisir les noms Noms avec signification proche : input et inputVal Noms similaires : clientRec et clientRep Éviter les nombres : total1 et total2 Attention à l’orthographe ! Éviter de mélanger les langues Éviter des caractères difficiles à lire : char1 et chartl, cOnf et c0nf, GREAT et 6REAT, tex2html et texZhtml... 37
  38. 38. Nom pour types de données spécifiques Compteur des boucles i, j, k (sauf si utilisée hors boucle) Sauf pour les longues boucles, où un nom parlant est mieux Ne pas mettre flag dans le nom des variables de statut Les variables temporaires sont à éviter (temp...) Nommer les variables booléennes (done, error, found, ok, success...) avec nom qui implique true ou false 38
  39. 39. Data types
  40. 40. Nombre (1) Éviter les nombres magiques Hardcoder les valeurs 0 et 1 ne pose pas problème Anticiper les divisions par zéro Rendre les conversions de type explicite Éviter les comparaisons de types différents 40
  41. 41. Nombre (2) Nombre entier Vérifier les divisions par zéro Vérifier les dépassements de capacité Diviser avant de multiplier (1e6 * 1e6 / 1e6) Nombre flottant Éviter addition et soustraction de nombres de magnitudes = Éviter les comparaisons pour l’égalité Anticiper les erreurs d’arrondi 41
  42. 42. Chaine de caractères Éviter les caractères et chaines magiques Attention à l’accès par indice avec les méthodes utilisées Attention au support ou non d’Unicode Penser à la politique d’internationalisation de l’application 42
  43. 43. Autres types Booléen Utiliser les booléens pour documenter son programme En nommant des expressions booléennes pour les conditions Simplifier les tests complexes avec des booléens Tableau/Liste S’assurer que les indices restent dans les bornes Attention aux indices lorsque plusieurs dimensions 43
  44. 44. Writing programs is like writing books
  45. 45. Code séquentiel Respecter l’ordre lorsqu’il a de l’importance Rendre visible les dépendances (noms des routines, arguments) Grouper les instructions de manière logique 45
  46. 46. Instructions conditionnelles Traiter les cas normaux d’abord (avec le if) ensuite les cas d’erreur (avec le else) Faire attention à bien utiliser < ou <= Simplifier les conditions complexes par un appel de fonction Ordonner les cas en commençant par le plus fréquent 46
  47. 47. Instructions répétitives (1) Boucles while, for et foreach Un seul point d’entrée par boucle Code d’initialisation juste avant la boucle Boucle infinie avec while(true){} Éviter les boucles vides Mise à jour des variables de contrôle en début ou fin du corps Une boucle = une fonction 47
  48. 48. Instructions répétitives (2) S’assurer que la boucle se termine et rendre la condition de terminaison claire et limpide Ne pas faire le singe en changeant les variables de contrôle pour quitter la boucle Ne pas dépendre de la valeur des variables de contrôle après la boucle Utiliser les break, mais avec modération 48
  49. 49. Imbriquer des boucles Attention aux noms des variables de contrôle Limiter la portée des variables de contrôle à la boucle Au grand maximum trois niveaux d’imbrication de boucles On doit pouvoir lire la boucle de manière globale 49
  50. 50. Expressions booléennes Comparer implicitement des booléens avec true et false Casser des conditions trop complexes en utilisant des variables booléennes intermédiaires ou dans une routine Inverser la logique pour avoir la condition du if positive Simplifier les expression booléennes avec la loi de De Morgan ! (A || B) ≡ ( !A) && ( !B) ! (A && B) ≡ ( !A) || ( !B) 50
  51. 51. Fundamental Theorem of Formatting “A good visual layout shows the logical structure of a program” “Any fool can write code that a computer can understand. Good programmers write code that humans can understand.” — Martin Fowler “Any fool can write code that a computer can understand. Good programmers write code that humans can understand.” — Martin Fowler
  52. 52. Bon layout Représenter la structure logique du code de manière précise et consistante Augmenter la lisibilité Supporter et faciliter les modifications En utilisant les blancs pour regrouper, et pour indenter et les parenthèses pour clarifier les expressions 52
  53. 53. Quelques règles de layout Une ligne de code ne devrait pas dépasser 80 caractères Une déclaration de variable par ligne Dans une classe : commentaire d’entête, données, méthodes public, protected puis private 53
  54. 54. Les commentaires Répétition du code Explication du code Marqueurs dans le code Résumé du code (focus sur le pourquoi, et pas sur le comment) Explication de l’intention du code (niveau problème et pas solution) Information additionnelle non présente dans le code “Good code is its own best documentation.” — Steve McConnell 54
  55. 55. Do not comment tricky code, rewrite it!Do not comment tricky code, rewrite it!
  56. 56. 56
  57. 57. 57
  58. 58. En résumé Réduire la complexité Écrire ses programmes pour des humains, pas pour la machine Consistance et cohérence Garder les éléments proches de leurs utilisations Penser et coder au niveau du problème, pas de la solution 58
  59. 59. À suivre http://geek-and-poke.com/ http://www.codinghorror.com/blog/ 59
  60. 60. Livres de référence I ISBN 978-0-735-61967-8 ISBN 978-0-132-35088-4 ISBN 978-0-596-51004-6 60
  61. 61. Livres de référence II ISBN 978-0-201-61622-4 ISBN 978-0-321-35668-0 ISBN 978-0-201-48567-7 61
  62. 62. Crédits https://www.flickr.com/photos/toolmantim/2887927385 https://www.flickr.com/photos/smitty/2245445147 http://www.flickr.com/photos/tetezinharomana/7152072635/ http://www.flickr.com/photos/jetstarairways/6769120131/ http://www.flickr.com/photos/47104521@N08/4332849715/ http://www.flickr.com/photos/dunechaser/2936384313/ http://www.flickr.com/photos/sillydog/287354869/ https://www.flickr.com/photos/small_realm/15375289074 http://www.flickr.com/photos/j1x4r/4313734090/ http://www.flickr.com/photos/focx/5485671820/ http://www.flickr.com/photos/cyberslayer/952153409/ http://geek-and-poke.com/geekandpoke/2014/7/17/simply-explained Photos des livres depuis Amazon 62

×