11 mars 2020
Pour un code simple
6 minutes de lecture
Au-delà de la syntaxe et des structures, écrire du code n'est pas chose aisée. Cela demande une capacité d'abstraction et de retenue. Plus une personne aura des années d'expériences derrière elle, plus elle sera amenée à retourner à une écriture simple et dépouillé de certaines lourdeurs.
J'aborde dans cet article, la notion de complexité du code et d'abstraction pour essayer de répondre à cette question : comment tendre vers cette forme de simplicité ?
La peur de dupliquer
Un code que l’on répète provoque très souvent chez nous une sorte de malaise. Une petite voix intérieure se fait soudainement entendre, nous incitant à factoriser ce code.
Cadavre exquis
Créer cette abstraction soulage : le code semble plus propre, plus concis et sera facilement réutilisable dans le futur. Seulement voilà, quelques semaines plus tard, un nouveau cas se présente correspondant à 95% au contrat de cette abstraction. Il faut donc ajouter un paramètre et créer un nouveau bloc conditionnel pour le couvrir. Au fil du temps, cette abstraction devient un cadavre exquis, chacun y va de son argument, de sa structure conditionnelle. C’est ce qu’on appelle en anglais une abstraction leak.
La mauvaise abstraction
Créer une abstraction est facile, en créer une bonne est plus difficile. Pourquoi ? L’occasion d'abstraire du code se présente assez tôt : dès qu'il y a répétition. Cependant créer une abstraction à ce stade serait hypothétique, elle se baserait sur des aprioris quant au futur du projet. Une abstraction prématurée se termine souvent en ce cadavre exquis évoqué plus haut.
Il est donc préférable d'en créer en se basant sur des connaissances empiriques et donc à posteriori. N’hésitons pas à dupliquer du code, le laissez évoluer, respirer. Au bout de quelque temps, si cette branche du code se stabilise alors il est envisageable de la factoriser.
Compliqué ne veut pas dire complexe
Le terme compliqué se rapporte à nos capacités à trouver une solution. Ce n'est pas simple certes, mais en analysant, découpant en sous-ensemble, cette difficulté est surmontable.
Lorsque l'on parle de complexité, nous décrivons un ensemble de choses qui semblent liées mais qu'il nous est difficile voire impossible d'anticiper le résultat, d’en comprendre complètement le fonctionnement, la structure ou d’en trouver la finalité. La complexité n’est pas corrélée avec le nombre de lignes de code : un code verbeux peut justement réduire cette complexité en limitant les possibilités d’interaction et ainsi réduire sa complexité.
Une mauvaise abstraction va complexifier du code, en le dupliquant vous risquez seulement de le rendre plus compliqué.
TypeScript pour exemple
Le TypeScript est compliqué car il apporte une difficulté supplémentaire et est souvent plus verbeux. Cependant il tend à rendre le code moins complexe par la suite en permettant de réduire drastiquement les mauvais choix ainsi que les interactions possibles grâce au typage. Utiliser TypeScript c’est comme ouvrir une voie d’escalade : cela demande du temps et de la difficulté pour poser vos points d'ancrage mais cela permettra à tout à chacun d'emprunter la voie en toute sécurité.
De la même manière, écrire des tests permet, en plus de prévenir de régressions, de documenter votre code en montrant des cas d'utilisation précis. S'ils peuvent être compliqués à mettre en place, les tests assurent un cadre sûr à votre projet.
Des notions relatives
Le terme compliqué est souvent relatif : une personne connaissant bien TypeScript trouvera le code plus simple qu’un néophyte. Introduire du TypeScript c'est donc compliquer le code pour certains, le simplifier pour d'autres. Il est donc important de prendre en compte le niveau de son équipe afin de bien placer les curseurs de difficulté.
La complexité, relève quant à elle d'une notion plus absolue : sa représentation mentale est difficilement possible. L’expérience d’une personne pourra difficilement pallier à ce problème, sa capacité d’abstraction peut l'aider mais cela restera très difficile à appréhender. C’est pourquoi il faut toujours garder son code à porter d'une représentation mentale.
La représentation mentale
Garder son code à porter d'une représentation mentale n'est pas facile, voici quelques pistes permettant de la garder dans le rétroviseur.
Être cohérent
Pour faciliter la représentation mentale il est important d’avoir un cadre de travail homogène. C'est pourquoi le respect de standard de code (coding standard) est primordial. Utiliser un outil de formattage comme Prettier permet de garantir une base de code homogène. Il devient alors plus facile de se concentrer sur les vraies difficultés liées à l'architecture d'un projet et de ses abstractions. Mettre en place un linter permet aussi d'assurer cette cohérence.
Au-delà de ces outils d'automatisation, respecter des patterns d'architecture connus dans la structure de son projet le rend plus compréhensible et permet de capitaliser sur de nombreuses ressources disponibles sur Internet.
Une ligne à tout prix
Tout comme le désir d'abstraire, il existe un désir lié à la brièveté du code. Nous sommes souvent amenés à penser qu'écrire moins de code est forcément plus propre. C'est ce que j'appelle le syndrome du « one-liner » : vouloir écrire une opération en une ligne.
Il est facile en JavaScript d’écrire et chaîner des fonctions pour n’avoir qu’une seule ligne, cependant il est préférable d'écrire plus de code et favoriser sa représentation mentale plutôt que de rechercher l'exploit de la ligne. Prenons l'exemple d'un bout de code permettant de passer d'un tableau à un objet ayant comme clés les ids :
const users = [
{ id: 111, name: 'Baptiste' },
{ id: 112, name: 'Adrien' },
]
Voici un code concis traitant cette opération :
const usersMap = users.reduce((obj, item) => ({ ...obj, [item['id']]: item }), {})
Et voici une version plus verbeuse :
const usersMap = {}
users.forEach((item) => {
usersMap[item.id] = item
})
Je vous laisse deviner quelle version présente la représentation mentale la plus claire. Écrire du code ce n'est pas écrire des haïkus :)
Savoir faire machine arrière
Il est normal de s'engager sur une mauvaise abstraction : c'est souvent en la codant qu'on se rend compte de ces limites. Si vous voyez que celle-ci devient périlleuse, n'hésitez pas à rebrousser chemin en remettant les choses à plat.
Il en va de même lorsque vous tombez sur une abstraction développée par une autre personne : si vous devez y ajouter une rustine il est peut-être préférable de la retirer. Si c'est possible, parlez-en avec la personne concernée pour éviter toute confusion. Une mauvaise abstraction ne va pas se bonifier avec le temps, au contraire celle-ci va s'immiscer dans le code et rapidement complexifier le code rendant le retour arrière très difficile.
Être modeste
Notre écosystème est très stimulant, il évolue chaque jour. Se tenir au courant, faire sa veille sont des réflexes importants à avoir. Il n'est donc pas rare d'apprendre de nouveaux concepts, patterns qui peuvent se révéler compliquer à appréhender. Bien souvent lorsque nous apprenons des concepts compliqués, nous voulons les utiliser par la suite. Ce comportement est normal, nous souhaitons avoir une récompense suite à l'effort investi. Mais si nous avons pris autant de temps à appréhender ce concept, est-ce vraiment une bonne idée de l’utiliser ? Ou est-ce pour obtenir cette récompense et flatter son ego ?
Il s’agit donc de bien réfléchir à la pertinence d’introduire du code, est-il compliqué mais justifié car il n’existe pas de moyen plus simple et acceptable ?
Pour finir
Écrire du code clair n'est pas une tâche triviale, cependant en gardant ces quelques idées en tête nous pouvons essayer de réduire cette complexité :
- Évitez les mauvaises abstractions ;
- Créez vos abstractions sur des à posteriori plutôt que des aprioris ;
- N'hésitez pas à faire marche arrière ;
- Gardez le code à porter d'une représentation mentale ;
- Soyez cohérent, modeste et bienveillant !
Voici les quelques articles et thread (en anglais) qui m'ont inspiré sur ce sujet :
- The Wrong Abstraction - https://www.sandimetz.com/blog/2016/1/20/the-wrong-abstraction
- Goodbye clean code - https://overreacted.io/goodbye-clean-code/
- Thread - https://twitter.com/thomasfuchs/status/1236306015169253377
👋