3 points par GN⁺ 2023-07-03 | 1 commentaires | Partager sur WhatsApp
  • En prenant la scène d’un développeur JavaScript avec 10 ans d’expérience en train de lire package.json comme une épreuve de la douleur, le texte montre à quel point la complexité accumulée de l’écosystème tient dans un seul fichier de configuration
  • Des champs comme main, browser, type: module ravivent les vieilles cicatrices de migration liées à JavaScript isomorphe, aux bundles navigateur et à la transition entre CommonJS et ESM
  • Dans scripts, dependencies, devDependencies, s’entremêlent anciennes variantes de lint, watchman, gulp, left-pad, moment.js et problèmes de gestion de paquets comme resolutions
  • eslint, postcss, jest et les outils de build et de test augmentent le coût de maintenance de l’environnement de développement à cause de règles strictes, d’erreurs d’installation spécifiques aux plateformes et de la difficulté de configuration d’ESM et TypeScript
  • Même en voyant node dans engines, la raison de ne pas migrer vers Bun ou Deno est la certitude que la douleur ne disparaîtra pas, mais empirera ; le développeur referme donc le fichier et survit pour l’instant

L’épreuve de lire package.json

  • L’histoire commence lorsqu’un développeur qui utilise JavaScript depuis 10 ans ouvre un fichier package.json sur son ordinateur et doit le lire jusqu’au bout
  • Ce fichier n’est pas un simple fichier de configuration, mais un objet qui fait remonter d’un coup les souvenirs et la douleur vécus dans l’écosystème JavaScript
  • version n’a toujours pas atteint 1.0, et SemVer reste le souvenir désagréable d’une convention qu’on a appris à ignorer depuis longtemps
  • name montre qu’il est impossible d’utiliser le nom souhaité, parce qu’un paquet a déjà été réservé il y a 7 ans par quelqu’un qui ne l’a jamais mis à jour

Les vieilles blessures des modules et du bundling

  • La présence simultanée des champs main et browser révèle les traces de JavaScript isomorphe
  • Le souvenir d’avoir essayé de require le module fs dans un bundle navigateur, ainsi que les hacks utilisés pour le faire fonctionner, reste une expérience pénible
  • type: module renvoie à la migration de require vers import
  • La tentative d’importer réciproquement des modules CommonJS et ESM reste un très grand moment de douleur

La confusion des scripts et des dépendances

  • scripts est le cœur d’un chaos brûlant et douloureux
    • On y trouve des variantes comme lint, lintall, lintfast, lintdiff
    • Exécution en parallèle, arguments peu clairs et double échappement d’arguments au format JSON s’y invitent
    • Même après une migration vers yarn et pnpm, certains sous-commandes continuent d’appeler npm
  • Certains scripts utilisent encore watchman
    • Il faut se souvenir qu’il ne faut pas l’utiliser avec les symlinks, faute de support
    • Le ticket correspondant est ouvert depuis 2015
  • Des scripts basés sur gulp subsistent aussi, et même si on aimerait les remplacer par quelque chose de plus moderne, personne n’ose s’en charger

La liste de paquets qui ravive les traumatismes

  • dependencies contient énormément de paquets, et chacun réactive à sa manière des souvenirs traumatiques
  • left-pad est un minuscule paquet, mais reste dans les mémoires comme le paquet légendaire qui a « cassé tout l’internet »
  • À chaque modification de la liste de dépendances, certains paquets affichent dans la console de longues demandes de dons ou des avertissements de breaking change
  • Le développeur en vient simplement à espérer qu’aucun paquet malveillant ne volera ses secrets ou ne détruira son ordinateur
  • moment.js reste dans les mémoires comme une bibliothèque dotée d’une bonne API, mais internet a jugé qu’elle était trop mutable, trop volumineuse et incompatible avec le treeshaking, si bien qu’il faut désormais migrer vers date-fns
  • Les versions de paquets sont très en retard par rapport à l’état actuel, et une mise à niveau est nécessaire, mais les précédentes expériences d’upgrade laissent présager une grande souffrance
  • resolutions reste une autre douleur choisie pour éviter de mettre à niveau certains paquets

Une autre couche de complexité créée par les outils de développement

  • En regardant devDependencies, il devient difficile de se souvenir d’une époque où seules les non-dev dependencies étaient nécessaires
  • La configuration de eslint est devenue si stricte qu’une petite erreur suffit à faire apparaître des soulignements rouges, et la CI traite les problèmes de lint comme si c’était la fin du monde
    • Cela donne un faux sentiment de sécurité aux ingénieurs juniors de l’équipe
    • Il y a eu de nombreuses disputes sur les règles à activer
    • La douleur augmente à la mesure du nombre de eslint-ignore disséminés dans la base de code
  • postcss n’est pas utilisé directement, mais existe parce qu’une dépendance de dépendance l’exige
    • À chaque tentative de npm install sur une nouvelle plateforme, il provoque d’obscures erreurs de compilation C++
  • jest a commencé comme un runner de tests rapide, mais il est désormais gros et lourd, et dépend de certains paquets Babel
    • Le reste de l’application est transpilé avec une combinaison d’esbuild et de swc
    • Le configurer correctement pour ESM et TypeScript relève d’un « projet scientifique de doctorat » tant c’est difficile
  • De nombreux outils et parseurs interviennent dans la base de code : TypeScript, esbuild, swc, babel, eslint, prettier, jest, webpack, rollup, terser, etc.
  • engines mentionne node, et même en migrant vers Bun ou Deno, la douleur ne s’arrêterait pas ; elle empirerait probablement
  • Après avoir lu jusqu’à la dernière accolade fermante, on referme l’onglet, on reprend son souffle et on se félicite d’avoir, pour l’instant, survécu avec ses mains et son cerveau intacts

1 commentaires

 
GN⁺ 2023-07-03
Commentaires Hacker News
  • Plutôt drôle. J’ai fait du JavaScript pendant environ 18 ans, et j’ai arrêté il y a à peu près 3 ans, donc la plupart des sources d’angoisse de cette liste datent des 10 dernières années
    Il est particulièrement frappant qu’il manque les polyfills, pourtant incontournables si ce texte avait été écrit en 2013. Quelles autres horreurs JavaScript de 2013 ont aujourd’hui presque disparu ? Bon, elles ont certes été remplacées par cette liste amusante
    Mon passage préféré, c’est quand on commence à compter les outils et parseurs qui fonctionnent dans la base de code, puis qu’on pense à TypeScript, esbuild, swc, babel, eslint, prettier, jest, webpack, rollup, terser, et que la douleur devient si grande qu’on ne veut même plus savoir s’il en manque encore

    • Grunt, Gulp, CoffeeScript, les IIFE, undefined écrasé, with, les closures pour imiter les champs privés, les prototypes modifiés, les variables globales implicites, this qui change selon le site d’appel, la coercition automatique de types lors des comparaisons…
      Oui, voilà à quoi ont ressemblé plus de 10 ans de JavaScript
    • D’accord pour les callbacks. Mais quand je regarde mon JavaScript d’il y a 10 ans, la plus grande souffrance, c’était surtout les fausses classes bricolées en modifiant SomeFunction.prototype
      On enveloppait ça dans une fonction anonyme auto-exécutée pour retourner un objet, afin de pouvoir appeler new SomeFunction() ou SomeFunction.actualFunction() comme si SomeFunction était une classe. L’absence de fonctions fléchées pesait aussi lourd : pour lier les événements au scope, on modifiait carrément Function.prototype lui-même pour utiliser .apply(), ou bien on tombait dans un enfer sans fin de .bind(this) dans chaque callback d’événement
    • On développait sur Firefox pour utiliser Firebug, tout en devant prendre en charge séparément ie6, ie7, ie8
    • Il y a aussi eu l’époque où l’on remplaçait les en-têtes par de petites applets Flash afin d’utiliser la police qu’on voulait sans être limité aux polices installées chez l’utilisateur
    • L’enfer des callbacks et l’absence générale de typage étaient énormes
      Aujourd’hui encore, j’ai eu la malchance de rédiger un exercice technique pour une entreprise qui utilise toujours du JavaScript pur, sans Promise ni fichiers de déclaration, et j’avais l’impression de revenir à ma première rencontre avec Node en 2012. L’exigence d’utiliser JavaScript a été contournée avec JSDoc, mais c’était bien pire que dans mon souvenir
  • Chaque fois que je lance un nouveau projet JavaScript — ou plus exactement un projet TypeScript — je suis toujours la même procédure
    Comme c’est généralement du front-end, je choisis React, même si j’aimerais bien essayer Svelte aussi. Pour le bundler, avant c’était create-react-app ou un wrapper autour de Webpack, mais aujourd’hui Vite est la meilleure option grâce à sa configuration légère et à son support des principaux frameworks
    J’installe et configure le compilateur TypeScript, en copiant-collant le plus souvent depuis un template. Je cible du JavaScript stable récent et des modules ESM, puis je configure eslint et prettier pour qu’ils s’accordent, en ajoutant aussi des plugins comme TypeScript et React. J’ajoute également des hooks pour lancer Prettier et eslint avant chaque commit
    J’installe aussi des extensions d’IDE et je prépare un .devcontainer ou une liste d’extensions recommandées. Je me fiche du style en soi ; ce qui m’importe, c’est la cohérence du code et la détection d’erreurs, donc pour eslint j’utilise généralement une configuration existante
    Ensuite, je mets en place les tests unitaires avec jest ou vitest, ce qui entraîne encore des réglages TypeScript et des règles eslint. Côté framework CSS, j’aime bien tailwind, alors j’installe aussi styled-components et twin.macro pour bien les intégrer à React, ainsi qu’un plugin Google Fonts ou une bibliothèque de polices
    Il faut à peu près une journée avant de pouvoir commencer à programmer. Pourquoi y a-t-il autant de travail ? Tant de gens utilisent la combinaison Vite + TypeScript + React/Vue/Svelte + eslint/prettier + tailwind/bootstrap + jest/vitest ; pourquoi n’existe-t-il pas une bibliothèque sans configuration qui couvre directement 90 % des cas d’usage ?

    • Même quelqu’un qui connaît déjà tout ça y passe une journée. En tant que développeur plutôt back-end et ops, j’ai essayé plusieurs fois d’entrer dans ce type de stack, mais honnêtement, dans bien des cas, j’ai simplement échoué
      Même quand j’arrivais à démarrer la chaîne d’outils d’une manière ou d’une autre, je n’avais jamais l’impression d’en avoir le contrôle ; au moindre petit à-coup, tout semblait prêt à s’effondrer, et j’avais le sentiment de ne pas pouvoir réparer quoi que ce soit
      Récemment, j’ai décidé de voir l’essentiel de cette stack JavaScript comme un obstacle à ce que j’essaie de faire, et j’ai construit à la place une application à rendu côté serveur, à l’ancienne, avec Flask et Jinja2. Ce n’est pas moderne ni clinquant, et comme il n’y a pas encore de CSS, c’est assez laid pour l’instant, mais on m’a conseillé d’essayer avec du CSS moderne pur. Malgré tout, la vitesse à laquelle on peut créer des fonctionnalités avec cette stack est assez stupéfiante
    • Il y a deux linters. Rien que ça, c’est déjà dingue. Le reste est pire, bien sûr, mais même la plus petite parcelle du choix d’outils dans l’écosystème JavaScript est remplie de douleur
    • Je copie un répertoire de démarrage TypeScript et je ne change que le nom dans package.json. Bon, je ne fais que du back-end, mais on pourrait peut-être se faire un template personnel de la même manière pour le front-end ?
    • npm create ne fait-il pas déjà ça ?
      Avec npm create vue, on obtient une configuration Vue assez correcte et fonctionnelle, avec la plupart des réglages déjà en place. Je suis d’accord pour dire qu’il y a beaucoup de boilerplate et de bidouilles diverses, mais les applications qu’on construit aujourd’hui pour le web sont aussi bien plus grosses qu’avant. On peut toujours utiliser JavaScript avec seulement ESModules, sans outillage, mais si on ne le fait généralement pas, c’est parce que ces outils apportent réellement quelque chose. Ce n’est pas la manière la plus propre, mais ça fonctionne
    • Il suffirait sans doute de créer un projet stub avec toute la configuration que tu aimes, de le mettre sur GitHub, puis, à chaque nouveau projet, de le cloner et de ne changer que quelques noms pour être prêt
  • C’est encore un cas où les gens disent JavaScript, mais veulent en réalité dire « le bric-à-brac de l’écosystème Node »
    Dès le départ, on te dit qu’il faut ouvrir et lire un fichier package.json, et ensuite tout continue dans cette logique. Parmi les choses mentionnées, presque rien n’a vraiment à voir avec JavaScript lui-même

    • Quelle proportion des développeurs JavaScript n’utilise pas NodeJS ?
      C’est vrai que JavaScript et NodeJS ne sont pas la même chose, mais la plupart ont sans doute compris ce que l’auteur voulait dire. Il aurait pu être plus précis, mais difficile de dire que c’est complètement faux
    • D’accord, donc l’écosystème n’est pas une cible valable pour critiquer un langage
    • Essaie donc d’écrire vraiment du JavaScript une fois, sans bundler qui utilise package.json. Tant qu’ECMA n’aura pas mis de gestionnaire de paquets ou de bundler dans la spécification officielle, package.json fera de fait partie de JavaScript
    • Si ça t’agace à ce point, considère simplement que chaque fois que quelqu’un dit JavaScript, il veut en fait dire ECMAscript
    • Oui. C’est une critique de l’écosystème JavaScript
  • J’aime bien le ton enjoué. Une fois qu’on s’est brûlé la peau et les terminaisons nerveuses sur plusieurs couches, c’est utile de se remémorer ce genre de point douloureux
    Inversement, ça veut dire qu’on peut donner un MacBook neuf à un junior motivé et le jeter dans le grand bain, il sera productif en moins d’une journée. Pas besoin de connaître les conteneurs, .NET, nginx, ni 100 outils en ligne de commande courants ; quand il y a un problème, il suffit de chercher

    • Oui. L’ironie, c’est qu’à cause de ce compromis, si on y jette même un développeur senior qui construit des choses pour le navigateur depuis 20 ans, il ne sera pas prêt en une journée
      Alors même qu’il sait qu’il pourrait construire le bateau entier en quelques jours s’il pouvait simplement y toucher directement, il se retrouve à réparer un bateau en bouteille avec les outils bancals fournis, en luttant contre des couches de complexité inutile. C’est exactement l’impression qu’on a quand on avance vite sur un projet perso en n’utilisant que JavaScript, HTML et CSS, puis qu’on se retrouve catapulté sur du frontend moderne
    • Et ensuite on bricole un truc pendant un à trois jours, on le regrette pendant les 10 années suivantes, puis on écrit ce genre d’article. Le cycle continue
    • Les juniors que je connais disent : « créons un framework pour gérer cette complexité »
      Ils ignorent naïvement qu’il faut des mois pour construire ça, et qu’une partie du problème vient justement de la surabondance de frameworks, si bien que le leur sera obsolète dès le lendemain
    • Maintenant, au lieu de chercher, ils demandent à ChatGPT
  • « J’ai suivi les instructions, puis il m’a dit que grunt n’était pas installé. Comme je suis vieux maintenant, je ne savais pas très bien ce qu’était grunt, et mon fichier grunt n’avait pas l’air correct non plus. Alors j’ai fait quelques recherches et j’ai compris ce qu’était grunt. Grunt, c’est… en fait je ne sais toujours pas bien ce que c’est. »
    --Joe Armstrong, https://www.youtube.com/watch?v=lKXe3HUG2l4
    Il y a quelques jours, j’ai exécuté gem install wayback_machine_downloader. Je n’ai jamais assez aimé Ruby comme langage pour entrer dans son écosystème, mais vu de l’extérieur, cet écosystème semble avoir été maintenu avec une stabilité remarquable. gem est toujours l’outil qu’on utilise, et Rails est toujours là
    J’attends un nouveau projet qui nécessitera un frontend assez complexe pour dépasser 0 à 30 lignes de JavaScript. À ce moment-là, je serai peut-être plus heureux avec HTMX qu’avec l’énorme framework le plus populaire du moment

  • Ce texte parle de npm, pas de JavaScript
    Je déteste npm à cause de tout ce fatras, et je l’évite autant que possible. Personnellement, j’utilise Deno, et au travail on utilise une sorte de bazel basé sur un monorepo qui permet de se passer de npm
    Mais je trouve que JavaScript/TypeScript est un langage agréable pour programmer, et c’est le premier langage que je choisis quel que soit le projet. Ça m’attriste quand les gens disent « JavaScript est nul » alors qu’ils veulent en fait dire que construire une app React avec npm est nul. Le développement JavaScript/TypeScript moderne est vraiment plaisant

    • D’accord. Je fais un jeu vidéo et j’ai décidé de n’utiliser aucune dépendance ; depuis, coder est vraiment agréable
  • J’ai l’impression que JavaScript et son écosystème nous ont tous laissé un PTSD, au point qu’on n’arrive plus à apprécier l’humour de ce texte
    Il y a beaucoup trop de discussions « sérieuses » autour d’un texte drôle. On peut le disséquer autant qu’on veut, mais il faut se rappeler que l’intention première, c’est l’humour

    • Le fait que ce soit de l’humour ne veut pas dire que ce n’est pas sérieux
  • Honnêtement, l’écosystème dans lequel j’ai commencé, c’était Node, et ce que j’ai appris ensuite avait aussi largement son lot de problèmes délirants
    Haskell était très difficile à utiliser sur plusieurs machines, son installation sur MacOS restait pénible en 2019, et la gestion de l’écosystème était compliquée. Les macros et les extensions sont extrêmement confuses, et la rétrocompatibilité du langage n’est pas très bonne. À l’inverse, on peut généralement s’attendre à ce que du JavaScript de 2010 fonctionne encore tel quel en 2023
    Même mettre en place correctement une image Docker ou un environnement comme codespace/gitpod est difficile, et les images de base fournies par GitHub ne sont pas terribles et posent problème
    Le C est globalement correct sur la plupart des plateformes, mais le langage lui-même est franchement complexe et demande une connaissance énorme de l’ensemble du système. Le résultat, c’est qu’on produit facilement du code peu portable, inadapté à la plupart des usages de la programmation générale
    Je pourrais continuer, mais quiconque a utilisé plusieurs langages sait que tous les écosystèmes ont divers défauts et que nous continuons tous à souffrir. Avec PHP, je n’ai jamais réussi à finir la configuration d’un projet en quelques jours, et Elm est moins douloureux, mais a ses propres problèmes avec son statut de dictateur bienveillant et la vitesse de développement

    • C’est pour ça que j’essaie d’utiliser Go pour presque tout. Même si ce n’est pas le choix optimal, ça minimise les corvées
    • Le C est complexe ? C’est presque le seul langage que je peux garder en tête, quelle que soit la fréquence à laquelle je l’utilise. Une partie de la syntaxe du JavaScript moderne, je m’en sers tous les jours et elle s’évapore quand même facilement de ma mémoire
  • Je suis un développeur polyglotte qui se sent à l’aise avec plusieurs paradigmes et langages de programmation, aussi bien en frontend qu’en backend
    Chaque fois que je vois un package.json dépasser 20 lignes, j’ai à peu près exactement cette réaction

    • Là, je lance un regard noir au nouveau frontend Angular en cours de développement, avec quatre composants frontend, chacun ayant un package.json de plus de 200 lignes
      Je récite à voix haute, comme pour repousser le diable. « Je ne dois pas avoir peur. La peur tue l’esprit. La peur est la petite mort qui mène à l’annihilation totale. J’affronterai ma peur. Je la laisserai passer sur moi et à travers moi. Et lorsqu’elle sera passée, je tournerai mon regard intérieur sur son chemin. Là où la peur sera passée, il n’y aura plus rien. Il ne restera que moi. »
      En train de pleurer
    • Pareil pour moi. Cela dit, petite parenthèse hors sujet : le lien dans le profil est bloqué par uBlock Origin et mène vers un terrier de sites bizarres. Je n’ai jamais utilisé hackernewsers, donc je ne sais pas si c’est un fonctionnement normal
  • On dirait un développeur JavaScript à l’ancienne en train de lire l’article, tourmenté par un PTSD et des flashbacks
    Je ne dois pas avoir peur. La peur tue l’esprit. La peur est la petite mort qui mène à l’annihilation totale
    J’affronterai ma peur. Je la laisserai passer sur moi et à travers moi. Et lorsqu’elle sera passée, je tournerai mon regard intérieur sur son chemin
    Là où la peur sera passée, il n’y aura plus rien. Il ne restera que moi
    Il finit l’article et réalise qu’il a survécu, mais il est déjà trempé de sueur