En revue, une remarque : « utilise plutôt addEventListener ». Et la réponse,
que j’entends chaque année :
Mais ça marche.
Elle est vraie. C’est même, à ce stade, la seule chose que vous puissiez vérifier. Vous avez écrit le code, vous avez cliqué, le menu s’est ouvert.
Le problème n’est pas que ce soit faux. C’est que ça ne dit rien de ce qui n’est pas encore arrivé.
Ce n’est pas une question de style
Il faut évacuer tout de suite la version paresseuse de cette discussion, celle où l’on vous répond « c’est plus propre ». Elle ne vous apprend rien, elle vous demande d’obéir, et vous avez raison de ne pas vous en contenter.
Ce qu’on vous dit en réalité est bien plus précis, et ce n’est pas un reproche sur votre code :
« Ça marche » est une preuve à un seul cas. Vous avez lancé le programme une fois, tout seul, dans les conditions exactes où vous venez de l’écrire. C’est un échantillon de taille 1. Ce n’est pas rien — c’est même nécessaire — mais c’est la forme de preuve la plus faible qui existe.
La bonne question n’est donc pas est-ce que ça marche, à laquelle vous avez déjà répondu. C’est :
Qu’est-ce qui devrait arriver pour que ça cesse de marcher ?
Le cas onclick
Voyons ce que cette question donne sur l’exemple.
// Votre fichier, semaine 3
bouton.onclick = () => ouvrirLeMenu();
Ça marche. Trois semaines plus tard, quelqu’un d’autre — un camarade, une bibliothèque, ou vous-même dans un autre fichier — ajoute un comportement sur le même bouton :
// Un autre fichier, semaine 6
bouton.onclick = () => fermerLaBanniere();
Le menu ne s’ouvre plus.
Prenez la mesure de ce qui vient de se passer : il n’y a aucune erreur. Pas
d’exception, pas d’avertissement, la console est vide. onclick est une
propriété : la seconde affectation a simplement écrasé la première, exactement
comme x = 2 après x = 1. Le comportement précédent n’a pas échoué, il a
disparu.
C’est le mode de panne le plus coûteux qui soit, et vous l’avez déjà rencontré dans l’article sur le cycle des frameworks : le système continue de fonctionner en étant cassé.
addEventListener ne se comporte pas ainsi. Il empile : deux appels, deux
écouteurs, les deux s’exécutent. Il permet aussi d’en retirer un seul
(removeEventListener), ou de poser des options — écouter une seule fois, ne
pas bloquer le défilement. Autant de choses que la propriété onclick ne sait
pas faire, parce qu’elle n’a qu’une case.
Le domaine de validité
Maintenant, la partie que la version « c’est plus propre » vous cache, et qui est la seule intéressante.
onclick n’est pas une erreur. Il a un domaine dans lequel il est
parfaitement valable, et ce domaine se nomme précisément : un seul écouteur, un
seul propriétaire de l’élément, aucun besoin de le retirer.
Dans votre TP de première année, seul sur votre page, onclick était le bon
choix : plus court, plus lisible, et la condition était respectée. Personne ne
vous a menti.
Toute solution a un domaine de validité de ce genre. Le problème n’apparaît que lorsqu’on en sort — et on en sort presque toujours par la même porte : quelqu’un d’autre arrive. Un binôme, une bibliothèque, un projet qui grossit, vous-même six mois plus tard.
D’où la formulation qui, je crois, vaut mieux que tous les rappels à la convention :
La faute n’est pas d’avoir choisi onclick. C’est de ne pas savoir qu’on a
choisi.
graph TD
E[Vous écrivez le code] --> T[Vous l'essayez une fois :
ça marche]
T --> Q{Qu'est-ce qui devrait arriver
pour que ça casse ?}
Q -->|vous savez répondre| C[Vous avez choisi]
Q -->|vous ne savez pas| H[Vous avez deviné]
class C ok
class H alerteC’est une exigence beaucoup plus petite que « écrire du code propre », et beaucoup plus atteignable : on ne vous demande pas d’être parfait, on vous demande de connaître la frontière de ce que vous venez de construire.
Et pour celui qui relit
La symétrie vaut d’être dite, parce qu’elle vous servira des deux côtés de la revue.
Si vous êtes celui qui fait la remarque, « c’est la convention » est une réponse faible — c’est justement celle qui déclenche le « mais ça marche ». La réponse forte est le scénario de panne : le jour où quelqu’un ajoutera un second écouteur sur ce bouton, le tien disparaîtra sans erreur. Elle est vérifiable, elle s’apprend, et elle ne demande à personne de faire confiance.
Un principe est une question déguisée, et une convention se défend par le cas qu’elle évite. Si personne autour de la table n’est capable de produire ce cas, il est légitime de demander si la convention s’applique ici.
Cela dit, l’inverse mérite d’être entendu aussi. Une convention est souvent l’option dont le domaine de validité est le plus large — et c’est exactement pour cette raison qu’elle fait un bon choix par défaut, y compris quand personne ne sait produire aujourd’hui le scénario qui vous ferait tomber. Choisir l’option la plus large quand on n’a pas de raison de faire autrement n’est pas de la superstition : c’est reconnaître qu’on ne connaît pas l’avenir du fichier.
Trois exemples, du plus doux au plus sérieux
| Le code | Ça marche jusqu’à… |
|---|---|
onclick au lieu de addEventListener | qu’un second écouteur existe |
| l’état stocké dans le DOM | qu’un second affichage existe |
innerHTML = saisieUtilisateur | jamais |
Le dernier demande une explication, et c’est lui qui compte le plus.
Injecter directement dans innerHTML du texte saisi par un utilisateur
fonctionne parfaitement. Ça a toujours marché, ça marchera toujours, et aucun
scénario ne le fera « cesser de marcher ». C’est aussi la façon la plus commune
d’ouvrir une faille de sécurité dans une page web : ce que vous insérez peut
contenir du code, et ce code s’exécutera chez vos visiteurs.
Ce cas-là démolit définitivement l’idée qu’on pourrait classer le code sur une seule échelle allant de « ça marche » à « c’est propre ».
« Ça marche » et « c’est correct » ne sont pas deux degrés. Ce sont deux axes différents. Un programme peut marcher parfaitement et être dangereux, comme il peut être élégant et faux.
Ce qu’il faut en retenir
Rien de ce qui précède ne vous demande d’abandonner « ça marche ». C’est le premier critère, et il reste nécessaire : un code qui ne marche pas n’a aucune qualité que sa beauté puisse racheter.
On vous demande seulement d’y ajouter une seconde question, qui coûte dix secondes :
Qu’est-ce qui devrait arriver pour que ça cesse de marcher ?
Si vous savez répondre, vous avez fait un choix — et vous pouvez le défendre en revue, y compris contre votre relecteur. Si vous ne savez pas, vous avez deviné, et ça a marché.
Ce n’est pas la même chose, et c’est à peu près toute la différence entre quelqu’un qui débute et quelqu’un dont on peut relire le code sans l’interroger.