Xavier Lamorlette

Conception code propre (clean code)

Sommaire :

Vocabulaire

Fonction pure

Une fonction pure :

SOLID

S: Single Responsibility

Une classe / fonction doit avoir une et une seule responsabilité.
Une classe ne doit donc changer que pour une seule raison.

Cela permet :

O: Open / Close

Une classe doit être ouverte à l'extension mais fermée à la modification : elle ne doit être modifiable que par extension.
L'objectif est de ne pas toucher le code existant pour ne pas introduire de bug.
Cela force à un bon usage de l'abstraction et du polymorphisme.

L: Liskov Substitution

On doit pouvoir utiliser une instance d'une classe dérivée à la place d'une de la classe de base sans le savoir, sans que cela modifie la cohérence du programme.
Ce principe de substitualité permet de dire si l'héritage est cohérent de point de vue fonctionnel des clients.

Programmation par contrat :

I: Interface Segregation

Il vaut mieux des interfaces spécifiques pour chaque client plutôt qu'une seule interface générale.
Un client ne doit pas dépendre de méthodes qu'il n'utilise pas.
Ce principe est proche de celui de responsabilité unique.

Cela permet :

D: Dependency Inversion

Il faut dépendre des abstractions et non des implémentations.
Les modules de haut niveau ne doivent pas dépendre de ceux de bas niveau. Tous doivent dépendre d'abstractions.
Les abstractions ne doivent pas dépendre des détails mais le contraire.

Inversion of Control

Dependency Injection

La dépendance est un service qui fait partie de l'état de l'objet.
Un objet fourni à un autre une dépendance, plutôt que de laisser l'objet la construire ou la trouver lui-même.
Ça permet le découplage.
L'injection peut-être faite via le constructeur ou un setteur.

Dependency Injection

Règles de flocage

De Sandi Metz dans 99 Bottles of OOP.

Règles à appliquer dans l'ordre :

  1. Sélectionner les choses les plus similaires.
  2. Trouver leur plus petite différence.
  3. Appliquer le changement le plus simple pour la supprimer.

Étapes d'une transformation de code:

  1. Compiler le nouveau code.
  2. Appeler le nouveau code.
  3. Utiliser le résultat du nouveau code.
  4. Effacer l'ancien code.

Lisibilité du code

Limiter l'utilisation d'auto

Il faut limiter l'utilisation d'auto car :

Utiliser des “strong types”

Contrairement aux “general-use types” (comme les types natifs tel int et float), il faut utiliser des types dont le nom explicite l'usage.
Cela peut être fait simplement par l'utilisation d'alias.
Pour que cela génére des erreurs de compilation, on peut utiliser des struct.

Command Query Separation

Une méthode doit être, de manière exclusive :

Il est cependant parfois utile de faire les deux. Par exemple : stack::pop().

GRASP

GRASP signifie : General Responsibility Assignment Software Principles.

Low Coupling

Entre deux options d'architecture, il faut choisir celle qui a le niveau de couplage le plus faible.

Protected Variations

Organiser les responsabilités de différentes parties du code autour d'interfaces stables permet de les protéger mutuellement contre leurs variations.

Indirection

Introduire un composant entre deux parties du code permet d'absorber les impacts de leurs changements.

Polymorphism

L'essence du polymorphisme (dynamique, statique, etc.) est de découpler le client des différentes manières (implémentations) de réaliser une tâche.

High Cohesion

Une partie de code (fonction, classe, module) doit se concentrer sur une seule tâche.

Information Expert

Il faut assigner une responsabilité à la classe qui a les données nécessaires à cette responsabilité : si une fonction utilise certains paramètres, elle doit être une méthode de la classe qui contient ces paramètres.
Cela permet de conserver la localité et l'encapsulation des données.

Creator

Une classe doit être en charge d'en créer une autre si :

Pure Fabrication

Si une responsabilité ne peut être logiquement assignée à une classe du domaine applicatif, il faut créer une nouvelle classe en dehors de celui-ci pour la prendre en charge de manière cohérente.
Par exemple, un controller d'une interface graphique (cet exemple est le neuvième principe GRASP).

Cohérence du niveau d'abstraction

Chaque partie de code ne doit concerner qu'un seul niveau d'abstraction : dans une partie de code (fonction, classe, méthode, module, etc.), il ne faut pas mélanger différents niveaux d'abstraction.

La dernière mise à jour de cette page date de juillet 2021.

Le contenu de ce site est, en tant qu'œuvre originale de l'esprit, protégé par le droit d'auteur.
Pour tout commentaire, vous pouvez m'écrire à xavier.lamorlette@gmail.com.