Clean code #1 : Posons les bases et le nommage

Comment faire un code propre? Je m’embarque ici dans une vaste question! Toute d’abord, je sais que j’ai assez peu expérience, je prendrai peu de risque dans ce premier article. J’aborderai un sujet assez simple, le nommage, grandement inspiré par le livre Clean Code de Robert C. Martin que je conseille à tous!

Ce sujet me tient à cœur suite à un déclique il y a quelques mois maintenant. Ce dernier m’a permis de grandement améliorer ma qualité de code en suivant quelques règles et astuces simples.

Qu’est ce que du code propre?

Pas de réponse facile, cependant je résume cela comme un code facile à lire/comprendre, maintenable et évolutif.

Comme débutant, nous connaissons souvent nos designs patterns de base, nous pouvons être un peu maladroit dans leurs utilisations, mais globalement faire un code maintenable et évolutif est à notre portée. Cependant, j’ai vu beaucoup de stagiaires/débutants (ainsi que certains développeurs expérimentés) produisant un code bordélique et illisible.https://fr.wikipedia.org/wiki/Patron_de_conception

Je ne me trompe probablement pas en disant qu’il vous arrive régulièrement de débugguer un bout de code pour comprendre ce qu’il fait. Perdre des heures à déchiffrer un algorithme illisible, quoi de plus rageant!

Tout cela, car le concepteur initial n’a pas pris le temps de faire quelques ajustements simples. C’est sur cet aspect que je vais concentrer cette série d’articles.

Nommage

Le nommage est l’un des critères les plus importants. Ce dernier permet de comprendre à la lecture d’un nom de variable ce qu’elle représente, à la lecture d’un nom de fonction ce qu’elle fait etc…

Utiliser des noms explicites

Par exemple, si vous souhaitez créer une classe date voici un exemple d’implémentation assez commun:

public class Date{
    int y;
    int m;
    int d;
    
    public int getY(){
        return this.y;
    }
}

Cela reste explicite, mais il est largement préférable, pour être le plus clair possible, de définir la classe de la manière suivante :

public class Date{
    int year;
    int month;
    int day;

    public int getYear(){
        return this.year;
    }
}

Bon jusque là, c’est relativement évidant!

Maintenant, une mauvaise habitude que je peux voir chez les accros aux commentaires comme j’ai pu l’être. Cette habitude consiste à mettre un commentaire alors que l’information du commentaire pourrait être contenue dans le nom de la variable.

Exemple :

// day since modification
int day;

/*
 *  Préferez la version suivante
 */

int daySinceModification;

Dans le cas de la première proposition, l’information n’est disponible qu’à la déclaration, mais sera pas directement accessible lors de l’utilisation de la variable.

Désinformation et ambiguïtés des noms

Autre point important, évitez la désinformation et les ambiguïtés lors du choix des noms de variables. Par exemple, n’utilisez le nom « list » dans vos noms de variable uniquement pour les listes et non pour les tableaux.

De même, il est préférable pour deux méthodes aux fonctionnalités proches d’avoir des noms similaires. Et l’inverse doit être évité, si vous avez des noms de méthodes similaires qui ont des objectifs différents, les autres développeurs qui utiliseront ou verront ces méthodes auront toujours un doute sur le fonctionnement et devront regarder la JavaDoc (si disponible) ou l’implémentation pour être sûr de leur choix.

Valeurs magiques

Voilà quelque chose qui me met réellement en colère quand j’en retrouve dans mon code (tout particulièrement) ou celui de mes collègues.

S’il vous plait, n’utilisez JAMAIS de valeurs magiques dans votre code. Lorsque vous utilisez un chiffre, une chaîne de caractères ou toutes autres valeurs ces derniers ont obligatoirement une signification. Créez une variable expliquant cette signification! Deux avantages :

  • Vous améliorez la lisibilité
  • Vous facilitez la ré-utilisabilité et donc la maintenance

Exemple:

// calcul d'une taille en Ko

double sizeInKo = sizeInOctet / 1024;
/*
* Préférez 
*/
public static final int OCTET_IN_KILO_OCTET = 1024
double sizeInKo = sizeInOctet / OCTET_IN_KILO_OCTET;

Si demain vous souhaitez passer de 1024 à 1000 octets par Ko dans la conversion. Vous n’avez qu’à changer la valeur de la variable et cela impactera directement l’ensemble de ses utilisations.

Autre argument, si vous définissez une constante NUMBER_ARTICLE_PER_PAGE = 5. Il y a fort à parier qu’il soit plus simple de rechercher le nom de la constante que la valeur 5 dans l’ensemble du code.

Conventions de nommage

Le nommage de certains éléments sont soumis à des conventions. Prenons les noms de classes ou de variables, ces derniers doivent de préférence être des noms et vous devez éviter l’utilisation des verbes . Par exemple :

public class Consumer{
    private int age;
    private String firstName;
}

Les méthodes/fonctions effectuent des actions, il est donc préférable de décrire cette action par un verbe par exemple:

  • deletePage
  • saveDocument
  • editUser

Conformément au standard des beans java, les noms de méthodes d’accès aux données commence par set, get ou is (pour les booléens).

public class Consumer{
    private int age;
    private boolean male;
    private String firstName;

    private String getFirstName(){
        return this.firstName;
    }

    private String setFirstName(String newFirstName){
        return this.firstName=newFirstName;
    }

    private String isMale(){
        return this.male;
    }
}

Il existe d’autres conventions de nommage qui dépendent du langage utilisé, la liste suivante correspond à ce que j’utilise en Java :

  • Les noms de classes, interface, énumération, méthodes et variables peuvent être composés de plusieurs mots séparés par des majuscules (nomDeVariable)
  • Les noms de classes, interfaces et énumération commencent par une majuscule (MaClasse)
  • Les noms de méthodes et variables commencent par une minuscule (nomDeMéthode)
  • Les nom de constantes sont en majuscules avec des underscores entre les mots (UN_NOM_DE_CONSTANTE)

Établir des règles de code

Pour améliorer la lisibilité du code au sein d’une entreprise, il faut définir des règles communes de code. Si chacun à ses propres règles, la lisibilité du code en sera grandement affectée. Voici quelques exemples possibles de règles:

  • accolade en bout de ligne ou à la ligne suivante
  • convention de nommage
  • longueurs maximales indicatives des lignes, méthodes et classes

J’encourage vivement à ne pas établir trop de règles, plus il y en a, plus il sera difficile de les faire appliquer. Il est beaucoup plus efficace de se concentrer sur les principaux critères de mise en forme du code, et de laisse les moins importants au choix du développeur.

Pour vous faciliter la tâche, il est possible d’utiliser les outils de formatage de votre IDE favori. La plupart d’entre eux proposent cette fonctionnalité, un simple fichier permet de partager (et de forcer) automatiquement les bonnes pratiques à vos collègues.

1 mot = 1 concept

Le plus simple pour ce point est de donner un exemple.

Concrètement, lorsque vous faites de la récupération de valeur (accesseurs ou autres) il faut éviter d’avoir des méthodes qui dans différentes classes utilisent indifféremment les mots get, fetch ou retrieve. Il faut en choisir un et s’y tenir. Un autre exemple courant est l’utilisation des mots Controller, Manager ou Driver. Ces trois derniers sont utilisés dans des contextes généralement proches.

Pour finir : RELISEZ VOUS !

Il faut toujours relire le code que vous avez modifié/créé avant  de le pousser votre dépôt. Cela permet de vérifier que votre code est compréhensible, de vérifier l’application des bonnes pratiques de l’entreprise parfois même de se rendre compte d’erreurs (et donc de bug).

L’analogie que j’aime faire est :

Vous relisez les mails à destination des clients, de vos responsables  ou de vos collègues, pourquoi pas votre code? Le code à les même destinataire, vos collègues qui le modifieront, vos responsables à qui vous rendez des comptes et à votre client qui recevra probablement les binaires!

Une meilleure qualité de rédaction de code améliore la qualité générale des sources et donc diminue mécaniquement le nombre de bug, ainsi tout le monde est content!

NB : Avec ce dernier point, je sais pertinemment que si j’ai le malheur de laisser des fautes, je vais me prendre la remarque ;).

Bibliographie :

  • Clean Code de Robert C. Martin
  • Effective Java de Joshua Bloch

Partager l'article :

Facebooktwittergoogle_plusredditlinkedinmail
 

3 commentaires

  1. Aurélien Répondre

    Bonjour,

    Une autre alternative aux nombres magiques est de les encapsuler dans une fonction utilitaire, du genre:

    double sizeInKo = toKBytes(sizeInOctet);

    (A noter qu’en anglais on parle plutôt de byte que d’octet => Kb au lieu de Ko)

    Mais ça reste fragile car rien ne distingue un int en byte d’un autre int en KByte. Pour cela introduire un nouveau type permet d’avoir un code plus robuste et clean à la fois (C++):

    ByteSize size1 = ByteSize::fromBytes(1024 * 10);
    ByteSize size2 = ByteSize::fromKb(10);
    assert(size1 == size2); // ok
    assert(size1.toKbytes() == size2.toBytes() * 1024); // ok

    Auquel cas, encapsuler la valeur magique directement dans l’implémentation de la fonction me parait acceptable:

    class ByteSize {
    public:
    int toKbytes() const {
    return this->m_sizeInBytes / 1024;
    }
    private:
    int m_sizeInBytes = 0;
    };

    Rappelons-nous du crash de Mars Climate Orbiter à cause d’un mélange d’unités dans le code: épargnons les pauvres sondes spatiales qui nous ont rien fait !

  2. Wodric Auteur de l’articleRépondre

    HI Aurélien,

    Dans l’exemple que je donne ta solution est plus intéressante. Elle clarifie le code et évite les erreurs de conversion. Elle n’est valable que dans certains cas. Par exemple, si la constante à un sens purement fonctionnelle.

    Je vais voir pour rajouter cet exemple à l’article.

    Merci pour ton retour !

  3. Ping : Veille du 18 avril 2016 – 10mentionBlog 2016

Vous aussi participez, laissez un commentaire