Normes de programmation
Largement inspiré de
MARTIN, Robert C., «Clean Code: A Handbook of Agile Software Craftsmanship», Pearson Education, 2008, 464 p.
Les commentaires
Les commentaires sont presque toujours néfastes. Pourquoi?
- ils décrivent souvent des évidences, généralement plus mal que le code lui-même
- ils vieillissent mal (mettez-vous à jour les commentaires chaque fois que vous modifiez du code?)
- ils déchargent la conscience du programmeur paresseux qui ne veut pas nettoyer son code («mon code est incompréhensible, je l’expliquerai donc par un commentaire… tant pis pour celui qui devra modifier mon code.»).
Alors que faire?
Plutôt que commenter du code obscur, clarifiez-le!
- Utilisez des variables au nom significatif
- Découpez vos algorithmes en plusieurs petites fonctions au nom significatif
- Utilisez des constantes plutôt que des libellés
Considérez l’exemple suivant; pouvez-vous comprendre tout ce qui s’y passe? :
import java.lang.Math; class np{ public static int nbNp(int n) { int[] premiers; premiers = new int[n]; for (int i = 2; i <= Math.sqrt(n); i++) { if (premiers[i] == 0) { for (int j = i*i; j < n; j+=i) { premiers[j] = 1; } } } int nbNP=0; for (int i = 2; i < n; i++) { if (premiers[i] == 0) { nbNP++; } } return nbNP; } public static void main(String[] args){ System.out.println( nbNp( 1000 ) ); } }
Versus celui-ci qui implante exactement le même algorithme :
import java.lang.Math; class NombresPremiers{ private int[] candidats; private int compte; private final int EST_PREMIER = 0; private final int N_EST_PAS_PREMIER = 1; private final int PLUS_PETIT_NOMBRE_PREMIER = 2; public NombresPremiers( int limiteSupérieure ){ candidats = new int[limiteSupérieure]; trouverNombresPremiers(); compte = compterNombresPremiers(); } public int getCompte() { return compte; } private void trouverNombresPremiers() { int plusGrandFacteurPossible = (int)Math.sqrt(candidats.length); for ( int facteur = PLUS_PETIT_NOMBRE_PREMIER; facteur <= plusGrandFacteurPossible; facteur++ ) { siPremierÉliminerLesMultiplesDe( facteur ); } } private void siPremierÉliminerLesMultiplesDe( int facteur ){ if ( candidats[ facteur ] == EST_PREMIER ) { éliminerLesMultiplesDe( facteur ); } } private void éliminerLesMultiplesDe( int facteur ){ for ( int j = 2; j*facteur < candidats.length; j+=1 ) { candidats[ j*facteur ] = N_EST_PAS_PREMIER; } } private int compterNombresPremiers() { int nbNombresPremiers = 0; for ( int i = PLUS_PETIT_NOMBRE_PREMIER; i < candidats.length; i++ ) { if (candidats[ i ] == EST_PREMIER) { nbNombresPremiers++; } } return nbNombresPremiers; } public static void main( String[] args ){ System.out.println( new NombresPremiers( 1000 ).getCompte() ); } }
Si vous devez absolument écrire un commentaire (honte à vous!) :
- Sur sa propre ligne, juste avant le code commenté
Le commentaire est comme un panneau routier; il nous met en contexte sur ce qui s’en vient et non sur ce qui est déjà passé.
- Indenté avec le code qu’il commente
Les commentaires font partie intégrante du code, évitez d’en défaire la structure.
- / seulement, pas de /* *
Vous trouvez que c’est trop long de mettre deux caractères devant chaque ligne? C’est parce que vous avez trop de commentaires. Clarifiez plutôt votre code.
- Jamais de code commenté
Le temps de faire des expérimentations, d’accord mais ne commitez jamais de code commenté. Qui aura la responsabilité de le supprimer définitivement? Vous ne perdrez pas l’«ancienne version» de votre code tant que vous utilisez un gestionnaire de sources.
- Pas d’historique des modifications en commentaire
Utilisez un gestionnaire de sources.
- Pas de commentaires redondants
Et quel commentaire n’est pas redondant?
Évitez des choses comme :
//initialise la variable début à 0 début=0;
Tout programmeur comprend le code sans lire le commentaire.
- Pas de discussion ni de «Todo» dans le code
Utilisez plutôt les outils de gestion de projet comme Gitlab.
Privilégier les fonctions et les noms significatifs
Pourquoi faire :
//Fonction qui retourne la racine carrée d'un nombre réel public double rc(double p)
Lorsqu’on peut faire :
public double racineCarrée(double opérande)
Ne commentez pas le code obscur, rendez-le clair!
Pas de décorations
À moins d’avoir un commentaire qui doit absolument être lu plus que n’importe quoi d’autre
// Ceci est bien joli, mais ce n'est pas nécessaire ///////////////////////////////////////////////////////////// // Variables // ///////////////////////////////////////////////////////////// int a; // Acceptable /****************************************************************** = Cette ligne doit être conservée à cause d'un bogue du compilateur = Voir https://compil.com/bugs/123456 ******************************************************************/ init_device(null);
Commentaires acceptables :
- Documentation des API publiques
- Les choix non triviaux
- Licences et citation d’auteur
La documentation
Dans un répertoire «doc»
- En format texte le plus possible afin de pouvoir les versionner
- Schémas dans un format standard (jpeg, pdf, etc.)
Javadoc
- Uniquement pour les API publiques
- Ne pas documenter les méthodes triviales (par exemple accesseurs/mutateurs). Le générateur de javadoc fait ça automatiquement
- Ne pas mettre de HTML
La documentation est faite d’abord et avant tout pour être lue dans le code. Le HTML rend la lecture pénible.
La nomenclature
- Utilisez des noms significatifs aussi longs que nécessaires.
- Les noms de variable courts sont acceptables dans des algorithmes courts
Les blocs
- Indenter avec un caractère TAB (pas d’espaces) en début de ligne
L’indentation n’est pas une décoration mais un symbole sémantique. Aussi, il doit être représenté par un symbole standard. Le caractère TAB permet la consistance à travers le code tout en permettant à chacun de choisir la largeur d’une indentation.
- Toujours mettre les accolades (pas d’exceptions)
Ne faites pas
if (condition) return 9;
Faites plutôt
if (condition) { return 9; }
- Les accolades ouvrantes sont en fin de ligne après une espace
- Les accolades fermantes sont seules sur leur ligne (sans commentaires de fin de ligne)
Exemple :
public double racineCarrée(double opérande) { if (opérande<0) { throw new IllegalArgumentException(...); } return ...; }
- Jamais de bloc sur une seule ligne
//À éviter if (a == 0){ return -1; }
Les comparaisons
- Privilégier le sens naturel de la comparaison :
if ( test <= 0 )
et non
if ( 0 > test )
- Placer la constante devant la variable est acceptable uniquement avec l’égalité et pour les langages où l’affectation est une expression :
if ( 0 == test )
afin d’empêcher l’erreur courante :
if ( test = 0 )
Les lignes
- Longueur max : 120 caractères
Personne ne veut «scroller» vers la droite…
- Pas de blancs inutiles à la fin de la ligne
- Pas de lignes vides à la fin du fichier
- Si nécessaire, séparer une instruction sur plusieurs lignes en alignant les paramètres
int a=fonctionAvecPlusieursParamètres( "Jean", "Tremblay", "Saguenay", 42, 0 );
- Une seule instruction par ligne
- Une seule affectation par ligne À éviter
int a,b,c; a = b = c = 0;
L’espacement
vertical
- Pas d’espacement directement après les accolades ouvrantes ou directement avant les fermantes.
- Une et une seule ligne vide entre deux déclarations de fonction
- On peut utiliser une ligne vide pour séparer les «paragraphes» d’un algorithme.
horizontal
- les espaces sont
- obligatoires autour des affectations
a = 0;
- obligatoires autour des opérateurs de comparaison
if (a < 0 ) {
...
}
- facultatives autour des opérateurs arithmétiques (recommandées pour mettre l’emphase sur la priorité
réponse = a+b*c; réponse = a + b*c;
- interdites entre les noms de fonctions et les parenthèses
//non public void maFonction (int param) { return autreFonction (42,22); } //oui public void maFonction( int param ) { return autreFonction(42, 22); }
- obligatoires entre un mot-clé et une parenthèse ouvrante (for, while, catch, etc.)
- obligatoires avant une accolade ouvrante
//non if(a < 0 ){ ... } //oui if (a < 0 ) { ... }
paramètres
Les paramètres sont des variables locales à une fonction et doivent donc suivre les mêmes normes.