1 of 100

Clean Code

Clément Defaux

Redouane Boutraa

Sébastien Laoût

2 of 100

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

3 of 100

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 of 100

4

Plan

  • Objectifs
  • Exemple en fil rouge
  • Principes & méthode
  • Ⓐ Nommage
  • Ⓑ Paradigmes & classes
  • Ⓒ Fonctions
  • Refactoring

Des questions ?

Prenez-note ✏ :

5 of 100

Exemple : avant

5

6 of 100

Exemple : après

6

7 of 100

Objectifs

7

8 of 100

Objectifs

  • Compréhensible par tous
  • Facilement maintenable
  • Réduit la complexité
  • Indépendant du développeur initial

8

9 of 100

Exemple

9

10 of 100

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 of 100

11

12 of 100

12

13 of 100

13

14 of 100

14

15 of 100

15

16 of 100

16

17 of 100

17

18 of 100

18

19 of 100

19

20 of 100

Principes

&

méthode

20

21 of 100

Principes

  • KISS : Keep It Simple Stupid
  • DRY : Don’t Repeat Yourself
  • YAGNI : You Aren’t Gonna Need It
  • La règle du boy scout

21

22 of 100

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

23 of 100

Méthode

Les règles métier doivent être limpide dans le code

  • Via le nommage
  • Puis via le découpage en petites fonctions :�Chaque fonction fait une seule chose et bien�Chaque fonction a un seul niveau d’abstraction
  • Puis via l’organisation des fonctions en classes�Chaque classe a sa propre responsabilité�Chaque classe encapsule ses détails techniques

23

24 of 100

Nommage

24

25 of 100

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

26 of 100

Pas d’abréviations : dans l’exemple

26

27 of 100

Est-ce que PriceDetails�est un nom assez descriptif ?

27

Au fait...

28 of 100

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

29 of 100

Sans parasites : dans l’exemple

29

30 of 100

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

31 of 100

Révéler l'intention : dans l’exemple

31

32 of 100

Expliquer les concepts : cohérent & cherchable

Mots communs pour ce qui se ressembleProduct (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

33 of 100

Cohérent & cherchable : dans l’exemple

33

34 of 100

Que mettez-vous�dans les commentaires ?

34

Au fait...

35 of 100

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

36 of 100

Paradigmes

36

37 of 100

Les paradigmes de programmation

POO

Procédurale

Evénementielle

AOP

Réactive

Composant

Prototype

Contrat

?

?

?

?

?

?

?

37

38 of 100

Java == JavaScript ?�

38

Au fait...

39 of 100

Structure de données == Objet ?�

39

Au fait...

40 of 100

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

?

41 of 100

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

42 of 100

Exemple : les formes Géométriques

42

Structure de donnée

Objet

Interface

  • Shape

Functions

  • périmètre
  • aire

Class

  • Circle
  • Square
  • Triangle

Attributes

  • List<Points>
  • ...

Class

  • Circle
  • Square
  • Triangle

Attribute

  • Point
  • longueur
  • largeur
  • ...

Class

  • Géométrie

Functions

  • aire
  • périmètre
  • ...

43 of 100

Classes

43

44 of 100

Principe de responsabilité unique

44

Une classe ne doit changer que pour une seule raison

45 of 100

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

46 of 100

Fonctions

46

47 of 100

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){

...�}

48 of 100

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){

...�}

49 of 100

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();

}

50 of 100

Refactoring

Refactoring

50

51 of 100

51

52 of 100

52

53 of 100

53

54 of 100

54

55 of 100

55

56 of 100

56

57 of 100

57

58 of 100

58

59 of 100

59

60 of 100

60

61 of 100

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

62 of 100

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 1Sous-titre 1Paragraphe d'accroche 1Corps de texte�en pyramide inversée

Titre 2Sous-titre 2Paragraphe d'accroche 2Corps de texte�en pyramide inversée

Titre 3Sous-titre 3Paragraphe d'accroche 3Corps de texte�en pyramide inversée

63 of 100

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 of 100

64

65 of 100

65

66 of 100

66

67 of 100

67

68 of 100

68

69 of 100

69

70 of 100

70

71 of 100

71

72 of 100

72

73 of 100

73

74 of 100

74

75 of 100

75

76 of 100

76

77 of 100

Liens

77

78 of 100

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

79 of 100

Les Code Smells du livre

79

80 of 100

Aides mémoire de refactoring

80

81 of 100

Questions ?

81

82 of 100

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 ? :

82

83 of 100

WARNING

OPINIONS MAY VARY

Voici nos interprétations subjectives�suite à la lecture du livre

83

84 of 100

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 of 100

85

86 of 100

Pas d’abréviations : dans l’exemple

idx => index / indices

nb => count

86

87 of 100

Révéler l'intention : dans l’exemple

ref => sharedId / personId

constantes uniques => dans le code

:v_id => :share_id et :person_id

87

88 of 100

Cohérent & cherchable : dans l’exemple

register => historize

88

89 of 100

Humainement & fonctionnellement compréhensible : dans l’exemple

Avant : une soupe technique de 175 lignes

Après : ces 11 lignes métier :

89

90 of 100

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 : ???

91 of 100

Que mettez-vous (ou pas)�dans des constantes ?

91

Au fait...

92 of 100

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

93 of 100

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

94 of 100

Humainement & fonctionnellement compréhensible : dans l’exemple

94

95 of 100

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 of 100

96

97 of 100

Objectifs → Avantages

  • Compréhensible par tous
  • Facilement maintenable
  • Réduit la complexité
  • Indépendant du développeur initial

97

98 of 100

Retours d’expériences

98

99 of 100

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

100 of 100

Liens

Projet GitHub d’exemple :�https://github.com/clementdefauxubik/clean-code-example�Demander l’accès à Clément :�c.defaux@ubik-ingenierie.com

100