Clean code

Cédric BRASSEUR

Mis à jour le  18/11/2024

Cédric BRASSEUR

  • Ancien étudiant de l'Exia.cesi
  • 4 ans consultant chez Amaris, placé chez Euro Information Dev
  • Auto-entrepreneur depuis début 2020 (Création de sites web, applications mobiles & formateur)

Et vous ?

  • Nom, prénom
  • Etudes réalisées
  • Attentes de la formation

Plan du cours

Introduction

  • Pourquoi la qualité ? Pourquoi l'agilité ? Pourquoi un code propre  ?

Clean Code

  • Les commentaires et la mauvaise idée reçu
  • Horizon du clean code et des principes à appliquer                      
  • Pratiques complémentaires (Introduction)

TDD

  • Explications sur le TDD et les "règles" à respecter
  • Démonstration TDD
  • Les avantages du TDD, où se trouve le gain de cette pratique ? 
  • Workshop TDD + Clean code

Clean Architecture

  • Gestion de la dette technique
  • Principes SOLID - Martin Fowler et Robert C. Martin
  • Découverte des principes de développement SOLID et pratiques de refactoring

Clean

Objectifs de la formation

  • Etre capable de comprendre les notions de qualité et de dette dans le code, de connaitre les principes de base du développement propre
  • Maitriser les bases du développement piloté par les tests (TDD), savoir refactorer du code
  • Comprendre l'intérêt de l'agilité dans un projet et l'utilité du clean code pour sa réussite

Introduction

(Entreprise & Clean Code)

C'est quoi un code propre ?

Chaque développeur a son propre point de vue sur ce qu'est un code propre. La plupart du temps, on a plus une liste de choses que l'on ne veut pas voir plutôt qu'une recette miracle. 

Attention :

  • Le Clean Code est très subjectif
     
  • Vous serez en constante évolution au cours de votre carrière, au départ c'est un frein à votre productivité car vous devez faire des efforts supplémentaires.

Quand doit-on coder propre ?

Dans l'idéal, il faudrait toujours coder le plus proprement possible, quelque soit le développement en cours. Mais dans la réalité d'une entreprise, on ne peut pas travailler uniquement la qualité.
 

Mise en garde :

  • Vous allez sûrement avoir une phase ou vous allez vouloir faire de la sur-qualité "inutile"
     
  • La deadline est un facteur qui impacte la propreté du code (on reviendra sur ça, mais c'est un fait en entreprise)

Ce qui est attendu de vous ?

Savoir être

Savoir faire

Savoir penser

Savoir structurer

Savoir être

Le savoir être englobe plusieurs softskills, élever le niveau, savoir communiquer, savoir tirer profit de l'expérience des autres et apporter son expérience aux autres, et ça ne concerne pas que vous...

Savoir être

Ethique et attitude de codeur responsable :

  • Zéro mythos : Faire ce qu'on dit, dire ce que l'on fait
  • Agilité en entreprise, appliquer ou faire appliquer les principes agiles
  • Communication, feedback en continue
  • Savoir dire non (même au big boss)
  • Vous êtes une startup

Développeurs heureux, code fabuleux !

Savoir être

Se regarder dans le miroir avant de critiquer les autres ! Souvent, c'est par manque de connaissance, ou parce que le contexte ne permettait pas de réaliser du clean code qu'on livre du code sale.

Donc soyez indulgent avec les autres, mais ne le soyez pas avec vous-même.

Si ça ne vous est pas encore arrivé, ça vous arrivera un jour ! 

Don't blame !
Blame, but efficiently

Savoir être

Agilité et feedback en continue 

  • TDD et BDD : feedback sur les intentions de test.
  • Pull Requests et Code Review : feedback sur les livraisons de code.
  • Intégration et Déploiement continu : feedback sur l’intégration et fiabilité de la chaîne de déploiement.

Savoir être

Rappels sur les méthodes agiles

  • Releases périodiques et fréquentes (toutes les 2 semaines max)  
  • Intégrer le client dans le cycle
  • Utilisation d'une préproduction
  • Pull request et revue de code obligatoire
  • Intégration et déploiement continu
  • Daily meeting (scrum meeting)
  • Démo et réunion de rétrospective
  • Afficher les dashboards nécessaire au monitoring d'un projet 

Pourquoi la qualité
&
Pourquoi l'agilité ?

Les entraves au clean code

Vu comme ça, c'est beau, mais il y a des entraves au clean code. 

  • Les fondements et normes des entreprises qui n'évoluent pas toujours au bon rythme.
  • La méthodologie a un impact important sur le clean code.

Mise en garde :

  • Vous allez sûrement avoir une phase ou vous allez vouloir faire de la sur-qualité inutilement
     
  • La deadline est un facteur qui impacte la propreté du code (on reviendra sur ça, mais c'est un fait en entreprise)

Les entraves au clean code

Le nombre de développeurs dans le monde a une courbe de croissance extrêmement élevée au fil des années.
Environ un facteur double tous les 5 ans.

Ceci engendre que :

  • Tous les 5 ans, la moitié des développeurs est inexpérimentée
  • On doit tous apprendre aux moins expérimentés à développer proprement selon ses connaissances
  • On doit s'attendre à ce que tout ce que l'on délivre soit clean. C'est ce qu'un client attend d'un programme, on doit donc avoir la même attente de nos devs

Comment juger le Clean Code ?

Un des pionnier du Clean Code (Robert C. Martin) propose une façon simple d'analyser si du code est propre ou non. Il suffit de compter le nombre de "WTF" / minute lors d'une revue de code.

Mettons nous dans le bon état d'esprit...

Exercice solo :

Le but de cet exercice n'est pas de réaliser du code complexe, il est de réaliser l'exercice en essayant d'avoir le code le plus "Clean" possible selon votre expérience personnelle actuelle.


Je propose une simple simulation de jeu du serpent : 2 joueurs lancent un dé (1-6) au tour par tour, ils doivent arriver à la case 50. S'ils dépassent 50, le joueur retourne directement à la case 25. Jusqu'à ce qu'un des deux gagne la partie.

Le jeu acclame le joueur par son nom à la fin.

(Aucune interaction utilisateur nécessaire, juste de l'affichage en ligne de commande ou autre selon vos envies)

Envoyez moi les exercices tout au long de la formation

(cdric.brasseur@gmail.com)

Revue de code avec le voisin !

Exercice duo :

Le but de cet exercice est de prendre 20 minutes pour faire une revue de code réalisé par son voisin.

On ne critique pas le code du voisin, on propose des améliorations et son point de vue.

Car le voisin va également faire une revue de votre code de 20 minutes également.

 
Mettez sur un fichier les différentes remarques que vous vous faites entre vous !

Envoyez moi les exercices tout au long de la formation

(cdric.brasseur@gmail.com)

Savoir faire

L'utilisation de tests est primordiale ! Une technique que l'on va approfondir plus tard durant la formation : le TDD.

Et dans une future formation, le BDD également !

On test en mode agile, dans le but d'avoir un test en continu et présent dans notre intégration continue.

Savoir structurer

Plusieurs principes sont clés pour ce savoir :

  • Gestion dette technique
  • Le DDD (Domain Driven Design)
  • Architecture propre et S0LID

Ce sont des principes que l'on va parcourir et aborder dans la dernière partie de la formation (Clean architecture)

Savoir penser

Encore un savoir assez abstrait, un peu comme le savoir être. Nous aborderons plus en détail ce savoir en conclusion de la formation, sûrement même après l'évaluation !

Un avant goût de ce que l'on verra :

  • Veille technologique
  • Intéressez-vous à ce que disent les développeurs expérimentés (Martin Flower, Robert C. Martin, ...)
  • Pragmatisme et concentration
  • Think first act last

Clean Code : concepts et conseils

Introduction - Savoir faire

On l'a dit précédemment mais le clean code est assez subjectif, dans cette partie je vais vous proposer une vision des choses que j'applique et complétée par celle qui est proposée par Robert C. Martin.

  • Ne pas laisser de surprise dans son code
  • Coder lentement mais efficacement !
  • Il est très rare qu'un développeur puisse développer dès la première itération du clean code. L'objectif premier étant de faire fonctionner nos développements, il est nécessaire de repasser sur ces développements pour les rendre propres
      ==> Refactoring

Conseils et exemples

Les commentaires

Quel est votre avis sur les commentaires dans le code ?

Quand faut-il en mettre ? Quel pourcentage par rapport au code ?

?

?

?

Les commentaires

Ne jamais tout commenter

Un exemple de code commenté intégralement, regardez bien :

Deux remarques à faire !

Les commentaires

Maintenance des commentaires ?

Dans la réalité des choses, les commentaires ne sont pas maintenus, il arrive même qu'ils n'aient plus rien à voir avec la ligne en dessous, suite à un refactoring ou autre raison. 

 

Le conseil qui est donné par Robert C. Martin est de ne pas commenter son code, si un commentaire est nécessaire autant le factoriser et le rendre plus clair !

"Un commentaire est un échec dans la clarification de votre code"

 

Il faut nuancer un peu quand même, certains commentaires ont leurs places dans votre code. Et parfois nous n'avons pas le temps ou pas les connaissances pour rendre le code plus clair, donc le commentaire reste intéressant.

Les commentaires

Les commentaires utiles

Le commentaire informatif : Celui qui donne une information sur un format d'entrée accepté par une méthode par exemple.

 

 

Les commentaires sur des conditions : Ici on ne commente pas, on créer une méthode dont le nom explique la condition. 

Les commentaires

Les commentaires utiles

Le commentaire clarifiant : Dans le cas de suite d'opérations arithmétiques par exemple pour un test.

Le commentaire utile : Dans le cas de la réalisation d'une opération non compréhensible par le contexte

Les commentaires

Les commentaires obligatoires

Le commentaire copyrights : Il est fréquent que le copyright d'entreprise soit nécessaire sur vos développements

Le commentaire pour la documentation automatisée : Si le besoin d'avoir une doc est présent, faites le... Mais excepté pour la doc, on est vraiment dans le commentaire complètement inutile.

Les commentaires

Les mauvais commentaires

Quelques exemples de mauvais commentaires :

  • Les commentaires manquant de clarté
  • Les commentaires redondants
  • Les commentaires pour la documentation (Si elle n'est pas obligatoire selon le contexte ça n'a pas de sens)
  • Les commentaires de versionning et de signature "Fait par BRASSECE", git sait très bien nous dire ça
  • Les commentaires d'accolades fermantes

Les standards de développements

Bien nommer ses variables

Aujourd'hui, il est possible de nommer les variables comme on le souhaite, profitons-en pour les nommer correctement !

 

En C# la convention est d'utiliser le PascalCase pour quasiment tout, les classes, les propriétés, les méthodes,... 

Dans d'autres langages on va plus utiliser le camelCase.

 

Chaque variable doit représenter ce qu'elle va contenir : parfois on va même mettre le type de la donnée dans le nom de la variable (mais souvent l'IDE sait vous donner l'information, donc elle serait redondante dans ce cas)

Anecdote Fortran

Les standards de développements

Bien nommer ses variables

J'espère que ça vous semble logique de bien nommer vos variables, mais si ça semble annodin c'est nécessaire et mérite de la réflexion.

  • Choisir des noms exprimant vos intentions dans le code          
  • Eviter la désinformation
  • Penser ses noms pour des recherches dans le projet
  • Eviter les codifications
  • Choisir des noms en rapport au contexte / domaine
  • Choisir un mot par concept et le garder cohérent (exemple : fetch / retrieve / get,...)
  • Eviter les noms qui se ressemblent trop (surtout s'ils sont longs)

Les standards de développements

Bien nommer ses fonctions / méthodes

Les méthodes sont des actions, lorsque l'on verra le principe du découplage, nous verrons que chaque méthode devrait en principe faire qu'une seule chose.

Une méthode représente une action, elle doit donc avoir un contexte verbeux et il faut choisir un nom révélateur.                                                                                      

Exemples :

  • InsertClient(),
  • GetAllClients() ,
  • GetCarById(),
  • ...                              

Les standards de développements

Une fonction doit faire une seule chose et doit la faire bien (SRP)

Selon Robert C. Martin, les fonctions devraient réaliser qu'une et uniquement une seule chose. Il faudrait donc extraire chaque "chose" pour en faire une fonction. Il en décrit copieusement les avantages et la clarté de code qui en découle. La difficulté réside dans le fait de savoir quand est-ce que l'on fait une seule chose.                                                                  

TODO : Faire cette slide correctement

Les standards de développements

Une fonction doit faire une seule chose exemple (SRP)

Ce bout de code est fréquent à voir, mais il est complexe à tester efficacement et il fait plusieurs choses...

La méthode ProcessFile devient presque discutable pour le coup, mais afin de ne pas laisser le client pouvoir faire ce qu'il veut avec nos méthodes, c'est envisageable

Les standards de développements

Un exemple de principe SOLID non respecté

Ce bout de code est simple, il modifie la valeur d'un argument passé en paramètre. Mais c'est que l'on appel un side effect.

Le code appelant n'a l'info que les données sont changées par la méthode que par le nom (et le out, en .Net)

Le code appelant sait que la donnée qu'il veut est retournée et il en fait ce qu'il veut lui-même !

Les standards de développements

Les arguments d'une fonction

Personnellement, j'essaye de limiter au maximum le nombre d'arguments dans mes fonctions (3 max)

 

A savoir aussi sur les arguments : 

  • Le problème des arguments est qu'ils mélangent souvent plusieurs niveaux d'abstraction, 
  • Les arguments sont même encore plus pénibles du point de vue des tests. Imaginez la difficulté que représente l’écriture de tous les cas de test qui permettent de vérifier que les différentes combinaisons des arguments fonctionnent...
  • Passer une valeur booléenne à une fonction est véritablement une pratique épouvantable !

Faites des classes !

Les standards de développements

Ne pas avoir de paramètre avec un booléen

On se retrouve avec un if dans notre méthode et ça n'est pas très clair. Souvent ça implique d'avoir un if dans le code utilisateur également, ce qui n'est pas top.

Les standards de développements

Ne pas avoir de paramètre avec un booléen

Ici, on a appliqué deux actions pour rendre le code plus Clean :

  • On a deux méthodes différentes pour gérer les simple et double quotes (sans if)
  • Et on a appliqué le DRY Principle en factorisant le code commun dans une méthode

Les standards de développements

Les instructions avec accolades

Une instruction avec accolade (if, foreach,...) devrait dans l'idéal ne jamais être utilisé avec des accolades, ceci forçant cette instruction à faire une seule chose.

Vous l'aurez compris, la plupart du temps, on va développer une fonction et appeler cette fonction en passant à la ligne avec une tabulation.

Les standards de développements

Attention à l'instruction switch !

Un switch ne peut par définition pas réaliser qu'une seule chose. Ils sont donc déconseillé (pas interdit).
Déconseillé car :

  • En général, si vous avez un switch, vous en aurez d'autres qui vont suivre dans d'autres parties de vos développements.
  • En termes de déploiement, le switch nécessite de déployer toutes les fonctions / classes / méthodes de tous les switchs en cas de modification
  • Difficile de retrouver toutes les occurrences (if ?)

 

Un switch devrait être cloisonné, placé derrière une fabrique abstraite et nous verrons ça quand nous parlerons de Design Patterns. (Même si j'admets encore en utiliser parfois)

Les standards de développements

Un exemple de code et de simplification

Ce bout de code est pas simple à comprendre, vous ne trouvez pas ? Et pourtant...

Comment l'améliorer ? Le rendre compréhensible ?

Les standards de développements

Deux étapes pour améliorer le code précédent

 

  • On renomme correctement les variables, les méthodes et les arguments

On comprend déjà beaucoup plus de quoi on parle et quel est l'objectif de ce bout de code

Les standards de développements

Deux étapes pour améliorer le code précédent

  • On créer une classe Cell pour clarifier ce int[] et l'utilisation de constantes

Il n'y a pas vraiment plus de ligne de code et aucun besoin de commentaire pour comprendre ce que cette méthode fait.

Les standards de développements

Un exemple de refactoring de conditions imbriquées

  • Un exemple de code "simple", mais pas clair à cause des conditions imbriquées

Les standards de développements

Un exemple de refactoring de conditions imbriquées

  • Première étape, on mets les exceptions en premier de manière à retirer quelques imbrications + être explicite sur les erreurs possibles.

Les standards de développements

Un exemple de refactoring de conditions imbriquées

  • Seconde étape, on peut encore retirer le else inutile et les accolades qui ne servent à rien + On créer une fonction pour la condition, ça n'est pas au code utilisateur de gérer la majorité.

DRY Principle

Ne vous répétez pas

Un code propre est un code qui ne contient pas de répétition. Lorsqu'une répétition se trouve dans votre code il vous faut factoriser en créant une fonction et remplacer les doublons par un appel à cette fonction.
En tant que développeurs, nous avons souvent tendance à utiliser le copier coller, il faut être vigilant...

 

C'est très simple à mettre en place mais pas toujours à identifier il faut donc être attentif ou utiliser un outil d'analyse de code tel que SonarQube pour détecter ça. 

 

L'avantage principal : Une erreur dans le code dupliqué n'est pas à corriger à plusieurs endroits, elle n'est à corriger que dans la fonction factorisée. 

Les standards de développements

Un exemple de DRY Principle

  • Un exemple de code ou vous pouvez simplement éviter de vous répéter...

Les standards de développements

Un exemple de DRY Principle

  • Une méthode qui regroupe le tout dans un LogAction(string action) pour éviter de se répéter, ça permet de pas avoir 3 fois la modif à faire un jour si on veut ajouter la location par exemple...

Et encore... Les méthodes LogLogin(), LogLogout(), LogSignUp() sont un peu inutiles maintenant, mais pourquoi pas...

La mise en forme

Introduction et importance

En début de formation nous avons parlé du nombre de WTF pour évaluer le Clean Code. La mise en forme de votre code est très importante pour la compréhension du code et donc la qualité de celui ci.

 

Soyons clairs, le formatage du code est extrêmement important, la fonction que vous développez aujourd'hui va évoluer et doit être maintenable, pensez à celui qui passera derrière vous.

 

Nous allons voir comment mettre en forme sur deux axes :

  • La mise en forme verticale : lecture et compréhension du code ligne par ligne.
  • La mise en forme horizontale : largeur de ligne et indentation.

La mise en forme

La mise en forme verticale

  • Bien nommer le fichier : On doit savoir au premier coup d'œil de quoi on parle
  • Voir son code comme un "journal" : On le rend lisible de haut en bas, en intégrant les concepts détaillés en bas de fichier
  • Un journal pas trop long ! Il n'y a pas de vraie règle absolue, mais disons que plus ils sont courts mieux c'est. 200 lignes semblent d'après moi un maximum à éviter de dépasser
  • Espacement vertical des concepts : Bien séparer les concepts avec un saut de ligne
  • Organiser son code proprement : Associer les propriétés, puis constructeur, puis associer les méthodes en liens et dont les concepts se suivent en allant du plus haut niveau vers le plus bas.

La mise en forme

Exemple : La mise en forme verticale

La mise en forme

La mise en forme horizontale

  • La taille d'une ligne de code ne doit pas dépasser (dans l'idéal) 120 caractères pour pouvoir être affiché sur un écran sans avoir à scroller vers la droite. 
  • Le nombre de tabulation en début de ligne défini un ensemble d'instructions communes effectuée dans la même portée.
  • Mauvaise pratique : Aligner les initialisation de variables, ça n'apporte pas une meilleure lisibilité
  • La tabulation permet de simplifier grandement la compréhension
  • Eviter les "tout en une ligne", autant faire le saut de ligne et la tab.

La mise en forme

Exemple : La mise en forme horizontale

La mise en forme

Exemple : La mise en forme horizontale

Pour définir les normes : Appliquez des règles d'équipe

La mise en forme

Exemple de code arithmétique et compréhensibilité

Voici un code que j'ai récupéré et que j'ai adapté pour le rendre plus lisible en termes d'arithmétique : 

Attention au Linter dans ce cas !

Retrouver le code de base ou le recoder

La mise en forme

Outil d'analyse automatisé et Linter

Un linter va analyser syntaxiquement votre code selon certaines règles (Exemple Resharper, ESLint,...) que vous mettez en place au fur et à mesure avec votre équipe de développement.

Durant la phase d'intégration continue il est fréquent d'utiliser un outil d'analyse de la qualité de votre projet. Exemple SonarQube, qui calcul des métriques de qualité de code souvent très utiles.

 

Nous allons voir comment mettre en place cet outil, avec SonarCloud, en ligne, simple à associer à un repo github.

Le gestionnaire de code source

Outil de versionning

Nous n'allons pas voir comment fonctionne un gestionnaire de code source (même si durant les exercices je peux vous aider à prendre en main git, si besoin).

 

Je tiens juste à rappeler les avantages en termes de Clean Code : 

  • Premièrement, le gestionnaire de code source va nous permettre d'éviter un certain nombre de commentaires inutiles (comme vu précédemment)
  • Il va permettre de mettre en place une revue de code efficace sur les changements qui ont été réalisés pour la fonctionnalité
  • Il permet de retrouver le code précédent en cas de besoin
  • Et bien d'autres avantages également...

Systématique !

L'intégration continue

La CI pour le bien de tous

L'intégration continue a pour objectif de faciliter la tâche aux développeurs pour gérer leur code source et réaliser les tâches tout en rajoutant une couche de sureté avec différents tests automatisés lors des merge (ou commit d'ailleurs).

 

Pour notre CI, on va mettre en place des étapes supplémentaires à notre validation de merge (déploiement impossible si rouge) :

  • Vérifications des tests automatisés (inclus la sécurité et qualité)
  • Réalisation de revue de code manuelle
  • Vérification syntaxique du code (Linter)
  • Gestion du build automatisé (générer les dépendances par ligne de commande, par exemple npm ci)

Systématique !

Importance des tests

L'objectif premier de réaliser des tests sur son application est de limité d'envoyer des erreurs en production.

On va donc tester les développements réalisés à chaque changement et surtout avant chaque mise en production, ce qui rend l'application plus robuste mais ne la rend pas infaillible.

  • L'utilisation d'une CI/CD force la réalisation de tests et surtout de s'assurer qu'ils passent,
  • L'identification des problèmes est donc réalisée bien plus tôt et plus simplement car tout est cloisonné,
  • Plus de productivité (si industrialisé) et rendement.

Les différents types de tests

Il existe de nombreux types de tests, nous allons essentiellement travailler les tests unitaires lors de cette formation. Et les tests d'acceptation dans la prochaine (BDD)

  • Tests unitaires : On test atomiquement toutes les portions de notre code ! L'objectif des tests unitaires est de couvrir le plus de code possible 100% est la valeur que l'on tend à atteindre pour la perfection. (Mais difficile en pratique)
     
  • Autres tests : Acceptation, interface, charge, performance, sécurité, exploitabilité, vérification de disponibilité immédiate, 

Les tests unitaires

Une pratique de plus en plus courante...

Une pratique a émergé suite à ce besoin grandissant en termes de tests unitaires sur l'intégralité de notre projet

Systématique !

Le TDD : Test Driven Development

Nous allons voir les règles et pratiquer le TDD dans la partie suivante de la formation et pour le reste de la formation

La revue de code

Rendu obligatoire dans le process de CI/CD !

Quelques règles pour la revue de code :

  • Une revue de code ce n'est pas juste vérifier l'indentation, s'il y'a un ; à la fin etc... Notre Linter s'occupe de ça bien mieux.
  • La revue de code doit prendre au minimum la moitié du temps qu'à pris le développement de la fonctionnalité.
  • La revue de code est obligatoire (je me répète, mais c'est important)
  • La revue de code est un moyen de prendre de l'expérience d'autrui et donner son expérience
  • La revue de code fait parti du savoir faire.

Conseil en vrac - Clean Code

Autres conseils selon mon point de vue

  • Il se cache souvent une classe derrière une méthode ayant plusieurs tabulations de profondeur de code, cette méthode doit sûrement définir des variables sur lesquelles elle travail ==> propriétés + méthodes.
  • No side effects : Effets de paire, chaque new a besoin d'un free, chaque open a besoin d'être closed. Et on ne change pas l'état de quelque chose dont on n'a pas la responsabilité.
  • Garbage collection : On est mauvais pour faire ça et on a même inventé le moyen de nous éviter ce problème car le garbage collector fait ça pour nous. Mais quel est le problème potentiel ? Side effects.
  • Open closed principle : Votre code doit être ouvert aux évolutions mais fermé aux modification (utilisation d'abstractions)
  • TODO qui sont commits deviennent des non-dos. Donc soit vous faites le TODO avant de commit, soit vous retirez le TODO.

Conclusion savoir faire

Le design simple et incrémental

Pensez simple votre design simple et incrémental. Ici je parle plus d'architecture de projet que de design (interface) mais c'est valable également pour l'interface.

La partie Clean Architecture sera abordée après le TDD durant la formation.

 

Votre objectif est de maîtriser les différents principes et outils présentés précédemment. En tant que développeur vous devez vous assurer vous même de la qualité de votre code.

Aparté : Le QA et sa place en entreprise

Exercice

Le but de l'exercice est simple : Choisir parmi un des sujet proposé et appliquer au maximum les principes de Clean Code vu ensemble

 

 

  • Faites un repo github pour votre projet
  • Aucune restriction en terme de technologie choisie.
  • Réalisez essentiellement une partie backend (le front peut être uniquement de l'affichage console)
  • Vous pouvez également choisir un sujet de votre choix, sachant que vous aurez entre 1h30 et 2h pour travailler dessus au total.

 

Envoyer la liste des sujets potentiels

Exercice

Revue de code sur les développements réalisés

 

J'hésite encore entre prendre un de vos projet et faire la revue de code avec vous ou vous faire faire la revue entre vous.

Je déciderai en fonction de la qualité des projets proposés par les étudiants.

Add enum + state sample 

Mise en oeuvre d'un outil d'audit de qualité

Mise en place de SonarCloud en CI

Sonar

Les métriques analysées

Les smells applicatifs

Dans la couche applicative, on retrouve des smells qui impactent une solution sur plusieurs modules, classes et méthodes en étant associés à plusieurs emplacements dans l’application. Quelques exemples marquants :

  • Chirurgie Shotgun (Shotgun Surgery) : une modification nécessitant d’être répliquée sur plusieurs classes en même temps.
  • Complexité pour la complexité (Contrieved Complexity) : utilisation inutile, voire forcée, de design patterns compliqués quand ce n’est pas nécessaire.

Sonar

Les métriques analysées

Les smells de classe

Les classes smells regroupent tous les anti-patterns inhérents à une classe. Pour en énumérer quelques-uns :

  • Feature Envy : une classe qui fait une utilisation abusive des méthodes d’une autre classe.
  • Large class : une classe qui contient beaucoup trop de lignes de code, plus d’une centaine.
  • Inappropriate intimacy : une classe qui accède aux détails d’implémentation d’une autre classe.
  • Orphan variable or constant class : une classe qui a une collection de constantes dont elle ne fait pas usage et, par conséquent, dont elle ne devrait pas être maîtresse.

Sonar

Les métriques analysées

Les smells de méthode

  • Utilisation de trop de paramètres : nous pouvons nous retrouver dans une situation où une méthode évolue avec le temps pour arriver au point où elle accepte beaucoup trop de paramètres en entrée.
  • Méthode trop longue : elle contient beaucoup trop de lignes. En général, une méthode avec plus de 20 lignes pourra être considérée comme trop longue. Le premier réflexe serait de découper ce type de méthode en plusieurs sous-méthodes. Toutefois, une telle pratique pourrait cacher un problème de design qui, pour être résolu, nécessiterait un refactoring plus important, tel que la création d’autres classes.

Sonar

Allons voir la doc de SonarCloud

Sonar

SonarLint

Installation & présentation de SonarLint

Pull request et revue de code

Revue de code

Voyons comment mettre en place les pull request et les revues de code sur notre repository Github...

Exercice

Exercice SonarCloud

 

Mettez en place l'intégration continue avec SonarCloud sur votre projet (ou sinon, réalisez une analyse sur votre poste avec SonarQube) regardez et corrigez un maximum des code smells / bugs qui vous sont remontés.

Prenez le temps de bien faire cet exercice, le but est vraiment de ne plus avoir de smells à cette version de votre code

Présentation de Lighthouse

 

 

Et les 4 axes qui sont analysés

Performances

Analyse des performances du site, temps de chargement, taille des images, premier affichage de la page d'accueil etc...

Accessibilité 

Analyse de l'accessibilité à votre site, ça passe par les variances de couleurs, la taille des caractères, la police choisie, etc...

Les 4 axes analysés

Performances

Bonne pratiques

Un peu comme ce que propose Sonar sur votre site web, ici ça analyse le code source disponible et fait des retours dessus

SEO

"Search Engine Optimization", des retours directs sur votre ranking dans les recherches google.
A savoir : Les autres axes améliorent aussi votre SEO

Exemple & utilisation

TDD : Tests Driven Development

Les tests unitaires

Définition, utilité et réalité

  • Un test unitaire est utilisé afin de pouvoir vérifier atomiquement que chaque élément de notre code fait ce qu'on attend de lui.
  • A une certaine époque, je n'utilisais les tests unitaires que pour tester grossièrement mon application à la fin de mes développements. 
  • Les tests unitaires sont souvent utilisés (à tort) comme des tests jetables, alors qu'ils doivent faire partie intégrante de votre intégration continue

Nous allons entamer votre apprentissage du TDD, mais sachez que vous ne serez sûrement pas encore experts à la fin de cette formation, à vous d'être assidu et pratiquer quand vous en avez la possibilité

Le TDD : Une méthodologie bien rodée et adaptée

Le TDD est une pratique qui a commencé à être réellement utilisée en 1999. Peu répandu en France à ma connaissance et pourtant... C'est un point si important ! On en parler juste avant, trop d'entreprise demandent à la QA pour réaliser des tests.

NON ! C'est à nous de tester nos développements

Les règles du TDD

Il y a trois grandes règles à respecter pour faire correctement du TDD

Les règles :

  • Première : Vous ne devez pas écrire de code projet tant que vous n’avez pas écrit un test unitaire qui ne passe pas.
  • Deuxième : Vous devez uniquement écrire le test unitaire suffisant pour échouer, l’impossibilité de compiler est un échec.
  • Troisième : Vous devez uniquement écrire le code projet suffisant pour réussir le test actuellement en échec (et faire passer les autres.)

Les tests et le code sont écrits ensemble, en commençant par les tests.

Garder des tests propre est primordiale

Maintenir ses tests c'est maintenir son code

Tous les concepts et conseils vu dans la partie précédente sont à appliquer dans vos tests unitaires. C'est important de le comprendre car c'est également un des avantages de l'utilisation de la méthode TDD.

Le Test Driven Development en agile

Pourquoi le TDD ?

Tout code doit être testé et en agile on doit être prêt à déployer toutes les 2 semaines (ou semaine). ça ne veut pas dire qu'on va forcément toujours délivrer tout ce qui est développé, mais on va déployer que des choses prêtes à être déployées et ce à un certain rythme (comparé à avant, ou on livrait tous les 3 mois)

Attention, la couverture de tests voulue est 100% mais c'est la valeur théorique quasi inatteignable

L'objectif des tests est de permettre n'importe quelle modification sans avoir peur de casser quelque chose.

Votre premier objectif est de tester chaque portion de code que vous développez

Le TDD

Les avantages de la méthodologie

  • En tant que développeur, c'est intéressant de tester ses développements grâce à des tests unitaires plutôt que d'utiliser un debugger. On a tous ce signe de victoire quand on fait passer un test, quel plaisir, pourquoi s'en priver ?
     
  • Le TDD est assez complexe à appréhender mais c'est une façon de développer qui vous permettra de devenir des développeurs sûrs de ce qu'ils déploient en production.
     
  • Quand vous développez des tests, vous écrivez votre documentation et vos exemples de code !  C'est important, c'est aussi un gain de temps et ce sont vos tests qui vont former les futures développeurs sur votre projet et non une doc écrite sur du code copier/coller dans un PDF 5 ans auparavant.

Petite démo du TDD

Je vais faire un exemple en l'expliquant pas à pas devant vous

Exercice simple

Exercice très simple mais qui permet d'appliquer facilement (même si pour le cas d'usage un peu bêtement) le TDD.

 

Réalisez une calculatrice simple, qui prend deux entiers en paramètres et qui retourne le résultat des opérations suivantes : 

  • Addition
  • Soustraction
  • Multiplication
  • Division

L'objectif est donc d'avoir une classe Calculator qui contient 4 méthodes entièrement testé en TDD (en démarrant par des tests en échec,...)

Faites en sorte que les paramètres ne puissent pas être négatifs et faites en sorte qu'une exception custom (Ou ArgumentException) soit levée si on tente de diviser par zéro.

Exercice simple

Vous allez devoir développer en TDD le célèbre FizzBuzz :

  • Une méthode GetOutput(int number) avec un paramètre d'entrée (number)
  • Cette méthode retourne un string
    • Si c'est un multiple de 3, retourne "Fizz"
    • Si c'est un multiple de 5, retourne "Buzz"
    • Si c'est un multiple de 3 et 5, retourne "FizzBuzz"
    • Si c'est multiple de ni l'un ni l'autre retourne le nombre en chaîne de caractère

 

Essayez de réaliser la méthodologie TDD la plus complète possible pour cet exercice.

Exercice reprise des bases du TDD

Tutoriel à suivre :

Pour celles et ceux qui finissent vite, quelques conseils pratiques peuvent être récupérés de ce lien, parcourez le :

Exercice intermédiaire

Refaites exactement les étapes réalisées avec vous pour la classe Stack, en démarrant le tout en TDD.

Rappelez-vous, on démarre par du code bête et méchant, jusqu'à ce que le besoin de faire évoluer le code projet (via un test) se fasse ressentir.

  • La stack créer est vide
  • Après un Push la stack n'est pas vide
  • Après un Pop sur une stack vide,  une erreur custom est retournée
  • Après un Push puis un Pop, la stack est vide
  • Après deux Push et un Pop, la stack n'est pas vide
  • Après avoir Push X, le premier élément est X
  • Après avoir Push X, un Pop supprime X
  • ...

Envoyez moi les exercices tout au long de la formation, j'utiliserai ces éléments pour la notation.

Exercice intermédiaire

Pour comprendre un peu le TDD, je vais vous envoyer un exercice un peu plus complexe que ceux que l'on a fait jusqu'à maintenant.

 

Le but est de vraiment prendre le temps de penser en TDD et de réaliser cet exercice en respectant toutes les règles proposées.

Envoyer Exercice_TDD_medium.md

Exercice: TDD sujet complet

Pour cet exercice, vous allez devoir implémenter un jeu dont les règles se trouvent ici

https://www.codewars.com/kata/5941c545f5c394fef900000c

 

Votre objectif est d'implémenter le jeu en réalisant une TDD la plus complète possible.

Le TDD

Petite mise en garde

Le TDD n'est pas simple à apprendre et à mettre en place. Prenez le temps d'apprendre ça sur des projets personnels avant d'emmener ça au travail.


Ce serait contre productif. Et vous l'avez expérimenté, la première fois c'est pas facile le TDD.
Un dernier exercice vous attend pour le Workshop final.

Le TDD

TODO

Ajouter un ensemble d'action chaîné à la stack, afin de pouvoir faire aucune de ces actions si par exemple il y a plus de pop que de push dans l'ensemble des actions.

+ Gérer le fait qu'il y a tjr plus de push avant chaque ensemble de pop

 

Voir si c'est en combien de temps c'est faisable, la difficulté et si possible en faire un exercice complémentaire

Clean Architecture

Introduction - Savoir structurer

Un autre objectif a atteindre pour réaliser du Clean Code est de réaliser également une Clean Architecture.

  • Fondamentalement le code n'a pas changé en 70 ans, on fait des if, des boucles, des sélections... Alors que l'architecture évolue en permanence.
  • Nous sommes tous des architectes en un sens, les architectes de nos développements (Design Architecture / Software architecture)

  • L'architecture permet de prendre les décisions critiques le plus tard possible dans le projet. (Exemple : Base de données)

Savoir structurer

Gestion de la dette technique

Une fois de plus l'utilisation d'un outil d'analyse qualité est de mise ici : SonarQube

Savoir structurer

Les métriques analysées

Les smells applicatifs

Dans la couche applicative, on retrouve des smells qui impactent une solution sur plusieurs modules, classes et méthodes en étant associés à plusieurs emplacements dans l’application. Quelques exemples marquants :

  • Chirurgie Shotgun (Shotgun Surgery) : une modification nécessitant d’être répliquée sur plusieurs classes en même temps.
  • Complexité pour la complexité (Contrived Complexity) : utilisation inutile, voire forcée, de design patterns compliqués quand ce n’est pas nécessaire.

Savoir structurer

Les métriques analysées

Les smells de classe

Les classes smells regroupent tous les anti-patterns inhérents à une classe. Pour en énumérer quelques-uns :

  • Feature Envy : une classe qui fait une utilisation abusive des méthodes d’une autre classe.
  • Large class : une classe qui contient beaucoup trop de lignes de code, plus d’une centaine.
  • Inappropriate intimacy : une classe qui accède aux détails d’implémentation d’une autre classe.
  • Orphan variable or constant class : une classe qui a une collection de constantes dont elle ne fait pas usage et, par conséquent, dont elle ne devrait pas être maîtresse.

Savoir structurer

Les métriques analysées

Les smells de méthode

  • Utilisation de trop de paramètres : nous pouvons nous retrouver dans une situation où une méthode évolue avec le temps pour arriver au point où elle accepte beaucoup trop de paramètres en entrée.
  • Méthode trop longue : elle contient beaucoup trop de lignes. En général, une méthode avec plus de 20 lignes pourra être considérée comme trop longue. Le premier réflexe serait de découper ce type de méthode en plusieurs sous-méthodes. Toutefois, une telle pratique pourrait cacher un problème de design qui, pour être résolu, nécessiterait un refactoring plus important, tel que la création d’autres classes.

Savoir structurer

Introduction au DDD

  • Le DDD vise à formaliser la gestion de connaissances, favoriser la collaboration avec les experts du domaine
     
  • Le DDD apporte une terminologie qui permet aux équipes de s’approprier des concepts métiers et de les retranscrire en éléments de modélisation. Permettant de peaufiner l'architecture applicative.
     
  • Le DDD est une approche qui permet de structurer la connaissance et de partager une compréhension commune du besoin logiciel entre les différentes parties prenantes impliquées dans la réalisation d’un logiciel.

Architecture propre et SOLID

Plusieurs principes peuvent vous permettre de réaliser une architecture clean. Nous n'allons pas aborder en détail ce point car il sera abordé lors d'une prochaine formation Architecture.

  • S : Single Responsibility Principle
  • O : Open/Closed Principle
  • L : Liskov Substitution Principle (Attention à l'héritage)
  • I : Interface Segregation Principle (Interface courtes)
  • D : Dependency Injection Principle

S : Single Responsibility Principle

C'est assez explicite par son nom, mais ça doit être précisé pour éviter de passer à côté de quelque chose d'important : On veut effectivement que chaque élément ne soit responsable que d'une chose et qu'il la fasse bien. Mais on souhaite aussi séparer les "choses faites" par acteur, c'est important pour éviter les soucis.

Prenons un exemple...

Vous avez trois services (d'entreprise) : 

  • Service RH
  • Service Cadre
  • Service Employés

Si vous réalisez une seule méthode pour calculer le salaire des employés, vous ne respectez pas le SRP. Imaginez que le calcul change pour le service Cadre uniquement, si le code a été factorisé, vous allez modifier le calcul de salaire de tous les services et causer des effets de bords sur les salaires des RH et Employés...

O : Open / Closed Principle

Votre programme doit être ouvert aux extensions mais fermé aux modifications. C'est à dire que l'on va utiliser des abstractions afin de faire évoluer le code existant plutôt que de le modifier ! Ainsi que gérer les injections de dépendances dans un sens particulier pour diminuer les impacts en modifications.

Comment gérer les dépendances ?

L'objectif est de respecter ce que l'on a vu dans la partie précédente, afin de rendre la partie Domain la moins sujette aux modifications impactantes, contrairement à la partie Presentation qui elle risque des modifications régulières mais ayant peu d'impacts sur le système.

O : Open / Closed Principle

Prenons un exemple...

Dans cet exemple, l'objectif est d'afficher des stats sur un support différent.
 

Il faut donc noter surtout le sens des dépendances ainsi que les interfaces utilisées pour cloisonner, et savoir que l'on pointe le plus possible vers l'Interactor (Buisness Rules) pour que cette partie soit la moins ouverte aux modifications.

L : Liskov Substitution Principle

Les interfaces doivent êtres utilisées de manière à s'assurer que chaque cas d'utilisation correspond bien aux attentes. Pour mieux comprendre prenons un contre-exemple bien connu.

Prenons un contre-exemple...

Admettons que nous avons une projet qui permet un User de travailler avec un Rectangle, puis par la suite on souhaite le faire travailler également avec un carré.

Ici, on peut imaginer que ça peut factoriser le code de réaliser quelque chose de ce style, mais ça ne respecte pas le LSP. 

 

Vous voyez pourquoi ?

L : Liskov Substitution Principle

Les interfaces doivent êtres utilisées de manière à s'assurer que chaque cas d'utilisation correspond bien aux attentes ET soient substituables (remplaçable)

Prenons un exemple architectural...

Pour le projet Collect&Verything, vous passez par des API REST, admettons une URI comme ceci :
collect.com/enterprise/cora/pickupaddress/57000 Metz.../products/123

Imaginons qu'une entreprise (Click) réutilise notre système sans lire correctement les specs et décide de mettre en place ce système, mais en utilisant pickup à la place de pickupaddress.

Ceci nous forcerait à avoir un if (enterprise == "Click") dans le code et dont des conditions à gérer. Ici, bien utiliser une interface permettrait d'éviter ce problème architectural

I : Interface Segregation Principle

Ce principe a pour objectif d'éviter de vous trimballer des choses dont vous ne dépendez pas (dans votre classe). 

Prenons un exemple...

Prenons ce diagramme de classes et imaginons que OPS soit une liste d'opérations et que chaque User utilise l'opération correspondant à son chiffre (U1 => op1,...) 

Il est nécessaire d'ajouter des interfaces afin de limiter les dépendances des Users vers les opérations qui l'intéressent

D : Dependency Inversion Principle

Ce principe dit d'abord que les programmes les plus flexibles sont les programmes dont le source code dépend d'abstractions et non d'éléments concrets. Plus directement, chaque import devrait être une abstraction et jamais une classe concrète. (Bien que ce soit impossible dans les faits, c'est une règle à appliquer au maximum)

Quel est l'objectif ?

Les éléments concrets sont plus volatiles & un changement dans une classe concrète nécessite forcément une modification dans la classe qui en dépend. Ce n'est pas (forcément) vrai dans le cas d'une modification d'abstraction.

Ne jamais faire référence à un élément volatile !

D : Dependency Inversion Principle

D'accord, mais comment faire ça ?

Pour éviter ces dépendances que l'on souhaite ne jamais mettre dans notre code, nous devons utiliser les "Abstract Factories",

La ligne rose est une barrière entre les abstractions et les implémentations concrètes

Prenons un exemple...

Remarquez les dépendances de chaque côté de la ligne rose sont dans des sens opposés (d'où le nom de DIP)
Par contre, l'élément concret ici ne respecte pas le DIP, on répète que le DIP n'est pas applicable à 100%

Architecture hexagonale

Sans rentrer dans le détail car vous le verrez dans une autre formation (en tous cas, si le formateur ne vous parle pas d'architecture hexagonale, demandez lui)

Pour faire simple :

  • On met au centre les données métier (Business Logic) et on s'arrange pour que d'un côté les utilisateurs puissent exploiter le logiciel et de l'autre côté, des "Bots" : Les différents tests automatisés (dont tests unitaires)
  • L'idée est de proposer des interfaces d'interaction avec votre Business Logic

Architecture Cloud

Celle-ci, c'est sûr que vous la verrez car elle fait partie d'une grande partie de votre cours Architecture : Création de services Cloud (échanges réseaux) et orchestration de ses service + User interface.

Image from redhat

Evaluations

Partie théorique

Envoyer fichier clean_code_test

Partie pratique

Je vais vous envoyer deux propositions de sujet sur un fichier .md

 

Vous pouvez choisir la proposition que vous voulez et normalement toutes les règles et choses à respecter pour l'évaluation sont présentes sur ce fichier.

BON COURAGE !

(après c'est fini)

Envoyer Evaluation_CleanCode.md

Partie pratique

BON COURAGE !

(après c'est fini)

Exercice de TDD en appliquant au maximum les principes de Clean Code que l'on a vu ensemble.

 

  • Faire une TDD de zéro pour le jeu du Serpent
    Règles supplémentaires
    • Si on tombe sur les cases 10, 20, 30, 40, on joue 2 fois
    • Ajoutez des cases bonus et des cases pièges (Exemple, la case 7 mène à la 19, la case 23 mène à la case 12,...)
    • Réalisez le jeu pour plus de deux joueurs
    • Permettez la modification du nombre de case du jeu à la création de celui-ci
    • ...
  • OU slide suivante si nous avons déjà eu le temps de faire cet exercice durant la formation

Conclusion

Savoir penser

  • Veille technologique en continue

  • Intéressez-vous à ce que disent les développeurs expérimentés
  • Pragmatisme et concentration
  • Think first act last

Le savoir pensé est un état d'esprit, c'est pourquoi je l'utilise en conclusion, je ne peux que vous encourager sur le chemin du Clean Code. 

clean-code

By Cėdric Brasseur

clean-code

Formation Clean Code By Cédric BRASSEUR

  • 760