- Après être passé de JavaScript à Rust pour se concentrer sur WebAssembly, l’auteur a évalué la valeur réelle de Rust sur 3 ans en créant Wick, des déploiements en production, un ebook et environ 100 paquets sur crates.io
- Le borrow checker, le système de types riche, les patterns fonctionnels et l’absence de
nullempêchent de nombreuses erreurs à la compilation et permettent de maintenir une grande base de code avec peu de tests - Clippy et les Cargo workspaces sont puissants, mais les lacunes des outils et de l’écosystème, comme la configuration globale des lint ou la publication de workspaces, se traduisent par un coût opérationnel
- L’async, le refactoring et la gestion des generic, lifetime et trait constraints restent des zones de friction plus importantes qu’en JavaScript ou en Go
- Rust est solide et polyvalent, mais les coûts de recrutement, d’apprentissage, d’itération rapide et d’investigation des problèmes sont élevés, ce qui le rend plus adapté quand le périmètre est clair ou que le coût initial peut être absorbé
WebAssembly a conduit au choix de Rust
- Il y a quelques années, l’auteur a mis de côté ses travaux existants pour se consacrer à 100 % à WebAssembly, et à l’époque Rust offrait le meilleur support de compilation vers WebAssembly
- Les runtimes WebAssembly riches en fonctionnalités étaient eux aussi basés sur Rust, ce qui en faisait l’option la plus réaliste parmi les choix possibles
- Il a ensuite créé Wick, un framework d’applications et un runtime qui utilisent WebAssembly comme système de modules central
- En 3 ans, avec plusieurs déploiements en production, un ebook et environ 100 paquets publiés sur crates.io, son expérience de Rust s’est approfondie
Maintenir plus de code avec moins de tests
- En Rust, l’auteur écrivait d’abord des tests comme dans n’importe quel langage, avant de réaliser qu’il produisait des tests qui ne pouvaient pas échouer dès lors que le code compilait
- En évitant les blocs
unsafe {}et les méthodes sujettes aux panic comme.unwrap(), de nombreux problèmes sont évités par défaut - Le borrow checker, le système de types riche, les patterns et bibliothèques fonctionnels, ainsi que l’absence de valeur
null, réduisent l’effort consacré aux tests - Le projet Wick, avec plus de 70 000 lignes de code, a pu être maintenu avec bien moins de tests que ce qui aurait été nécessaire dans d’autres langages
- Quand des tests sont nécessaires, le harness de tests d’intégration de Rust permet de les ajouter facilement au plus près du code
Rust change aussi les habitudes de code dans les autres langages
- Le compilateur Rust signale sans cesse des problèmes dans du code qui paraissait normal dans d’autres langages, et ce processus a fini par transformer les habitudes de développement de l’auteur
- Désormais, dans d’autres langages aussi, un ordre de lignes de code étrange ou un retour de fonction non vérifié lui paraît inconfortable
- Même face à des erreurs d’exécution, il ressent désormais une réticence bien plus forte qu’avant
- La rigueur de Rust est contraignante, mais une fois habitué à la protection offerte par le compilateur, il devient difficile de revenir à d’autres langages
Clippy est utile bien au-delà d’un simple linter
- Clippy est le linter de Rust, mais il ressemble davantage à un assistant bienveillant qui propose du code alternatif qu’à un simple outil de vérification
- La bibliothèque standard de Rust est très vaste, et ses nombreuses fonctionnalités sont dispersées entre types, traits, macros et fonctions, ce qui rend l’API recherchée difficile à trouver
- Plusieurs règles détectent des patterns courants qui peuvent être mieux remplacés par des méthodes ou types de la bibliothèque standard
- Exemple : manual_is_ascii_check
- Les centaines de règles couvrent la performance, la lisibilité et les indirections inutiles, et proposent si possible du code de remplacement
- Une configuration globale des lint à l’échelle du projet semblait devoir devenir possible via une issue Cargo, mais en attendant Wick devait mettre à jour automatiquement par script les configurations de lint inline de dizaines de crates
L’écosystème comporte des lacunes qu’il faut accepter
- Le problème de configuration globale de Clippy n’est qu’un exemple parmi d’autres des lacunes de l’écosystème souvent rencontrées dans les outils et bibliothèques Rust
- Les issues concernées sont désormais fermées, mais elles sont restées ouvertes pendant des années et leur résolution a pris du temps
- Rust attire de nouveaux utilisateurs au point d’avoir longtemps été élu « langage le plus apprécié », mais cet élan ne s’est pas traduit immédiatement par une amélioration spectaculaire des bibliothèques et des outils
- Il arrivait souvent que des forks ponctuels apparaissent pour gérer un cas d’usage précis, et Wick a connu une situation similaire en essayant de soumettre des PR
- Parmi les raisons possibles figurent la pression pour maintenir des API stables et la granularité du système de types
- Les mainteneurs de bibliothèques ont du mal à accepter de petits changements, car ils peuvent entraîner une montée de version majeure
- Écrire du code Rust capable de satisfaire les besoins de tout le monde représente aussi une charge importante
Cargo, crates.io et les frictions autour de la publication depuis un workspace
- La structure du dépôt de Wick a été conçue en s’inspirant de projets populaires et paraissait raisonnable au départ, mais des problèmes sont apparus à l’étape de publication
- Avec Cargo, il est facile de construire, tester et utiliser des crates de taille modulaire, mais la publication sur crates.io est un problème distinct
- Sur crates.io, tous les crates référencés doivent être publiés individuellement pour qu’un paquet puisse être publié
- Il est logique d’empêcher la publication d’un crate qui dépend d’un paquet présent uniquement sur le système de fichiers local
- Mais dans une structure naturelle où un grand projet est découpé en petits modules internes, il n’est pas possible de publier un crate en incluant des sous-crates qui n’existent qu’à l’intérieur du crate parent
- Une correction a été apportée : un crate avec une dev dependency locale peut être publié sans inclure de
versiondans leCargo.toml - Le support des Cargo workspaces lui-même est excellent, et l’expérience de gestion de grands projets est meilleure que dans la plupart des autres langages
- Cependant, les workspaces ne résolvent pas le problème de publication et, malgré les différentes approches de configuration, il reste difficile de trouver une « bonne réponse » qui se publie facilement
- L’existence même de nombreux crates utilitaires autour de cargo workspace publish montre bien le problème
- Lors de la publication de Wick, il fallait souvent plus d’une heure en combinant des tâches manuelles répétitives et des outils ne fonctionnant que partiellement
L’async est l’une des plus grandes sources de friction
- L’async en Rust donne l’impression d’avoir été ajouté après la création initiale du langage, et dans la pratique il gêne souvent comme une fonctionnalité greffée tardivement
- Les erreurs sont difficiles à comprendre et à résoudre, et même lorsqu’on cherche une solution il faut trier selon plusieurs runtimes et leurs propres approches de l’async
- Certaines bibliothèques async peuvent ne pas être utilisables en dehors d’un runtime async spécifique
- Pour quelqu’un qui a 20 ans de JavaScript et aussi de l’expérience en Go, l’async de Rust est la plus grande source de frustration et de friction
- Ce n’est pas un problème insurmontable, mais il faut toujours être prêt à voir surgir des problèmes d’async à tout moment
- Dans d’autres langages, l’async fonctionne presque de manière invisible, de façon naturelle
Le refactoring peut devenir une tâche éprouvante
- Le système de types riche de Rust est à la fois une force et une faiblesse
- Penser avec les types Rust est agréable, mais gérer les types Rust peut tourner au cauchemar
- Les données et les signatures de fonction peuvent inclure des generic type, generic lifetime et trait constraints
- Les constraints elles-mêmes peuvent à nouveau avoir des generic type et des lifetime, au point qu’il y a parfois plus de constraints de type que de code réel
- Exemple : rxRust observable.rs
- Comme il faut définir les generics pour chaque
impl, c’est déjà fastidieux à l’écriture, et en refactoring un petit changement peut déclencher une cascade de modifications- Exemple : Wasmtime Cranelift iter.rs
- Lorsqu’il faut répéter les mêmes constraints ou listes de generics à plusieurs endroits, il n’existe pas au niveau du langage ou des outils de moyen pour les aliaser ou les référencer depuis une définition centrale, ce qui laisse subsister une charge de duplication
Jugement final : puissant, mais coûteux
- Rust est assez polyvalent pour écrire avec le même langage du code système, des applications CLI, des serveurs web et des clients web
- Avec WebAssembly, il est possible d’exécuter le même binaire de LLM dans le navigateur et en ligne de commande
- Les programmes Rust peuvent être extrêmement robustes, et une fois qu’on a fait l’expérience des problèmes que Rust empêche, il devient difficile de revenir à d’autres langages
- Quand l’auteur est brièvement revenu à Go, la vitesse de développement lui a de nouveau semblé séduisante, mais après avoir subi un panic à l’exécution, cet avantage s’est atténué
- Rust a des inconvénients bien réels
- Le recrutement est difficile
- L’apprentissage est lent
- Le langage est trop rigide pour l’itération rapide
- Il est difficile de traquer les problèmes de mémoire et de performance, surtout dans le code async
- Toutes les bibliothèques ne sont pas assez bonnes pour du code sûr
- Les outils de développement ont encore une grande marge d’amélioration
- L’auteur a réalisé des choses impressionnantes avec une petite équipe, mais a aussi rencontré de gros obstacles, et comme il existait des raisons techniques solides de choisir Rust pour Wick, il estime qu’il est encore trop tôt pour dire si Rust en valait la peine
- Si l’on doit itérer rapidement, Rust a de fortes chances de ne pas être le bon choix
- Si le périmètre est connu ou que l’on peut absorber un coût initial plus élevé, Rust mérite d’être sérieusement envisagé
- À mesure que la perspective WebAssembly gagne en importance chaque mois, la possibilité de réutiliser partout un logiciel robuste écrit une seule fois devient de plus en plus réaliste
1 commentaires
Avis sur Hacker News
J’ai beaucoup utilisé Rust, mais même après des années, il me semble toujours peu productif
Ces temps-ci, j’utilise beaucoup Zig, et j’ai l’impression d’être environ 10 fois plus productif, parce que je peux me concentrer uniquement sur le code que je veux écrire sans me demander quels outils ou bibliothèques utiliser
Je sais que Rust apporte la sécurité mémoire et que c’est important, mais son ergonomie est vraiment mauvaise. Chaque fois que j’utilise Rust, j’ai l’impression d’être contraint, et comme je dois constamment chercher des bibliothèques ou la bonne manière de faire les choses, je ne peux pas simplement « taper du code »
Le système de types peut lui aussi devenir incontrôlable, et il est souvent difficile de savoir quelles méthodes peuvent réellement être appelées sur telle ou telle structure. Rust est un excellent outil et résout beaucoup de problèmes, mais je ne le considère pas comme un bon langage généraliste
Même en ayant utilisé Python pendant près de 20 ans, je travaille maintenant aussi vite en Rust qu’en Python
À mon sens, Rust a complètement raté le bon compromis. Il est trop pointilleux sur les détails bas niveau pour écrire des applications haut niveau, et trop complexe pour l’embarqué ou les systèmes d’exploitation
Pour le premier cas, je choisirais C++, Java, Haskell, OCaml, voire Go avec un peu de C ; pour le second, le C utilisé comme une sorte d’assembleur à macros convient bien mieux
J’ai toujours le sentiment que la vision originale de Graydon Hoare — quelque chose de plus proche de OCaml/SML avec types linéaires, garbage collection, allocation sur la pile, green threads et CPS — aurait donné un langage bien meilleur
En C, une petite erreur conduit souvent à un comportement indéfini et à des ennuis ; avec Rust, ça n’existe pas, et ça change complètement la donne
Je me demande si tu veux dire qu’avec Zig, il n’est pas nécessaire de chercher des bibliothèques ni de comprendre comment faire
Rust oblige à décider à l’avance où vont chaque bit et chaque octet, dans quel thread ils seront utilisés et selon quel mode de mutation ils seront manipulés. Si l’on n’est pas au niveau d’un parseur ou d’un microcontrôleur, ce processus paraît fastidieux
J’aime d’abord faire fonctionner quelque chose, puis déterminer la meilleure structure d’API ; Rust entre en conflit avec cette façon de faire
Même si le système de types de Rust est plus puissant, Swift permet d’obtenir 90 % des performances avec un flux beaucoup plus naturel
Le fait que crates.io n’ait pas d’espaces de noms est peut-être la critique la plus importante
N’importe qui peut réserver un nom de paquet générique dans l’espace global, et sauf à éviter le dépôt crates.io, la plupart des gens doivent s’en accommoder. Or certains paquets portant ces noms génériques réservés ne sont pas, en réalité, les meilleurs à utiliser
C’était peut-être une réaction à la notation DNS inversée à la Java, verbeuse et pénible, mais une approche à la GitHub, avec des espaces de noms utilisateur/groupe préfixant le nom du paquet, aurait été un bon compromis
J’ai envoyé cette analyse à l’équipe crates.io, en signalant aussi l’existence d’une politique interdisant l’automatisation, mais ils ont répondu que ce n’était pas une preuve suffisante de réservation abusive de noms
Le problème de crates.io, c’est que même quand une politique claire existe, elle n’est pas appliquée. Résultat : tous les noms de crates courts et faciles à retenir sont déjà pris, et il n’y a aucun moyen de les récupérer
NPM, PyPI, RubyGems, Hex d’Elixir, Cabal de Haskell, etc. : autour de 2014-2015, lorsque Rust est apparu, il ne me vient pas vraiment d’exemple de gestionnaire de paquets non Java qui n’ait pas eu un espace de noms global unique
Certains ont ensuite essayé de corriger cela, mais à l’époque, c’était simplement ainsi que fonctionnaient les gestionnaires de paquets
Les systèmes de gestion des dépendances, moins bons, apparus ensuite dans d’autres langages ont très peu appris des exemples précédents
Elle a aussi l’avantage de supprimer le besoin d’une base de données globale de paquets au niveau du langage. Si vous publiez un paquet sur example.com/your-thing, il est en quelque sorte immédiatement publié
Bien sûr, on peut fournir séparément des caches et des moteurs de recherche si on le souhaite
C’est du genre : http-server est mauvais, il ne faut pas l’utiliser, il faut utiliser MuffinTop — et il faut juste le savoir
L’idée de noms de paquets officiels est intéressante, mais si le code derrière un alias change avec le temps, cela risque en pratique de devenir déroutant
Au final, cela restera probablement une partie du processus qui consiste à devenir expert d’un domaine dans n’importe quel écosystème
Si l’on crée un
.cargo/config.tomlà la racine du workspace, il s’applique à toutes les crates, ce qui permet de configurer des lints Clippy globauxDans le fichier, il suffit de mettre sous
[build]quelque chose commerustflags = ["-Wclippy::lint_name_to_warn", "-Dclippy::lint_name_to_deny"]Attention toutefois :
rustflagsremplace les valeurs au lieu de s’y ajouter, donc s’il existe une autre source comme la variable d’environnementRUSTFLAGS, elle écrasera ce réglagelib.rsoumain.rs. C’est simpleJ’apprends Rust parce qu’il semble évident qu’il va devenir important professionnellement. J’aimerais vraiment l’aimer et j’en vois les avantages, mais il fait partie des langages les plus désagréables que j’aie utilisés jusqu’ici
J’ai continué à espérer qu’en gagnant en compétence, mon aversion disparaîtrait, mais plus je monte la courbe d’apprentissage, moins je m’y attache vraiment
Ce n’est pas grave. Ce ne sera sans doute pas le seul langage que je maîtrise tout en le détestant. Mais tant de gens disent aimer Rust que je pensais que moi aussi j’y prendrais plaisir
Le compilateur Rust semble aussi s’être amélioré pour accepter un éventail plus large de cas valides
La clé pour comprendre le borrow checker a été de comprendre le modèle mémoire sous-jacent. Le modèle mémoire de Rust est le même que celui de C, à l’exception des extensions destinées aux abstractions comme les génériques
Les règles du borrow checker semblent arbitraires au début, mais elles sont profondément liées à ce modèle mémoire. Le vrai intérêt, c’est quand on se fait surprendre par le borrow checker sans l’avoir voulu, car cela révèle un bug dû à une baisse d’attention
Ce qui fait peur, c’est que dans des langages comme C ou C++, un tel code pourrait simplement être accepté et continuer son chemin
Le système de types strict et le borrow checker de Rust poussent en douceur à structurer correctement le code, et je suis convaincu qu’ils ont amélioré ma conception du code dans tous les langages que j’utilise
C’est une fonctionnalité d’utilisabilité très basique pour les programmeurs, partagée par la plupart des langages populaires, et même C++ a des arguments par défaut depuis longtemps
Ancien programmeur C/C++ qui appelait pthread presque chaque semaine pendant 10 ans, j’utilise maintenant Rust asynchrone partout
Je ne comprends pas pourquoi l’asynchrone est autant détesté. À mon avis, tout le monde devrait utiliser l’asynchrone pour tout. Même pour les tâches « simples » qui, en apparence, sont monothread
Si le cas d’usage de l’auteur avait été Wasm, il aurait certainement eu un autre point de vue
Les travaux qui utilisent de gros buffers ou les réutilisent pour éviter le coût des allocations bénéficient souvent encore des anciens pools de threads. On peut en partie régler cela avec des allocateurs bump ou shardés, mais pour des boucles serrées vectorisables et limitées par le CPU, les pools de threads fonctionnent mieux
L’asynchrone est un bon outil, mais il n’y a pas que des contextes où il est optimal
Go, C# et TypeScript n’ont pas ce genre de barrière
Par exemple, il semble qu’on ne puisse même pas utiliser
awaitdans la fonctionmainsans le décorateur importé de TokioEnginene sont pasSend, alors que j’essaie de les utiliser dans une closure asynchroneGPT-4 m’a suggéré de créer un
tokio Runtimedans un thread et d’utiliserblock_on(). Je vais essayer demain. C’est mon premier vrai projet RustJe me demande aussi si « maintenant j’utilise Rust asynchrone partout » veut dire « j’utilise Tokio partout »
Programmer en Rust n’a vraiment rien d’une relation abusive. Le compilateur essaie d’aider autant que possible, et les messages d’erreur de rustc, en particulier, sont parmi les meilleurs au monde
Ce n’est pas le compilateur Rust qui ressemble le plus à une relation abusive, mais plutôt le système d’exploitation. Le matériel aussi, puisqu’il faut exécuter correctement l’assembleur ; vu comme ça, on pourrait aussi parler de relation abusive
Les messages d’erreur de Rust sont incomparables, et aucun compilateur ne s’en approche
Au passage, j’ai utilisé LaTeX récemment et les messages d’erreur étaient atroces. Essayer de comprendre ce qui n’allait pas en examinant les erreurs était un cauchemar
Futuren’est plusSendniSyncToute la console se retrouve couverte d’erreurs, et la vraie erreur de syntaxe est enfouie quelque part au milieu
Mon principal reproche est que je ne comprends toujours pas complètement les durées de vie (lifetimes), et que le compilateur ne peut pas m’aider à chaque fois. Je comprends pourquoi, car le compilateur raisonne de manière conservatrice
Dans les tests C++, on dit souvent : « si ça compile, c’est probablement correct »
Si l’on pense que Rust gère tellement d’erreurs que les cas de test courants deviennent inutiles, j’y vois le signe qu’on ne testait pas ce qu’il fallait dans les autres langages
Ce qu’il faut tester, ce ne sont pas les problèmes du langage lui-même, mais la logique métier
Si, en regardant un test, on se dit « je le testerais en JavaScript, mais pas besoin en Rust », alors on peut tout simplement supprimer ce test
La distinction « logique métier contre problème de langage » n’existe pas. Le langage est le socle sur lequel repose la logique métier
Si l’on ne teste pas les modes d’échec, je ne vois pas bien à quoi servent les tests
Contrairement à la plupart des langages familiers, C++ a l’IFNDR, qu’on décrit parfois en plaisantant comme un faux positif à la question « est-ce un programme C++ ? »
Dans certains cas où le code écrit est manifestement suspect, un compilateur C++ conforme au standard n’a pas le droit de vous le signaler ; il doit simplement continuer et produire quelque chose
Cela peut être un exécutable qui fonctionne, ou un exécutable qui provoque une catastrophe tous les vendredis. Impossible de le savoir
La norme ISO identifie bien ces cas, mais c’est tellement vague qu’il est difficile de cerner précisément ce qui est inclus ; à mon avis, la plupart des logiciels C++ non triviaux actuels sont probablement de l’IFNDR en pratique. Autant rejeter tout le langage
Rust semble avoir enfin brisé l’idée selon laquelle le programmeur doit contrôler et avoir conscience de tout ce que fait le compilateur
En réalité, ce n’était déjà plus le cas depuis des décennies, et les compilateurs tenaient presque de la magie. Avec l’emprunt, Rust a largement inversé cette tendance et a rendu les gens plus à l’aise avec l’idée que le compilateur en sait plus qu’eux
J’aimerais qu’on aille encore plus loin dans ce confort. Sauf nécessité algorithmique, on ne devrait pas avoir à itérer explicitement sur les collections depuis le début. Plusieurs opérations devraient être parallélisées implicitement. J’aimerais un Bash dans l’esprit de Rust
Rust est assez transparent sur ce qu’il fait et très conservateur en matière de magie du compilateur. Le langage ne fait pas d’allocation sur le tas, pas de comptage de références, et pas de conversions implicites de types numériques
Il ne copie pas les types qui ne sont pas déclarés implicitement copiables, et même là, ce n’est légal que pour les types copiables par un simple
memcpysuperficielRust utilise partout des abstractions sans surcoût, ce qui rend le code généré prévisible et généralement simple. La disposition de base des types standard est bien connue, donc on sait qu’un parcours de
Vecsera compilé en boucle incrémentant un pointeur, et il n’y a pas de parallélisme impliciteDécrire l’emprunt comme « le compilateur en sait plus que le programmeur » est étrange. L’emprunt ressemble à la vérification de types. Si l’on déclare un type comme temporaire et qu’on l’utilise comme s’il vivait longtemps, on obtient une erreur
C’est comme retourner un
Bardepuis une fonction déclarée comme retournant une structureFoo: cela produit une erreur. Si le compilateur « en sait plus », c’est simplement parce qu’on a écrit un bugL’emprunt se compile lui aussi en utilisation directe de pointeurs sans ramasse-miettes, et dans les structures et fonctions à ABI C, il est garanti comme étant littéralement identique aux pointeurs C. Si l’on pense en savoir plus que le compilateur, on peut aussi contourner les durées de vie avec
unsafeiter()En revanche, je ne suis pas d’accord pour dire que cela devrait être implicite
À certains égards, Rust donne plus de contrôle au programmeur que C. Par exemple, Rust prend en charge l’assembleur inline dans le standard, tandis que l’assembleur inline en C dépend d’extensions propres aux fournisseurs
En revanche, les valeurs par défaut pratiques sont très différentes. En Rust, les conversions de types non sûres exigent beaucoup de procédures et de prudence, et il faut respecter davantage de règles qu’en C
En particulier, les références Rust se comportent pratiquement toutes comme
restrict, et il est très facile de casser cela lorsqu’on fait un castunsafed’un pointeur brut vers une référence sûre. Résultat : si l’on a le choix, on est fortement incité à ne pas écrire ce genre de codeAu contraire, je veux un contrôle plus explicite, et j’aimerais réduire cette charge grâce à un système de types plus expressif. Idéalement, j’aimerais que le système de types de Rust ressemble à une variante de Prolog
Apprendre quand investir dans les contraintes de type, et quand ne pas le faire, est une leçon importante
Ce n’est pas propre à Rust, même si la manière de l’exprimer peut varier un peu
J’ai eu affaire à du C++ excessivement typé et à du Java trop abstrait et trop typé ; les deux posent le même genre de problèmes lors du refactoring
À l’inverse, j’ai aussi vu beaucoup de Go manquant de types et de documentation, où certaines valeurs se retrouvent dispersées partout et deviennent des mines à retardement à l’exécution, ce qui peut rendre le refactoring vraiment très difficile
La sensation de progresser arrive plus vite au début, mais on finit généralement par livrer les bugs aux utilisateurs
Il n’existe pas de réponse magique à ce compromis. Rust offre une palette de choix assez large sur cet axe
Dire que « Rust vous crie dessus toute la journée, tous les jours, pour des choses qui, dans votre vie d’avant, vous auraient paru parfaitement normales » vaut aussi, dans une certaine mesure, pour un bon compilateur C avec tous les flags activés
J’aime les langages et compilateurs qui permettent de désactiver sélectivement ces cris et d’écrire volontairement du mauvais code. Du mauvais code qui fonctionne et qu’on peut écrire vite vaut souvent mieux qu’un code parfait qui prend une éternité
On peut commencer par faire une preuve de concept mauvaise mais fonctionnelle, puis la corriger pour la rendre moins mauvaise
Le fait de « bien attirer de nouveaux utilisateurs, sans que les bibliothèques ou les outils s’améliorent de façon spectaculaire, et en ne produisant que des forks ponctuels pour traiter des cas d’usage spécifiques » n’a rien à voir avec l’âge
Attirer des développeurs cœur est difficile, et il faut beaucoup d’efforts pour rendre cela attractif. En plus, les conventions culturelles sont fixées par les premiers adoptants, et l’absence de conventions est souvent aussi néfaste que de mauvaises conventions
Regardez Python : son approche relâchée des environnements de développement et d’exécution a abouti à une cinquantaine de façons concurrentes de développer ou d’exécuter des programmes Python
Le dépôt de paquets le plus utilisé, PyPI, a été un bazar pendant des années ; peu de gens construisent par-dessus les paquets existants, les noms ressemblent à ceux d’un générateur de mots aléatoires, l’écosystème contient beaucoup de code malveillant, et on ne peut même pas rechercher des paquets en ligne de commande
Ce n’est pas la faute du langage, mais celle de la communauté et de l’équipe cœur, restées en spectatrices. La culture est plus importante que la technologie au centre
Je ne cherche pas à m’en prendre uniquement à Python ; c’est simplement le problème que je connais le mieux. C existe depuis un demi-siècle, mais sa communauté n’a pas non plus vraiment structuré la moitié des solutions mises en place par des langages plus modernes
Le compilateur vous crie dessus pour corriger les choses, alors que vous voulez juste tester une idée avant de tout peaufiner parfaitement