let message : string = 'Hello world!'
let maxNumberOfWords = 15
function writeLine(line : string) {...}Amélioration de la lisibilité du code
Étienne André etienne.andre@univ-nantes.fr
Any fool can write code that a computer can understand. Good programmers write code that humans can understand.
Programs must be written for people to read, and only incidentally for machines to execute.
Introduction
Conventions de codage
Nommage de variables et de fonctions
Éviter des mauvaises interprétations
Esthétique
Commentaires
Simplification du flot de contrôle
Conclusion
Degré pour lequel un système, un composant ou un processus répond aux besoins spécifiés.
utilisateurs, développeurs, gestionnaires, etc.
robustesse, efficacité, portabilité, maintenabilité, etc.
Ici, nous nous intéressons au point de vue des développeurs et à la maintenabilité du code.
concision, cohérence, modularité, simplicité, documentation interne.
Plus le code est simple à lire, plus il est maintenable.
Le code doit réduire le temps de lecture et compréhension pour les autres développeurs.
Introduction
Conventions de codage
Nommage de variables et de fonctions
Éviter des mauvaises interprétations
Esthétique
Commentaires
Simplification du flot de contrôle
Conclusion
N’importe quelle chaîne de caractères alphanumériques est un identifiant valide.
Pas universel : Java, OCaml, etc., imposent des règles sur la casse de la première lettre de l’identifiant
Proposées par les créateurs du langage ou par la communauté de développeurs.
Pour assurer la cohérence, chaque projet ne doit adopter qu’une seule convention.
Utiliser la même convention à l’intérieur d’un projet est plus important qu’adopter la « meilleure » convention.
Les variables et les fonctions utilisent le camelCase : on utilise les majuscules pour séparer les noms composés :
Nom souhaité | camelCase |
"nom de famille" |
|
"a réussi l’examen" |
|
Conseillé :
let message : string = 'Hello world!'
let maxNumberOfWords = 15
function writeLine(line : string) {...}Déconseillé :
let MESSAGE : string = 'Hello world!'
let max_number_of_words = 15
function WriteLine(line : string) {...}En TypeScript, les Types utilisent le PascalCase : la première lettre de chaque mot est en majuscule :
| Nom souhaité | PascalCase |
|---|---|
"nom de famille" |
|
"a réussi l’examen" |
|
Conseillé :
type LabelledValue {...}
type Point3D {...}
type GraduateStudent {...}Déconseillé :
type Labelled_Value {...}
type POINT3D {...}
type graduatestudent {...}Il peut être intéressant de mettre les noms des constantes globales en majuscules (Screaming Snake Case)
const ANNEE_FONDATION : number = 2022
console.log(`Nantes Université a été fondée en ${ANNEE_FONDATION}`);kebab-case-looks-like-this
max-parallel-eventssnake_case_looks_like_this
another_variable_nameALSO_KNOWN_AS_UPPER_CASE_EMBEDDED_UNDERSCORE
COMMONLY_REFERS_TO_CONSTANTSIntroduction
Conventions de codage
Nommage de variables et de fonctions
Éviter des mauvaises interprétations
Esthétique
Commentaires
Simplification du flot de contrôle
Conclusion
par exemple a, b, f.
Petite portée, noms courts.
Large portée, noms longs.
const maximumNumberOfActiveThreads : number = 8;ou
const MAXIMUM_NUMBER_OF_ACTIVE_THREADS : number = 8;function sumArray(values : number[]): number {
let sum: number;
for (let each of list) {
sum = sum + each;
}
return sum;
}
Les noms des identifiants doivent être précis.
par ex. une fonction qui calcule la taille d’un arbre :
function size(tree: Tree): number {
//(...)
}De quoi s’agit-il ? De la hauteur ? Du nombre d’éléments ? De l’empreinte mémoire ?

Alternatives :
function height(tree: Tree): number {}
function numberOfNodes(tree: Tree): number {}
function footprint(tree: Tree): number {}Les identifiants génériques tels que tmp, aux ou retval veulent souvent dire :
— Je ne sais pas comment appeler ma variable !
function euclideanNorm(values: number[]): number {
let retval: number = 0;
for(let i : number = 0; i < values.length ; i+=1) {
retval += values[i] * values[i]
}
return Math.sqrt(retval);
}Le code précédent est lisible, mais l’identifiant de la variable (retval) n’apporte aucune information.
Maintenant, supposons que le développeur ait remplacé par erreur * par + :
retval += values[i] + values[i]sumOfSquares += values[i] + values[i]Quelle erreur est la plus visible ?
tmp désigne vraiment une valeur temporaire : if(begin > end) {
let tmp: number = end;
end = begin;
begin = tmp;
}Parenthèse : peut-on échanger la valeur de deux nombres sans passer par une variable temporaire ?
Oui :
a = a + b;
b = a - b;
a = a - b;Traditionnellement, les identifiants i, j et k désignent des itérateurs de boucle :
for(let i : number = 0; i < 10; i+=1) {
for(let j : number = 0; j < 20; j+=1) {
for(let k : number = 0; k < 40; k+=1) {
// instructions
}
}
}Parfois, ajouter l’unité de mesure simplifie la lisibilité.
par ex. la fonction wait(delay) :
function wait(delay: number){}De quelle unité de temps s’agit-il ? Secondes ? Millisecondes ?
Alternative :
function wait(delayMilliseconds: number){}Considérez par exemple :
let start: number = now();
treatmentThatTakesTime();
let elapsed = now() - start;
console.log("The execution took " + elapsed.toString() + "seconds")Et :
let startMilliseconds: number = now();
treatmentThatTakesTime();
let elapsedMilliseconds = now() - startMilliseconds;
console.log("The execution took " +
elapsedMilliseconds.toString() + "seconds")Lequel des deux morceaux de code révèle plus facilement l’erreur ?
| Identifiant | Identifiant enrichi |
|---|---|
|
|
|
|
|
|
Introduction
Conventions de codage
Nommage de variables et de fonctions
Mauvaises interprétations
Esthétique
Commentaires
Simplification du flot de contrôle
Conclusion
Certains identifiants sont source de confusion.
Par exemple :
results = filter(clients, "birthyear > 2000")Les clients nés après l’année 2000 ?
Ou le contraire ?
Si premier cas : select() est un meilleur nom.
Si deuxième cas, reject() ou exclude() ?
Utilisez min et max pour les limites
Supposez que vous souhaitiez limiter à 24 le nombre d’articles dans un panier et que vous déclariez la constante suivante :
const tooManyCartItems: number = 24;Le problème ici c’est que l’on ne peut pas dire s’il s’agit une limite inclusive ou non. Est-ce que le panier peut avoir 24 articles ou non ? |
const maxNumberOfCartItems: number = 24;Ici, la limite est clairement inclusive.
Utilisez first et last, plutôt que start, stop, pour les intervalles inclusifs :

Parfois, il est utile d’utiliser des intervalles inclusifs/exclusifs
Par exemple, ils est plus simple d’écrire :
todayEvents = eventsInRange("22/1/2018 00:00", "23/1/2018 00:00")que
todayEvents = eventsInRange("22/1/2018 00:00", "22/1/2018 23:59")Dans ces cas, utilisez begin et end pour les intervalles inclusifs/exclusifs :

Traditionnellement, les identifiants booléens sont précédés par is, has ou need(s) pour éviter l’ambiguïté.
let readPassword: boolean = true;Est-ce que la variable dit que le mot de passe a été lu, ou qu’il doit être lu ?
let isAuthenticated : boolean = true;
let needPassword : boolean = true;Introduction
Conventions de codage
Nommage de variables et de fonctions
Éviter des mauvaises interprétations
Esthétique
Commentaires
Simplification du flot de contrôle
Conclusion
No matter how slow you are writing clean code, you will always be slower if you make a mess.
Un programme bien formaté est plus lisible qu’on programme mal formaté.
function pgcd(a: number, b: number): number
{
while (a!=b){
if (a>b){ a-=b ;}
else {b-=a;}
}
return a;}function pgcd(a: number, b: number): number
{
while (a!=b){
if (a>b){ a-=b ;}
else {b-=a;}
}
return a;}// Calcul du plus grand commun diviseur de
// deux entiers
function pgcd(a: number, b: number): number {
while (a != b) {
if (a > b) {
a = a - b;
}
else {
b = b - a;
}
}
return a;
}Sans :
title = request.POST.get('title')
email = request.POST.get('email')
location = request.POST.get('location')
email = request.POST.get('email')
url = request.POST.get('url')
details = request.POST.get('details')Avec :
title = request.POST.get('title')
email = request.POST.get('email')
location = request.POST.get('location')
email = request.POST.get('email')
url = request.POST.get('url')
details = request.POST.get('details')function validateEmail(email: Email): string {
let error:string="";
let tfl:string = email.value.trim();
let emailFilter:RegExp = /^[^@]+@[^@.]+\.[^@]*\w\w$/ ;
let illegalChars:RegExp = /[\(\)\<\>\,\;\:\\\"\[\]]/ ;
if (email.value === "") {
email.style.background = 'Yellow';
error = "You didn't enter an email address.\n";
} else if (!emailFilter.test(tfld)) {
email.style.background = 'Yellow';
error = "Please enter a valid email address.\n";
} else if (email.value.match(illegalChars)) {
email.style.background = 'Yellow';
error = "The email address contains illegal characters.\n";
} else {
email.style.background = 'White';
}
return error;
}Utilisez les lignes vides pour créer des strophes de code :
function validateEmail(email: Email): string {
const emailFilter : RegExp = /^[^@]+@[^@.]+\.[^@]*\w\w$/;
const illegalChars: RegExp = /[\(\)\<\>\,\;\:\\\"\[\]]/;
let error : string = "";
let tfl : string = email.value.trim();
if (email.value === "") {
email.style.background = 'Yellow';
error = "You didn't enter an email address.\n";
} else if (!emailFilter.test(tfld)) {
email.style.background = 'Yellow';
error = "Please enter a valid email address.\n";
} else if (email.value.match(illegalChars)) {
email.style.background = 'Yellow';
error = "The email address contains illegal characters.\n";
} else {
email.style.background = 'White';
}
return error;
}Quelle version est plus lisible ?
Sans commentaires
function adultOrMinor(age: number): string {
if (age >= 18) {
return "adult";
} else {
if(age <= 3){
return "baby";
}
return "minor";
}
}Avec commentaires
function adultOrMinor(age: number): string {
if (age >= 18) {
return "adult";
} else {
if(age <= 3){
return "baby";
}
return "minor";
}
}Version simplifiée d’un manuel du RER D
1er CAS : Aucun robinet d’arrêt n’est fermé :
Purger la valve
2e CAS : Un robinet d’arrêt est fermé :
Ouvrir le robinet
Dans les 2 cas :
- ouvrir le robinet d’arrêt
- vérifier les freins du dernier véhicule
Remettre le train en marcheSi aucun robinet d’arrêt n’est fermé, le mécanicien doit-il vérifier les freins ?
Version corrigée dudit manuel du RER D
1er CAS : Aucun robinet d’arrêt n’est fermé :
Purger la valve
2e CAS : Un robinet d’arrêt est fermé :
Ouvrir le robinet
Dans les 2 cas :
- ouvrir le robinet d’arrêt
- vérifier les freins du dernier véhicule
Remettre le train en marche| L’erreur d’indentation de ce manuel ferroviaire a causé la mort de 56 personnes à Paris en 1988 |

Certains langages imposent l’indentation comme faisant partie de la sémantique
Exemple
Python
annee = 2026
if annee == 2026:
print("Cette année")…donne une erreur !
IndentationError: expected an indented block after 'if' statement on line 2Introduction
Conventions de codage
Nommage de variables et de fonctions
Éviter des mauvaises interprétations
Esthétique
Commentaires
Simplification du flot de contrôle
Conclusion
Un code bien commenté est plus lisible qu’un code sans commentaires.
| beaucoup commenter ≠ bien commenter ! |
Un code avec trop de commentaires inutiles est souvent plus difficile à lire qu’un code sans commentaires.
// Function declaration
function factorial(num: number): number {
let factorial:number = 1; // Assigns 1 to factorial
let i: number = num; // Assigns num to i
while(i >= 1) { // loops while i >= 1
// assigns factorial with de product of factorial and i
factorial = factorial * i;
i--; // decrements i
}
return factorial; // return factorial
}| Tous les commentaires ci-dessus sont inutiles. |
Ne commentez pas ce qui peut être déduit directement du code.
Ne commentez pas juste pour commenter.
Soyez précis !
Mettez-vous à la place de la personne qui lira votre code :
Anticipez les questions probables
Annoncez les pièges
Donnez une vision d’ensemble (résumé de l’algorithme)
// Total number of active threads for handling requets
const threads: number = 5Un changement du nom de l’identifiant peut remplacer un commentaire :
const numberOfActiveThreads = 5Les « commentaires du réalisateur » sont des informations additionnelles dont seul le développeur dispose :
// I compared the performance several times using from 1 to 20 active
// threads and find out that 5 active threads achieves the best
// performance for 8 cores CPU.
const numberOfActiveThreads = 5;/*
after hours of consulting the tome of google
i have discovered that by the will of unknown forces
without the below line, IE7 believes that 6px = 12px
*/
font-size: 0px;Ce genre de commentaire peut aussi expliquer l’état du code :
// After adding new features for version 3.0 (November 2017), the
// code became fragile. Maybe we should split this function into
// two others, displayRaw() and displayHTML().
function display(){}| Commentaire | Description |
|---|---|
| Mauvais code, mais qui fonctionne |
| Mauvais code, qui ne fonctionne pas |
| À faire |
| Code réservé aux spécialistes |
Les commentaires externes à une fonction s’adressent aux utilisateurs.
Les commentaires internes s’adressent aux autres développeurs.
// Calculates the factorial of a number.
function factorial(num: number): number {
let factorial:number = 1;
let i: number = num;
// A loop has better performance than recursive calls.
while(i >= 1) {
factorial = factorial * i;
i--;
}
return factorial;
}Introduction
Conventions de codage
Nommage de variables et de fonctions
Éviter des mauvaises interprétations
Esthétique
Commentaires
Simplification du flot de contrôle
Conclusion
L’ordre de lecture d’une expression est importante :
if (length > 10)est plus simple à lire que :
if (10 < length)Comme d’autres langages, TypeScript propose un opérateur ternaire (opérateur conditionnel en une seule ligne).
Syntaxe : cond ? a : b (si condition alors a, sinon b)
Dans certains cas, le code est lisible et compact :
timeString = (hour > 12) ? 'pm' : 'am';Mais dans la plupart des cas, le code devient plus complexe :
let isLeapYear: boolean = ((year % 400) === 0) ? true :
(((year % 100) === 0)? false :
(((year % 4) === 0) ? true : false));function adultOrMinor(age: number): string {
if (age >= 18) {
return "adult";
} else {
return "minor";
}
}function adultOrMinor(age: number): string {
return (age >= 18) ? "adult" : "minor";
}L’introduction de variables auxiliaires explicatives (ou constantes) permettent d’améliorer la lisibilité d’une expression complexe.
Ces variables sont souvent plus utiles que les commentaires.
Par exemple, considérez le code C++ suivant :
float _x = abs(x - deviceInfo->position.x) / scale;
int directionCode;
if (0 < _x && x != deviceInfo->position.x) {
if (0 > x - deviceInfo->position.x) {
directionCode = 0x04 /*left*/;
} else if (0 < x - deviceInfo->position.x) {
directionCode = 0x02 /*right*/;
}
}Le même code, sans commentaires, mais avec des variables explicatives :
static const int DIRECTION_CODE_RIGHT = 0x02;
static const int DIRECTION_CODE_LEFT = 0x04;
static const int DIRECTION_CODE_NONE = 0x00;
int oldX = deviceInfo->position.x;
int directionCode
= (x > oldX)? DIRECTION_CODE_RIGHT
: (x < oldX)? DIRECTION_CODE_LEFT
: DIRECTION_CODE_NONE;Souvent, il est recommandé de n’avoir qu’une instruction de retour dans une fonction.
Dans certains cas, comme dans la vérification des paramètres, le retour anticipé simplifie la lecture :
function contains(str: string , substr: string ): boolean {
if (str === null || substr === null) return false;
if (substr === "") return true;
// (...)
}createUser()function createUser(name: string, password: string, birthday: Date): User | undefined {
let newUser: User | undefined = undefined;
if (name !== undefined) {
if (password !== undefined) {
if (birthday !== undefined) {
newUser = {
name: name, password: password, birthday: birthday
};
} else {
console.log('User birthday is undefined');
}
} else {
console.log('User password is undefined');
}
} else {
console.log('User name is undefined');
}
return newUser;
}createUser(), avec retour anticipé d’erreursfunction createUser(name: string, password: string, birthday: Date): User | undefined {
if (name === undefined) {
console.log('User name is undefined');
return undefined;
}
if (password === undefined) {
console.log('User password is undefined');
return undefined;
}
if (birthday === undefined) {
console.log('User birthday is undefined');
return undefined;
}
return {name: name, password: password, birthday: birthday};
}Utilisez les expressions positives plutôt que les négatives.
Préférez :
if (a === b) {
// Cas 1
} else {
// Cas 2
}à :
if (a !== b) {
// Cas 2
} else {
// Cas 1
}Remplacez :
if (<booleanExpression>) {
return true;
} else {
return false;
}Par :
return <booleanExpression>;Par exemple, remplacez :
if (a > b) {
return true;
} else {
return false;
}Par :
return (a > b);=)Qu’affiche ce morceau de code ?
let annee = 2046;
if(annee = 2000){
console.log("An 2000 !");
}else{
console.log("Pas l'an 2000");
}An 2000 !Eh oui, confusion entre le = et le === (ou le ==) 👿
Erreur très classique dans les langages impératifs !
==)Qu’affiche ce morceau de code ?
if(2046 == "2046"){
console.log("Test 1");
}
if(2046 === "2046"){
console.log("Test 2");
}Test 1Explication : le == effectue un transtypage, pas le ===
Utiliser exclusivement le |
Introduction
Conventions de codage
Nommage de variables et de fonctions
Éviter des mauvaises interprétations
Esthétique
Commentaires
Simplification du flot de contrôle
Conclusion
Les commentaires externes doivent expliquer ce que fait une fonction (l’intention).
Les commentaires internes doivent expliquer pourquoi le code a été écrit comme ça (la raison).
Le code source doit être assez clair pour expliquer comment il s’exécute (la manière).
La lisibilité du code a un impact important sur la maintenabilité d’un logiciel.
La lisibilité ne concerne pas seulement la qualité des commentaires :
le choix des identifiants et la simplicité du flot de contrôle sont tout aussi importants.
Let us change our traditional attitude to the construction of programs: Instead of imagining that our main task is to instruct a computer what to do, let us concentrate rather on explaining to human beings what we want a computer to do.
Always code as if the guy who ends up maintaining your code will be a violent psychopath who knows where you live.