Clean Code en C++ : principes et exemples pratiques
Chaque développeur C++ rencontre tôt ou tard le problème de la maintenance de son propre code ou de celui des autres. Les modèles complexes, les fonctions surchargées et les macros interminables transforment le projet en cauchemar. Le concept de Clean Code (code propre), popularisé par Robert Martin, propose des règles simples mais efficaces qui rendent le code compréhensible, sûr et facile à modifier. Dans cet article, nous allons analyser les principes clés du Clean Code appliqués au C++ et montrer comment les mettre en pratique.
1. Noms des variables et fonctions : dites ce que vous faites
La première règle du code propre est que le nom doit révéler l'intention du développeur. En C++, c'est particulièrement important en raison de l'abondance de pointeurs, de références et de surcharges.
Mauvais exemple :
int d; // temps écoulé en joursvoid f(int* a, int n); // ???Bon exemple :
int joursDepuisDerniereConnexion;void traiterDonneesUtilisateur(const std::vector<int>& idsUtilisateurs);Utilisez des mots complets, évitez les variables d'une seule lettre (sauf pour les indices dans les boucles courtes). Pour les variables booléennes, utilisez les préfixes is, has, should :
bool estSaisieValide;bool aPermissions;Nommez les classes et les structures avec des noms, et les fonctions avec des verbes ou des combinaisons verbales : class CompteUtilisateur, void calculerSalaire().
2. Fonctions : petites, avec une seule responsabilité
Une fonction ne doit faire qu'une seule chose et bien la faire. La longueur maximale est de 20 à 30 lignes. Si la fonction est plus longue, divisez-la en fonctions auxiliaires.
Mauvais exemple (fonction monolithique) :
void traiterCommande(Commande& commande) { // vérification du paiement // mise à jour du stock // envoi d'email // journalisation // génération du reçu}Bon exemple (décomposition) :
void traiterCommande(Commande& commande) { if (!validerPaiement(commande)) return; mettreAJourStock(commande); envoyerEmailConfirmation(commande); journaliserTransaction(commande); genererRecu(commande);}Essayez d'éviter les effets de bord. Une fonction ne doit pas modifier les variables globales ou les arguments passés par référence sans indication explicite dans le nom (reinitialiserDonnees, remplirTampon).
3. Gestion de la mémoire et des ressources : RAII et pointeurs intelligents
C++ donne un contrôle total sur la mémoire, mais cela entraîne des fuites. Clean Code propose d'utiliser l'idiome RAII (Resource Acquisition Is Initialization) et les pointeurs intelligents au lieu des new/delete bruts.
Mauvais exemple (gestion manuelle) :
void traiter() { int* donnees = new int[100]; // ... beaucoup de code ... if (erreur) { delete[] donnees; return; } delete[] donnees;}Bon exemple (RAII) :
void traiter() { std::unique_ptr<int[]> donnees = std::make_unique<int[]>(100); // ... code ... // delete est appelé automatiquement à la sortie de la portée}Pour la propriété partagée, utilisez std::shared_ptr, pour les références faibles — std::weak_ptr. Ne retournez jamais de pointeurs bruts sur des données internes — utilisez des références ou des pointeurs intelligents.
4. Gestion des erreurs : exceptions et codes de retour
Le code propre exige une gestion explicite et prévisible des erreurs. En C++, il existe deux approches principales : les exceptions et les codes de retour. Choisissez un seul style dans le cadre du projet.
Mauvais exemple (ignorer les erreurs) :
int diviser(int a, int b) { return a / b; // division par zéro !}Bon exemple (exceptions) :
int diviser(i