Clean Code
Clément Defaux
Redouane Boutraa
Sébastien Laoût
Qui sommes-nous ?
2
Sébastien Laoût
Développeur full-stack (Java / TypeScript) depuis 13 ans
Principalement sur de l'e-commerce
Actuellement Tech Leach chez Auchan
Chez Ubik Ingénierie depuis 9 ans
Clément Defaux
Développeur Java & Spring Boot (+ de la CI et du front)�A travaillé chez Adeo / Leroy Merlin�Actuellement chez Decathlon
Chez Ubik Ingénierie depuis 3 ans
Redouane Boutraa
Développeur full-stack depuis un peu plus d'un an�Back-end Java et Node.js / front-end Angular, JSP et EJS
Actuellement chez Brico Dépôt
Chez Ubik Ingénierie depuis moins d'un an
Auteur : Robert C. Martin�Date de publication : Août 2008
3
Clean Code: A Handbook of Agile Software Craftsmanship
Définitions multiples :�Certains choix sont subjectifs.
4
Plan
Des questions ?
Prenez-note ✏ :
Exemple : avant
5
Exemple : après
6
Objectifs
7
Objectifs
8
Exemple
9
Spécifications fonctionnelles
Mapper une ligne de base de données vers un objet Java
Une ligne a :� un libellé� un intervalle de validité dans le temps
Une ligne peut :� être supprimée (historisée) : grisée� être active : en surbrillance
10
11
12
13
14
15
16
17
18
19
Principes
&
méthode
20
Principes
21
Nous sommes des traducteurs Français ↔ Informatique
Réduction de 50 % si le produit périme dans les 4 jours�
discount = daysUntilExpiration <= 4 ? percent(50) : NO_DISCOUNT;
↕
22
Méthode
Les règles métier doivent être limpide dans le code
23
Nommage
24
Pas d’abréviations ni de noms imprononçables
⛔ config + conf + cnf + cfg 🔎�✅ configuration
⛔ pdt ❓❗�✅ pediatry ? pedometer ?� periodicity ? ponderation ?� postdate ?� product ? production ?� pendant ? pommeDeTerre ?
⛔ generationYmdhms 📣�✅ generationTimestamp�🥇 generationDateTime
25
NE JAMAIS ABRÉVIER
�CLEAN
Pas d’abréviations : dans l’exemple
26
Est-ce que PriceDetails�est un nom assez descriptif ?
27
Au fait...
Sans parasites
⛔ Variable, Value, Data, Info, Details, Manager, Processor
⛔ Order orderObject; ✅ order
⛔ class PriceInfo {} ✅ Price
⛔ class PriceDetails {} ✅ PriceTimeline / PricingPlan
⛔ String eanString; ✅ String ean 🥇 Ean13 ean // Not EuropeanArticleNumbering13
⛔ String strName; ✅ name
⛔ List<Long> idList; ✅ ids
⛔ void fStart(int pSpeed) { _player.fRun(pSpeed); }�✅ void start(speed) { player.run(speed); }
⛔ interface ICar {} ✅ interface Car {}� ICar iCar = new Car(); Car car = new CitroenCar() // PeugeotCar... or CarImpl
List<String> names = new LinkedList<String>()
28
Sans parasites : dans l’exemple
29
Révéler l'intention
À quoi sert la variable / méthodes / classe ?�⛔ List<Integer> list = …�✅ List<Integer> flags = …�🥇 EnumSet<Flag> flags = …
Comment peut-on l’utiliser ?�⛔ overridePrice(Product productA, Product productB)�✅ overridePrice(Product source, Product destination)
Expliquer “pourquoi” au lieu de “comment”�⛔ String getBarcodeReplacingNumbersUsingSmurfAlgorythm()�✅ String getBarcodeTextForFont()
30
Révéler l'intention : dans l’exemple
31
Expliquer les concepts : cohérent & cherchable
Mots communs pour ce qui se ressemble�✅ Product (pas Article)�✅ Cart (pas Shopping Cart, ni Shopping Basket)�✅ Voucher (pas Coupon, ni Token)
Mots différents pour ce qui ne doit pas être confondu�✅ Site = Magasin (“site d’implantation” dans tout le SI)�✅ Store = Le store Vue.js (ne pas utiliser pour décrire un magasin)
Glossaire commun au projet et au métier
32
Cohérent & cherchable : dans l’exemple
33
Que mettez-vous�dans les commentaires ?
34
Au fait...
Déplacer les commentaires dans les noms et / ou le typage
⛔�int DD = 3; // Default duration (in minutes)
⛔�int DD = 3; // Default duration (in minutes)��⚠️�int DURATION = 3; // Default (in minutes)
🚸�int DEFAULT_DURATION = 3; // In minutes
✅�int DEFAULT_DURATION_IN_MINUTES = 3;
🥇�Duration DEFAULT = Duration.ofMinutes(3);
35
Paradigmes
36
Les paradigmes de programmation
POO
Procédurale
Evénementielle
AOP
Réactive
Composant
Prototype
Contrat
?
?
?
?
?
?
?
37
Java == JavaScript ?�
38
Au fait...
Structure de données == Objet ?�
39
Au fait...
Les structures hybrides ?
40
Types ou Fonctions ?
Types
Fonctions
Création d’une structure de données
Création d’objets
Représentent une conception confuse
Assemblent le pire des deux mondes
?
Ce qu’il faut retenir ?
41
Structure de donnée
Objet
Facilite l’ajout de nouvelles fonctions
sans modifier les structures de données existantes
Facilite l’ajout de nouveaux types�(Classes, Interfaces) sans modifier les fonctions existantes
Exemple : les formes Géométriques
42
Structure de donnée
Objet
Interface
|
Functions
|
Class
|
Attributes
|
Class
|
Attribute
|
Class
|
Functions
|
Classes
43
Principe de responsabilité unique
44
Une classe ne doit changer que pour une seule raison
Principe de responsabilité unique
45
Une classe ne doit changer que pour une seule raison
Faire de petites classes
Maintenir la cohésion
Peu de variables
Fonctions
46
Heuristique des fonctions
47
Une fonction ne doit faire qu’une seule chose, n’avoir qu’un seul but
Nommage de fonction avec un seul verbe
Faire des fonctions courtes
searchProfileAndRefund()
private Profil searchProfil(int id){� …
}
private void refund(Profil profil){
...�}
Heuristique des fonctions
48
Une fonction ne doit faire qu’une seule chose, avoir qu’un seul but
Faire des fonctions courtes
Nommage de fonction avec un seul verbe
Avoir le moins d’arguments de fonction possible
Éviter les arguments boolean
private Profil searchProfil(int id, String username){� …
}
private void refund(Profil profil, boolean isConnected){
...�}
Heuristique des fonctions
49
Une fonction ne doit faire qu’une seule chose, avoir qu’un seul but
Faire des fonctions courtes
Nommage de fonction avec un seul verbe
Avoir le moins d’arguments de fonction possible
Éviter les arguments boolean
Avoir un seul niveau d’abstraction par fonction
Écrire les fonctions appelées sous la fonction appelante
refund(Profil profil){
String url = “http://myAccount”;
String port=”8080”;
profil.getCardNumber();
}
refund(Profil profil){
getConnection();
profil.getCardNumber();
}
Refactoring
Refactoring
50
51
52
53
54
55
56
57
58
59
60
Suivons les principes du Clean Code pour refactorer
Le nommage est déjà bon
Extraire chaque responsabilité dans une méthode courte
Réorganiser toutes ces méthodes dans des classes cohérentes
61
La métaphore de l’article de presse
Avoir une vue globale
Plonger dans les détails uniquement si besoin
Hiérarchiser pour faciliter la décision
62
Titre 1�Sous-titre 1�Paragraphe d'accroche 1�Corps de texte�en pyramide inversée
Titre 2�Sous-titre 2�Paragraphe d'accroche 2�Corps de texte�en pyramide inversée
Titre 3�Sous-titre 3�Paragraphe d'accroche 3�Corps de texte�en pyramide inversée
La métaphore de l’article de presse
Avoir une vue globale�Plonger dans les détails uniquement si besoin�Hiérarchiser pour faciliter la décision
63
entryPoint() {
stage1();
stage2();
}
stage1() {
actionA();
actionB();
}
stage2() {
actionC()
actionD()
}
actionA() {
// Fonction courte
}
actionB() {
// Fonction courte
}
actionC() {
// Fonction courte
}
actionD() {
// Fonction courte
}
64
65
66
67
68
69
70
71
72
73
74
75
76
Liens
77
Vidéos
Clean Code - Uncle Bob�(leçons 1 à 6 résumant le livre de manière vivante)�https://www.youtube.com/watch?v=7EmboKQH8lM&list=PLmmYSbUCWJ4x1GO839azG_BBw8rkh-zOj
Exercices de nettoyage de codes de Victor Rentea�(excellent pédagogue)�https://www.youtube.com/playlist?list=PLggcOULvfLL_MfFS_O0MKQ5W_6oWWbIw5
78
Les Code Smells du livre
79
Aides mémoire de refactoring
https://drive.google.com/drive/folders/1hvLAWeAgT753Mkb8zaHxNyBYwCewuWbb (par Victor Rentea)
80
Questions ?
81
Crédits des images
Titre :�Plan :�Exemple :�Objectifs :�Principes & méthode :�Nommage :�Révéler l'intention :�Cherchable :�Au fait... :�Fonctions :�Classes :�Refactoring :�Liens :��Questions ? :
https://www.pexels.com/fr-fr/photo/vue-de-l-exterieur-du-batiment-327483/�Internet...�https://www.pexels.com/fr-fr/photo/texte-6140480/�https://www.pexels.com/fr-fr/photo/gros-plan-de-main-humaine-327533/�https://www.pexels.com/fr-fr/photo/bibliotheque-interieure-lumineuse-590493/�https://www.pexels.com/fr-fr/photo/etiquette-de-produit-blanche-1111319/�https://www.pexels.com/fr-fr/photo/homme-travaillant-ordinateur-2696299/�https://www.pexels.com/fr-fr/photo/personne-tenant-une-boussole-1125272/�https://www.pexels.com/fr-fr/photo/illustration-point-d-interrogation-356079/�https://www.pexels.com/fr-fr/photo/ordinateur-portable-noir-et-gris-546819/�https://www.pexels.com/fr-fr/photo/bois-art-peinture-maison-6692956/�https://www.pexels.com/fr-fr/photo/homme-portant-une-pipe-grise-585419/�https://www.pexels.com/fr-fr/photo/corde-noire-de-machine-d-exercice-moderne-accrochee-a-un-mousqueton-en-metal-3839053/�https://www.pexels.com/fr-fr/photo/photo-en-grand-angle-du-robot-2599244/
82
WARNING
OPINIONS MAY VARY
Voici nos interprétations subjectives�suite à la lecture du livre
83
Spécifications fonctionnelles
Étant donné� Un utilisateur sportif� Il / elle reçoit des recommandations sur ses sports favoris
Quand� Il / elle veut se désinscrire d’un sport donné
Alors� On supprime ce sport dans les favoris de l’utilisateur� On garde un historique de la suppression
84
85
Pas d’abréviations : dans l’exemple
idx => index / indices
nb => count
86
Révéler l'intention : dans l’exemple
ref => sharedId / personId
constantes uniques => dans le code
:v_id => :share_id et :person_id
87
Cohérent & cherchable : dans l’exemple
register => historize
88
Humainement & fonctionnellement compréhensible : dans l’exemple
Avant : une soupe technique de 175 lignes
Après : ces 11 lignes métier :
89
Nommer les nombres magiques
⛔�if (player.getHealthPercentage() < 10) {� game.slowDown();�}
✅�static final int MINIMUM_GOOD_HEALTH_PERCENTAGE = 10;�if (player.getHealthPercentage() < MINIMUM_GOOD_HEALTH_PERCENTAGE) {� game.slowDown();�}
🥇�if (player.hasBadHealth()) {� game.slowDown();�}
90
Exemple 2 : ???
Que mettez-vous (ou pas)�dans des constantes ?
91
Au fait...
Utiliser des variables intermédiaires
⛔�if (captain.getAge() >= 18) { captain.drink(alcohol); }
✅�boolean hasMajority = captain.getAge() >= 18;�if (hasMajority) { captain.drink(alcohol); }
🥈�boolean canDrinkAlcohol = captain.getAge() >= 18;�if (canDrinkAlcohol) { captain.drink(alcohol); }
🥇�if (captain.canDrinkAlcohol()) { captain.drink(alcohol); }
92
Humainement & fonctionnellement compréhensible
Le code EST la spécification ultime : il doit transpirer le fonctionnel, et pas la technique
⛔ boolean canChangePrice(Product product) {� List<Error> productErrors = form.getErrors().get(product.getId());� return (errors == null || error.size() == 0) &&� (product.getStatus() == NEW || product.getStatus() == ACTIVE) &&� product.getSupplier().getStartDate().isBefore(LocalDateTime.now());�}
✅ boolean canChangePrice(Product product) {� return hasNoError(product) &&� product.isEditable() &&� product.hasActiveSupplier();�}
93
Humainement & fonctionnellement compréhensible : dans l’exemple
94
Fonctions
Petites�Ne faire qu'une seule chose�Un seul niveau d'abstraction�Ordonnées�Switch�Arguments : peu, et pas de booléen�Pas d'effet secondaire�Command/Query Separation�Ne pas retourner de codes d'erreurs�La gestion d’erreurs est une chose à part
95
96
Objectifs → Avantages
97
Retours d’expériences
98
Retour d’expérience
99
Sébastien
Des petites fonctions / classes, ça paraît extrémiste�On s’y essaye, pour voir�Et on découvre tous les avantages : simplicité, organisation, réutilisation
Clément
TODO
Redouane
TODO
Liens
Projet GitHub d’exemple :�https://github.com/clementdefauxubik/clean-code-example�Demander l’accès à Clément :�c.defaux@ubik-ingenierie.com
100