Logo Spiria

10 bonnes pratiques pour du code lisible

13 février 2020.

C’est un fait reconnu que le code est lu beaucoup plus souvent qu’il n’est écrit. C’est pourquoi sa lisibilité est essentielle. 

Un jour ou l’autre, quelqu’un lira votre code et essaiera de comprendre quelle est sa finalité. Cette personne pourra même être vous-même… et il est bien possible que vous perdiez du temps à tenter de comprendre ce que vous avez écrit quelques mois plus tôt, parce que ce n’est plus très frais dans votre mémoire et parce que vous n’avez pas accordé suffisamment d’attention à la lisibilité.

J’ai eu l’occasion d’assister à une présentation sur les bonnes pratiques de rédaction de code faite par Jason McCreary (@gonedark). Si rien n’est en soi très révolutionnaire, c’est un ensemble de règles que j’ai trouvé intéressant de partager et qu’il me semble important de garder à l’esprit.

Jason propose une liste de 10 points à garder en tête pour que vous ou le programmeur suivant puisse comprendre facilement et intuitivement votre code. Pensez-y, si votre code est immédiatement compréhensible, il pourrait vous arriver de sauver la fin de semaine d’un collègue en support postproduction, ou celle d’un futur vous-même.

Formater

Il y a plein de normes et de possibilités. Il ne s’agit pas de débattre sur l’indentation par des tabulations ou par des espaces, ou encore des mérites comparés des styles Allman et K&R, mais plutôt de convenir d’une norme (par exemple PSR12) et de s’y tenir. Les “CodeSniffer” et les environnements de développement (IDE) font très bien la détection automatique de violations d’une norme de codage définie et ils permettent de s’assurer de maintenir une base de code propre et cohérente. Soyez rigoureux et consistants.

Code mort

Le code est mort, effacez-le !!! Faites le ménage dans ces blocs commentés, ces variables inutilisées et ce code qui n’est jamais appelé. Voyez votre programme comme un arbre bien entretenu : il y a des moments où il faut couper le bois mort pour favoriser une croissance harmonieuse et éviter les accidents.

Code imbriqué

Si vous respectez le premier point et que votre indentation vous amène à commencer votre ligne en dehors des limites de l’écran, c’est un signe qu’il faut peut-être revoir votre approche. Évidemment les conditions imbriquées sont partie intégrante d’un code, mais, quitte à écrire des sous-fonctions, il faut garder en tête que le programmeur derrière vous n’a pas forcément le diagramme que vous aviez sous les yeux pour écrire vos conditions ! Démêlez le code imbriqué en utilisant des clauses de garde, des retours anticipés ou des aspects de la programmation fonctionnelle.

Utiliser des objects

C’est une remarque un peu plus destinée aux programmeurs PHP, mais elle s’applique à bien d’autres langages. L’idée ici est de privilégier l’utilisation d’objets sur celle des tableaux. L’exemple le plus évident en PHP est l’utilisation de tableaux pour passer un nombre variable de variables.

Gros blocs de code

On le sait tous qu’une fonction de 500 lignes, c’est mal. Alors, n’en faites pas ! Jamais. Si vous traînez déjà un bloc de code atteignant une longueur critique, il est temps de le remanier en un bloc plus lisible et moins complexe.

Dénomination

“foo” est un nom de variable pour les exercices à l’école, pas un pour la vraie vie.

Si la fonction getWeekReport retourne un rapport pour un mois, c’est que ce n’est définitivement pas un bon nom.

Si la fonction getReport retourne uniquement un rapport pour une semaine, elle pourrait judicieusement s’appeler getWeekReport.

Si vous ne trouvez pas le bon nom tout de suite, continuez à coder et revenez-y plus tard. Ce ne doit pas être un bloquant et le nom parfait s’imposera de lui-même plus tard.

Adieu les commentaires

Voilà qui est un peu provocant, mais il faut en fait considérer les points suivants :

  1. Les DocBlocks ne sont pas des commentaires ; on les aime et on en veut.
  2. Si vous avez besoin d’expliquer votre code avec du texte, c’est probablement que votre code est améliorable.
  3. $today = date(); // Set today date. Ceci est un parfait exemple de commentaire non pertinent.
  4. Les commentaires ne sont pas interdits pour autant, par exemple s’ils servent à expliquer une règle d’affaires.
  5. On préfère de loin pas de commentaires du tout à des commentaires erronés !
  6. Au final, peu importe les commentaires, seul le code est exécuté. Seul le code compte vraiment.

Mettez-vous donc au défi de réécrire le code pour qu’il n’ait pas besoin de commentaires.

Valeurs de retour acceptables

Un lecteur doit comprendre facilement ce que la fonction retourne. Certains préfèrent un seul retour dans la fonction. D’autres regroupent par type de retour (par exemple tous les if … return true au début, puis les if return false ensuite).

Idéalement, on doit éviter de pelleter dans le jardin du voisin les cas qui nous embêtent. Comme le return null qui implique que le cas null va probablement devoir être traité ailleurs.

Règle des 3

C’était nouveau pour moi et j’ai trouvé ce principe intéressant. Il s’illustre comme suit :

  • Si je vous demande ce qui vient après “2”, vous pouvez ne pas avoir de réponse. Ce peut être 3 ou 4, ou pourquoi pas 1 ou 2,1.
  • Si je vous demande ce qui vient après “2, 4”, vous avez quelques idées, mais pas de certitude.
  • Si je vous demande ce qui vient après “2, 4, 16”, vous pensez certainement à 256.

C’est la règle des 3.

Dans le monde des programmeurs, cela signifie que votre code devrait suivre une logique. Il faut donc éviter les cas où votre code fait “2, 4, 6, 27” ! Votre code est peut-être juste et fait ce qu’il faut, mais c’est totalement contre-intuitif pour le lecteur.

Dans la même approche, si votre code fait “2, 4, call function DonextStep”, ça peut aussi nuire à la lisibilité de votre code. Cela implique de parfois devoir dupliquer votre code. Donc, oui, ça va à l’encontre du DRY... ¯\_(ツ)_/¯

Symétrie

Pour garder ce concept simple, je l’illustrerai en disant que si on a deux fonctions create et update, on s’attend alors à ce qu’elles prennent le même type de paramètres et retournent le même type de variable.

Function update (User user) : boolean success
Function create(User user) : boolean success

Plutôt que :

Function update (int userId, User user) : boolean success
Function create(Array[]) : User user

Si vous souhaitez approfondir ces principes, Jason McCreary a publié BaseCode, un guide dans lequel il développe davantage les différents points et les illustre par de nombreux exemples pratiques (disponible pour 29 $ sur son site). Vous pouvez aussi regarder des screencasts sur sa chaîne YouTube.

Bon code!