Dans cet article, nous allons parler des conventions de codage. Quel est l'intérêt d'en adopter, comment les mettre en place au sein des équipes, et comment vérifier qu'elles sont bien appliquées.
Le code styling, aussi appelé conventions de codage ou simplement règles de codage, désigne un ensemble de règles visant à définir la façon dont le code est rédigé.
Pour les néophytes, ce qu'il faut savoir, c'est que dans la plupart des langages de programmation, il est possible d'écrire les choses de différentes manières : Les sauts de lignes ne sont pas forcément obligatoires, le nombre d'espaces à utiliser n'est pas figé, l'indentation également. Même certains éléments de syntaxes peuvent être équivalents, par exemple le classique n++
(ou n+=1
) qui équivaut à n = n+1
.
Pour illustrer ça plus en détail, prenons en exemple le code python suivant :
import os; from pwd import getpwuid; MY_PATH='/home'
def a( b ): return {getpwuid(os.stat(os.path.join(b, c)).st_uid).pw_name for c in os.listdir( b )} if os.path.exists( b ) else set()
a( MY_PATH )
Celui-ci est totalement équivalent à celui-là :
import os
from pwd import getpwuid
MY_PATH = '/home'
def get_owners_in_directory(path):
"""return a set of all existing owners in a given directory"""
owners = set()
if os.path.exists(path):
for subdirectory in os.listdir(path):
absolute_path = os.path.join(path, subdirectory)
pw_name = getpwuid(os.stat(absolute_path).st_uid).pw_name
owners.add(pw_name)
return owners
get_owners_in_directory(MY_PATH)
C'est presque exactement le même code, il réalise les mêmes opérations. Il est simplement écrit différemment.
Le premier est plus court, plus concis. En revanche, sa lecture est compliquée, l'auteur a décidé de se passer de blocs, les variables et les noms des fonctions sont réduits à 1 caractère. Bref, en ouvrant le code, impossible de comprendre rapidement ce qu'il fait.
Le second est plus détaillé. Les éléments sont bien séparés dans des blocs, des variables intermédiaires sont créées afin de bien détailler l'ensemble des opérations. L'auteur a misé sur la compréhension : un code simple, mais sans doute plus verbeux, et qui tient sur 17 lignes là où le premier tenait sur 3.
Il n'y a pas une seule bonne manière d'écrire du code. Certain se mettront au défi d'écrire le code qui tient sur le moins de lignes possible, là où d'autres préfèrent prendre leur temps, détailler. C'est juste une question de style.
La programmation est un art collectif.
Une application est destinée à être construite par différents développeurs, qui vont ajouter, modifier ou supprimer du code tout au long du cycle de vie du produit.
Comme on l'a vu, chaque développeur va arriver avec son style qui lui est propre.
Afin de garder une cohérence dans le code global de l'application, mais aussi dans le but de faciliter la lecture du code, l'équipe doit partager des règles de codage communes.
Ceci n'a aucune influence directe sur le programme. Que Pierre préfère utiliser une indentation à 2 caractères tandis que Paul préfère utiliser une indentation à tabulation ne changera absolument pas la façon de fonctionner du programme. Et si Jacques a l'habitude d'écrire des lignes de 240 caractères de long, ça ne changera pas non plus la vitesse d'exécution ou le résultat de l'instruction.
Pourtant, avec un code qui mélange les styles des différents développeurs, le risque d'erreur est accru.
Et donc logiquement, adopter un style commun aura pour effet de minimiser le risque d'erreurs. En effet, l'œil va petit à petit s'habituer à un certain niveau d'indentation, à la même logique de bloc, en un mot, au style. En ouvrant le code du voisin, c'est comme si vous étiez chez vous. Vous avez vos habitudes, faites comme chez vous, vous êtes à la maison.
Un exemple assez connu concerne l'utilisation des accolades (pour les langages qui en utilisent) dans les blocs de codes avec une seule instruction. Elles sont souvent facultatives. Le code suivant est correct :
// incorrect
if ($shootsCnt > 3)
doABarrelRoll();
Une seule instruction ⇒ pas d'accolades.
Le problème vient quand un autre développeur veut modifier ce code, pour ajouter une instruction par exemple. S'il est habitué à avoir dans tous les cas des accolades (ou pire, s'il est habitué à changer de langage et qu'il fait un peu de python à côté par exemple), le risque de ne pas voir, à cause de l'indentation, l'absence d'accolades, est important. En conséquence, le développeur risque d'ajouter son instruction directement après le if, en sortant la commande existante du bloc conditionnel.
// shit happens
if ($shootsCnt > 3)
reload();
doABarrelRoll();
Dans ce cas-là, l'instruction doABarrelRoll
sera joué quoi qu'il arrive, ce qui n'est pas le comportement attendu. Pour minimiser ce risque, la plupart des conventions conseillent d'utiliser les accolades même s'il n'y a qu'une seule instruction.
// that's good
if ($shootsCnt > 3) {
doABarrelRoll();
}
Dans les grandes lignes, et de manière non exhaustive, les conventions de code vont regrouper :
let myVar=3
ou let myVar = 3
)Les conventions adoptées par l'équipe feront l'objet d'un document qui les illustrera avec des exemples. Ce document sera inclus au projet ou à la documentation de l'équipe.
En premier lieu, il faut que l'équipe adhère à l'idée de la nécessité d'adopter un style guide. Cela n'ayant aucun effet sur le code, certains développeurs peuvent le vivre comme une contrainte. Expliquer les enjeux et les illustrer par des problèmes réellement rencontrés dans le passé est une bonne manière de faire.
Ensuite, il faut regarder si, pour le langage ou le framework utilisé, des conventions de code sont déjà suggérées.
En python, par exemple, la PEP 8 fait presque l'unanimité.
Le monde javascript n'ayant pas adopté de conventions au niveau du langage, la plupart des frameworks vont proposer leurs style guides dans leurs documentations. C'est le cas, par exemple, de Vue.js, qui propose son propre style guide.
Ces documents vont servir de point de départ à l'équipe. Celle-ci doit ensuite s'accorder sur les règles à suivre ou à ne pas suivre, introduire des règles plus spécifiques ou adapter le style en fonction de la réalité des problématiques rencontrées.
Par exemple, la PEP 8 indique qu'une ligne devrait faire au maximum 79 caractères. Cette préconisation date d'une époque où les écrans étaient moins larges qu'aujourd'hui, et la plupart des équipes montent jusqu'à 100 voir 120 caractères par lignes. L'objectif derrière cette règle étant que l'entièreté du code soit visible lorsqu'on ouvre deux documents côte à côte, sans avoir besoin de faire du scrolling horizontal.
Même les grands projets suivant la PEP 8 vont publier leurs propres règles. Voir par exemple le coding style de Django.
Enfin, dernier point : il peut arriver localement de passer outre une règle des conventions de code. C'est tout à fait normal, et parfois, il vaut mieux transgresser une règle plutôt que chercher à l'appliquer à tout prix, si cela doit se faire au détriment de la lisibilité du code.
Une fois qu'on s'est entendu sur le style à adopter, il est important de vérifier qu'il est appliqué. Il existe des outils spécialisés, en particulier pycodestyle pour le code python, qui s'assure que les règles sont bien respectées.
Cet outil permet de personnaliser les règles à appliquer dans le fichier de configuration du projet (ici setup.cfg
)
[pycodestyle]
max-line-length = 120
statistics = True
Voici par exemple ce que retourne pycodestyle quand on le lance contre le premier snippet de code de cet article :
(venv) ➜ ~ pycodestyle snippet.py
snippet.py:1:10: E702 multiple statements on one line (semicolon)
snippet.py:1:36: E702 multiple statements on one line (semicolon)
snippet.py:1:45: E225 missing whitespace around operator
snippet.py:2:7: E201 whitespace after '('
snippet.py:2:9: E202 whitespace before ')'
snippet.py:2:80: E501 line too long (132 > 79 characters)
snippet.py:2:94: E201 whitespace after '('
snippet.py:2:96: E202 whitespace before ')'
snippet.py:2:118: E201 whitespace after '('
snippet.py:2:120: E202 whitespace before ')'
snippet.py:3:1: E305 expected 2 blank lines after class or function definition, found 0
snippet.py:3:9: E201 whitespace after '('
snippet.py:3:17: E202 whitespace before ')'
Il existe également des intégrations dans les IDE qui vont analyser le code à l'enregistrement et souligner les erreurs. C'est un des meilleurs moyens d'apprendre. Au bout d'un moment, on anticipe les erreurs et on se met à coder directement de la manière attendue.
Il est important d'effectuer une analyse au moment de réaliser le commit, pour être certain de ne pas pousser du code invalide. Mais nous y reviendrons lorsque nous aborderons les hooks de pré commit.
Enfin, l'objectif étant de maximiser la lisibilité, les outils ne peuvent suffire. La revue de code sera une bonne manière de s'assurer qu'on est dans l'esprit des conventions de code. Mais là aussi, nous y reviendrons.
Dans le prochain article, nous parlerons de code linting. J'aurais pu faire un article pour regrouper les deux thématiques, mais j'ai estimé que c'était suffisamment différent pour scinder ça en deux parties.
2022 - tominardi.fr