Journal Mon inquiétude sur les dépendances en Rust

Posté par  (site web personnel, Mastodon) . Licence CC By‑SA.
66
2
juil.
2024

Bonjour 'Nal,

Tout a commencé quand j'ai voulu faire des choses un peu inhabituelles sur mon blog personnel (entre autres, écrire des maths avec une syntaxe personnalisée), et pour cela changer le moteur de blog. De Zola, un générateur de site statique dans la lignée de Jekyll, Hugo, etc., je suis passé à un petit script maison. J'ai décidé de l'écrire en Rust, car même si ce n'est pas le plus pratique comme langage de script, c'est un langage que j'adore et dans lequel je voulais justement acquérir plus d'aisance.

Comme la structure du site proposée par Zola me paraissait plutôt pratique, je l'ai plus ou moins conservée. Il y a des fichiers Markdown convertis en HTML, avec un en-tête en TOML pour les métadonnées (date, etc.) ; des templates (en l'occurrence en Tera) qui définissent le HTML autour du Markdown rendu et peuvent aussi constituer des pages à part entière ; et des fichiers quelconques qui sont simplement copiés (images, CSS, etc.).

Je commence donc à écrire mon script, un peu laborieusement car je n'ai pas touché à Rust depuis un moment. J'ajoute au fur et à mesure les dépendances dont j'ai besoin, en prenant des librairies parmi les plus courantes :

  • anyhow pour propager facilement les erreurs,

  • clap pour le parsing des arguments en ligne de commande du script,

  • heck pour convertir entre différents styles de nommage,

  • pulldown-cmark pour lire le Markdown et le convertir en HTML,

  • regex pour les expressions régulières, et lazy_static pour ne compiler une regex qu'une fois,

  • tera pour les templates (même engin que Zola),

  • toml pour lire le TOML,

  • walkdir pour lister un dossier récursivement.

Comme j'ai plutôt l'habitude d'écrire des scripts en Python, j'ai tendance à chercher « la librairie Rust qui correspond à tel module Python ». Par exemple, j'ai ajouté regex sans me poser trop de questions (en pensant à import re), et de même pour clap (import argparse) et walkdir (from os import walk).

À un moment donné, j'ai l'idée de regarder les dépendances transitives. Et là, surprise en examinant le Cargo.lock : il y en a 126.

9 dépendances directes, ce n'est déjà pas rien, mais 126 dépendances au total, je trouve ça complètement excessif. Je sais qu'il y a des projets à 500 dépendances, en particulier en JavaScript, je sais qu'il y en a que ça ne dérange pas, mais je sais aussi ce qui est arrivé à left-pad, à polyfill.io, à xz, et d'autres, et je ne veux certainement pas passer le temps qu'il faudrait pour vérifier ne serait-ce que superficiellement qui sont les auteurs de toutes ces librairies et si je suis prêt à leur faire confiance. Je ne suis pas non plus en train d'écrire l'application Web d'une entreprise, mais un bête script générateur de blog. Pour le dire de manière plus éloquente, certes à un point où mon script ne marchait pas encore, j'avais plus de dépendances que de lignes de code.

En examinant cargo tree, j'ai pu constater quelles librairies contribuaient le plus à cette explosion. D'abord, clap :

└── clap v4.5.8
    └── clap_builder v4.5.8
        ├── anstream v0.6.14
        │   ├── anstyle v1.0.7
        │   ├── anstyle-parse v0.2.4
        │   │   └── utf8parse v0.2.2
        │   ├── anstyle-query v1.1.0
        │   ├── colorchoice v1.0.1
        │   ├── is_terminal_polyfill v1.70.0
        │   └── utf8parse v0.2.2
        ├── anstyle v1.0.7
        ├── clap_lex v0.7.1
        └── strsim v0.11.1

Aussitôt remplacée par pico-args, qui n'est pas tout à fait aussi pratique mais n'a aucune dépendance et ne fait même pas 700 lignes de code. (En plus, je fais confiance à l'auteur, qui a aussi écrit une excellente librairie de rendu SVG, resvg.)

Ensuite, il y a tera :

└── tera v1.20.0
    ├── chrono v0.4.38
    │   ├── iana-time-zone v0.1.60
    │   └── num-traits v0.2.19
    │       [build-dependencies]
    │       └── autocfg v1.3.0
    ├── chrono-tz v0.9.0
    │   ├── chrono v0.4.38 (*)
    │   └── phf v0.11.2
    │       └── phf_shared v0.11.2
    │           └── siphasher v0.3.11
    │   [build-dependencies]
    │   └── chrono-tz-build v0.3.0
    │       ├── parse-zoneinfo v0.3.1
    │       │   └── regex v1.10.5
    │       │       ├── regex-automata v0.4.7
    │       │       │   └── regex-syntax v0.8.4
    │       │       └── regex-syntax v0.8.4
    │       ├── phf v0.11.2 (*)
    │       └── phf_codegen v0.11.2
    │           ├── phf_generator v0.11.2
    │           │   ├── phf_shared v0.11.2 (*)
    │           │   └── rand v0.8.5
    │           │       └── rand_core v0.6.4
    │           └── phf_shared v0.11.2 (*)
    ├── globwalk v0.9.1
    │   ├── bitflags v2.6.0
    │   ├── ignore v0.4.22
    │   │   ├── crossbeam-deque v0.8.5
    │   │   │   ├── crossbeam-epoch v0.9.18
    │   │   │   │   └── crossbeam-utils v0.8.20
    │   │   │   └── crossbeam-utils v0.8.20
    │   │   ├── globset v0.4.14
    │   │   │   ├── aho-corasick v1.1.3
    │   │   │   │   └── memchr v2.7.4
    │   │   │   ├── bstr v1.9.1
    │   │   │   │   └── memchr v2.7.4
    │   │   │   ├── log v0.4.22
    │   │   │   ├── regex-automata v0.4.7
    │   │   │   │   ├── aho-corasick v1.1.3 (*)
    │   │   │   │   ├── memchr v2.7.4
    │   │   │   │   └── regex-syntax v0.8.4
    │   │   │   └── regex-syntax v0.8.4
    │   │   ├── log v0.4.22
    │   │   ├── memchr v2.7.4
    │   │   ├── regex-automata v0.4.7 (*)
    │   │   ├── same-file v1.0.6
    │   │   └── walkdir v2.5.0
    │   │       └── same-file v1.0.6
    │   └── walkdir v2.5.0 (*)
    ├── humansize v2.1.3
    │   └── libm v0.2.8
    ├── lazy_static v1.5.0
    ├── percent-encoding v2.3.1
    ├── pest v2.7.10
    │   ├── memchr v2.7.4
    │   ├── thiserror v1.0.61
    │   │   └── thiserror-impl v1.0.61 (proc-macro)
    │   │       ├── proc-macro2 v1.0.86
    │   │       │   └── unicode-ident v1.0.12
    │   │       ├── quote v1.0.36
    │   │       │   └── proc-macro2 v1.0.86 (*)
    │   │       └── syn v2.0.68
    │   │           ├── proc-macro2 v1.0.86 (*)
    │   │           ├── quote v1.0.36 (*)
    │   │           └── unicode-ident v1.0.12
    │   └── ucd-trie v0.1.6
    ├── pest_derive v2.7.10 (proc-macro)
    │   ├── pest v2.7.10 (*)
    │   └── pest_generator v2.7.10
    │       ├── pest v2.7.10 (*)
    │       ├── pest_meta v2.7.10
    │       │   ├── once_cell v1.19.0
    │       │   └── pest v2.7.10 (*)
    │       │   [build-dependencies]
    │       │   └── sha2 v0.10.8
    │       │       ├── cfg-if v1.0.0
    │       │       ├── cpufeatures v0.2.12
    │       │       └── digest v0.10.7
    │       │           ├── block-buffer v0.10.4
    │       │           │   └── generic-array v0.14.7
    │       │           │       └── typenum v1.17.0
    │       │           │       [build-dependencies]
    │       │           │       └── version_check v0.9.4
    │       │           └── crypto-common v0.1.6
    │       │               ├── generic-array v0.14.7 (*)
    │       │               └── typenum v1.17.0
    │       ├── proc-macro2 v1.0.86 (*)
    │       ├── quote v1.0.36 (*)
    │       └── syn v2.0.68 (*)
    ├── rand v0.8.5
    │   ├── libc v0.2.155
    │   ├── rand_chacha v0.3.1
    │   │   ├── ppv-lite86 v0.2.17
    │   │   └── rand_core v0.6.4
    │   │       └── getrandom v0.2.15
    │   │           ├── cfg-if v1.0.0
    │   │           └── libc v0.2.155
    │   └── rand_core v0.6.4 (*)
    ├── regex v1.10.5
    │   ├── aho-corasick v1.1.3 (*)
    │   ├── memchr v2.7.4
    │   ├── regex-automata v0.4.7 (*)
    │   └── regex-syntax v0.8.4
    ├── serde v1.0.203
    ├── serde_json v1.0.120
    │   ├── itoa v1.0.11
    │   ├── ryu v1.0.18
    │   └── serde v1.0.203
    ├── slug v0.1.5
    │   └── deunicode v1.6.0
    └── unic-segment v0.9.0
        └── unic-ucd-segment v0.9.0
            ├── unic-char-property v0.9.0
            │   └── unic-char-range v0.9.0
            ├── unic-char-range v0.9.0
            └── unic-ucd-version v0.9.0
                └── unic-common v0.9.0

Sérieusement, c'est juste effrayant. Je me suis tourné vers Minijinja, qui fait plus ou moins la même chose avec une seule dépendance obligatoire — et qui en fait un but explicite (« Minijinja is a powerful but minimal dependency template engine »), l'auteur, un développeur connu, ayant écrit sa peur face à l'explosion des micro-dépendances. Au départ, j'ai utilisé une fonctionnalité optionnelle de Minijinja qui rajoute deux dépendances, pour avoir une certaine API, puis j'ai refactorisé mon code pour ne pas en avoir besoin.

Ensuite, il y a le cas de regex :

└── regex v1.10.5
    ├── aho-corasick v1.1.3
    │   └── memchr v2.7.4
    ├── memchr v2.7.4
    ├── regex-automata v0.4.7
    │   ├── aho-corasick v1.1.3 (*)
    │   ├── memchr v2.7.4
    │   └── regex-syntax v0.8.4
    └── regex-syntax v0.8.4

Contrairement à Tera, ça ne me fait pas hurler, surtout que toutes ces librairies sont du même auteur — Andrew Gallant — et essentiellement crées pour les besoins de regex. Je vois un peu qui est Andrew Gallant, il est connu comme étant l'auteur de ripgrep, et regex est une merveille de performance qui fait justement le succès de ripgrep. D'un autre côté, j'avais ajouté la dépendance à regex par réflexe pythonicien, mais je n'en avais besoin que pour une seule expression régulière toute bête, que j'ai facilement remplacée par deux appels à str::split_once. Du même coup, j'ai éliminé la dépendance à lazy-static, dont j'ai appris par ailleurs qu'elle se remplaçait facilement par OnceCell qui est dans la bibliothèque standard.

Il y avait encore walkdir :

└── walkdir v2.5.0
    └── same-file v1.0.6

(en fait, quelques dépendances de plus sous Windows). D'un côté, ce n'est pas monstrueux (et c'est encore du Andrew Gallant), d'un autre côté, ce n'est tout de même pas bien compliqué d'implémenter la lecture récursive d'un dossier. Je me suis empressé de le faire, en 50 lignes de code, et de retirer cette dépendance.

J'ai aussi remplacé heck par un bête .replace('-', "_") après m'être assuré que cela convenait dans mon cas.

Bilan : je n'ai « plus que » 24 dépendances, pour 5 dépendances directes : anyhow, minijinja, pico-args, pulldown-cmark et toml. L'arbre est celui-ci :

├── anyhow v1.0.86
├── minijinja v2.0.2
│   └── serde v1.0.203
├── pico-args v0.5.0
├── pulldown-cmark v0.11.0
│   ├── bitflags v2.5.0
│   ├── memchr v2.7.4
│   ├── pulldown-cmark-escape v0.11.0
│   └── unicase v2.7.0
│       [build-dependencies]
│       └── version_check v0.9.4
└── toml v0.8.14
    ├── serde v1.0.203
    ├── serde_spanned v0.6.6
    │   └── serde v1.0.203
    ├── toml_datetime v0.6.6
    │   └── serde v1.0.203
    └── toml_edit v0.22.14
        ├── indexmap v2.2.6
        │   ├── equivalent v1.0.1
        │   └── hashbrown v0.14.5
        ├── serde v1.0.203
        ├── serde_spanned v0.6.6 (*)
        ├── toml_datetime v0.6.6 (*)
        └── winnow v0.6.13

Les deux plus gros contributeurs sont pulldown-cmark et toml. Ces deux bibliothèques sont utilisées respectivement par rustdoc (l'outil standard de documentation d'API en Rust, utilisé par absolument tout le monde) et par Cargo lui-même, donc j'ai plutôt confiance en ces deux librairies.

Quelle est la conclusion ? Que ce n'est pas bien difficile, dans beaucoup de cas, de se passer d'une dépendance. J'ai l'impression qu'il y a une culture, dans une partie du monde informatique, de prendre les dépendances trop à la légère. J'ai pris Rust comme exemple, mais je crois comprendre que JavaScript est encore pire. Que les outils comme Cargo rendent très facile l'utilisation de librairies, c'est fantastique (en Python c'est plus compliqué, et ne parlons même pas de C ou C++), mais il ne faut pas abuser des bonnes choses. Chaque dépendance a un coût, celui de la mettre à jour et de s'adapter si elle change son API, et elle porte un risque, celui d'être utilisée pour propager du code malveillant, ou tout simplement d'avoir des vulnérabilité (à force d'importer de plus en plus de code dans son projet, on augmente du même coup la surface d'attaque potentielle). Quand on a 130 dépendances, il est irréaliste de les auditer individuellement. Les outils comme cargo audit sont une très bonne chose, mais si on peut s'en passer, c'est encore mieux.

  • # Merci

    Posté par  . Évalué à 10 (+10/-0).

    Merci pour ce retour d'expérience. Je partage la même inquiétude sur le nombre très élevé des dépendances indirectes, et les difficultés que ça apporte pour la fiabilité, la maintenance. Je développe une petite application en Flutter pour mobile, et c'est un sujet que je regarde régulièrement. Il m'arrive parfois de rajouter quelques lignes de codes pour éviter d'ajouter une dépendance.

  • # Les limites de l'exercice

    Posté par  . Évalué à 10 (+11/-1).

    Toute la difficulté est de savoir où placer la limite.

    Moins de dépendances, c'est effectivement moins de code (surface d'attaque moindre) et moins de personnes extérieures à qui faire confiance. Le journal l'explique très bien. Et, quand on peut obtenir moins de dépendances juste en changeant la bibliothèque qu'on utilise, c'est très bien.

    Mais si on enlève des dépendances en réécrivant soi-même le code de la bibliothèque, là, on peut partir dans l'excès inverse : on risque de recoder mal ce qui a été codé bien par une équipe compétente. On perd la force du travail d'équipe, le partage du travail.

    La frontière est mince. Dans le journal, les exemples donnés semblent raisonnables (grosses bibliothèques enlevées en (re)codant quelques cas particuliers) mais il serait facile d'aller trop loin si on ne fait pas attention. J'ai vu nombres d'étudiants recoder (très) mal des fonctionnalités de bibliothèques pour de mauvaises raisons (ignorance de l'existant, c'est plus rigolo de tout (re)faire soi-même, etc.)
    Dans le contexte d'enseignement, ça peut être bien (on apprend quand on (re)code), mais dans un contexte plus professionnel (stage, emploi), ça peut vite apporter des problèmes (performances, sécurité, maintenabilité, etc.)

    • [^] # Re: Les limites de l'exercice

      Posté par  . Évalué à 9 (+7/-1).

      J'ai vu nombres d'étudiants recoder (très) mal des fonctionnalités de bibliothèques pour de mauvaises raisons

      et

      c'est plus rigolo de tout (re)faire soi-même,

      justement c'est quand on est étudiant que c'est une excellente raison! ça permet d'apprendre;

      Il ne faut pas décorner les boeufs avant d'avoir semé le vent

  • # Éternel problème des SPOF

    Posté par  (site web personnel) . Évalué à 10 (+10/-1).

    J'aime pas spécialement Rust (surtout pour sa syntaxe, donc complètement subjectif) mais j'ai rien contre le langage directement. Par contre je déteste les crates.io et l'écosystème qui en est lié. Déjà parce qu'il faut obligatoirement un compte GitHub pour publier mais parce qu'il est conçu comme npm, on fait des modules de 10 lignes et on en revient à télécharger la terre entière pour un projet quelconque.

    Alors pour Rust on va dire que c'est moins grave car les LTO et la compilation fait que cela reste moins bloat que les projets nodejs mais ça n'en est pas moins énervant. Plus il y a de pièces en mouvements dans un moteur, plus il y a de risques. Le gros problème est évidemment lié au SPOF. N'importe qui avec une simple dépendance peut introduire une backdoor en rien de temps.

    Ce qui me chiffonne le plus c'est l'aspect mise à jour de sécurité. Là où des bibliothèque partagées permettent de sécuriser un système avec une simple mise à jour de la .(dll|so|dylib), les projets Rust doivent tous être recompilés. On va dire que ce n'est pas mieux avec les projets externes directement intégrés dans un projet mais ça doit rester anecdotique.

    Aucune solution n'est parfaite mais pour moi tous les écosystèmes basés sur ce concept comme Rust, Go et npm sont vérolés de base en plus d'être des plaies pour les packagers Linux/*BSD.

    git is great because linus did it, mercurial is better because he didn't

    • [^] # Re: Éternel problème des SPOF

      Posté par  . Évalué à 4 (+2/-0).

      Il n'est plus possible de garder cette logique de bibliothèques partagées avec Rust ? C'est forcément des binaires statiques ?

      • [^] # Re: Éternel problème des SPOF

        Posté par  . Évalué à 2 (+1/-0).

        Je n'en suis pas sûr, et j'ai une très grosse flemme d'aller vérifier, donc faîtes-vous plaisir, corrigez moi :-D

        J'ai cru comprendre que la stabilité de l'ABI n'était pas une priorité de Rust (pour le moment), ce qui expliquerait qu'il ne produit que des binaires statiques.

        • [^] # Re: Éternel problème des SPOF

          Posté par  (site web personnel, Mastodon) . Évalué à 4 (+3/-0).

          Cargo est parfaitement capable de créer et d'utiliser des librairies dynamiques, mais en gros les seuls qui le font sont ceux qui ont besoin de FFI avec d'autres langages (souvent C, mais aussi tout langage capable de comprendre l'ABI C, comme C++ ou Python).

          Déjà, le principe même de vouloir mettre à jour une librairie dynamique sans recompiler ses dépendants est fondamentalement en conflit avec la monomorphisation des génériques, c'est-à-dire le fait qu'une même fonction dans la librairie peut être appelée avec des types différents dans le dépendant, non connus à l'avance, ce qui nécessite de la recompiler une fois par type avec lequel elle est utilisée dans le dépendant. C'est la même chose en C++ avec les templates. Toute tentative de créer une librairie dynamique à l'ABI stable se heurte à ce problème, qui rend le code pas du tout idiomatique parce que les génériques sont partout dans le langage.

  • # Un peu de nuance

    Posté par  . Évalué à 5 (+5/-1).

    Quand on regarde le retour du cargo tree sur tera, regex-syntax v0.8.4 apparaît plusieurs fois.
    La même lib (avec la même version) est utilisée par plusieurs dépendances de tera, pourtant tu n'auras qu'une seule lib installée.

    Pour clap vs pico-args, c'est un choix perso au détriment des fonctionnalités.

    Je comprend la réflexion du trop de dep, mais il faut parfois relativiser:
    préférer une crate sans dep mais qui réimplémente tout dans son coin ou une crate avec des dépendances (qui ont plus de chance d'être revues par plus de dev).
    Du coup, tu préfères une n-ième crate pour un runtime async sans dépendance face à tokio? Le deuxième ayant certainement plus de reviews que le premier.

    Personnellement, je suis passé de la politique "moins de dep" à "que des dep maintenues", je m'appuie sur les indicateurs (nombre de téléchargement et surtout date du dernier update) de crates.io

    Tu peux aussi avoir d'autres critères comme cargo-geiger et cargo-crev.

    • [^] # Re: Un peu de nuance

      Posté par  (site web personnel, Mastodon) . Évalué à 4 (+3/-0).

      Quand on regarde le retour du cargo tree sur tera, regex-syntax v0.8.4 apparaît plusieurs fois.
      La même lib (avec la même version) est utilisée par plusieurs dépendances de tera, pourtant tu n'auras qu'une seule lib installée.

      C'est vrai. Note toutefois que ces doublons ne sont pas décomptés dans mon total de 126 (j'ai juste fait rg "name =" Cargo.lock | wc -l).

      Et je ne dis pas que les dépendances sont « mal » (au contraire, c'est un soulagement d'avoir enfin un langage de bas niveau où c'est facile d'utiliser des dépendances). Je critique plus une certaine culture d'en ajouter sans prendre en compte leur coût. Je suis tout à fait prêt à utiliser tokio, ou regex, ou pulldown-cmark, ou toml. Je suis sceptique sur Tera parce que les dépendances me paraissent excessives rapportées au service rendu.

      • [^] # Re: Un peu de nuance

        Posté par  (site web personnel) . Évalué à 3 (+1/-0).

        Je critique plus une certaine culture d'en ajouter sans prendre en compte leur coût.

        J'ai souvenance d'une librairie js installable avec npm qui te fournissait une fonction te disant si un nombre était pair ou impair…

        « Il n’y a pas de choix démocratiques contre les Traités européens » - Jean-Claude Junker

        • [^] # Re: Un peu de nuance

          Posté par  (site web personnel) . Évalué à 4 (+2/-0).

          Non c'est 2 librairies :

          Heureusement, il existe des libs permettant de les différencier :

          https://link-society.com - https://kubirds.com

          • [^] # Re: Un peu de nuance

            Posté par  (site web personnel) . Évalué à 1 (+2/-3).

            les librairies, c'est ceux qui vendent des bouquins ; les bibliothèque c'est là où on peut les emprunter et consulter, non ? ;-)

            • [^] # Re: Un peu de nuance

              Posté par  (site web personnel) . Évalué à 1 (+0/-1).

              Une librairie c'est aussi la francisation du terme anglais "library" qui veut dire bibliothèque, contrairement à "book shop".

              Donc, ne pas confondre librairie et librairie. Tout comme il ne faut pas confondre cuisinière (la machine) et cuisinière (la personne).

              https://link-society.com - https://kubirds.com

              • [^] # Re: Un peu de nuance

                Posté par  (site web personnel) . Évalué à 1 (+1/-2). Dernière modification le 03 juillet 2024 à 18:51.

                c'est aussi la francisation du terme anglais "library" qui veut dire bibliothèque

                cela s'appelle un anglicisme (je ne rejette pas l'archaïsme pour autant) :-) ce qui est confirmé sur librairie
                pour autant je maintiens que le terme bibliothèque est plus approprié (cf. 7 bien mieux décrit et défini), comme indiqué sur traductions classiques auquel tu peux ajouter tous les termes ayant leur équivalent français (éventuellement anglicisé ?)

                il ne faut pas confondre cuisinière (la machine) et cuisinière (la personne)

                tu te fâcheras avec qui tu veux, je ne suis plus là   ----->   [   ]
                le cuisinier, c'est quel meuble — à des fins d'équité ? /o\

                • [^] # Re: Un peu de nuance

                  Posté par  (site web personnel) . Évalué à 1 (+1/-2).

                  1) Anglicisme c'est un emprunt à l'anglais, ici c'est un mot anglais re-traduit en français, donc bien une francisation et non un anglicisme. Quitte à être chiant, autant l'être jusqu'au bout non ?

                  2) Je suis pas le seul a utiliser ce mot dans ce sens, pourquoi me reprendre moi et pas les autres ?

                  3) Tu as ton avis, une bibliothèque c'est à propos de livres (bibli), ici on n'a pas de lives. On a parfaitement le droit de ne pas adhérer aux traductions classiques de LinuxFR

                  4) En fait, je n'adhère même pas à cette manie de tout vouloir traduire. cadriciel ? sérieusement ?

                  le cuisinier, c'est quel meuble — à des fins d'équité ? /o\

                  Ce genre d'équité à la mord-moi-le-noeud, je m'en contre fiche.


                  Bref, t'as eu envie d'être chiant et trolleur alors qu'on n'est pas Vendredi. C'est triste de voir les traditions se perdre.

                  https://link-society.com - https://kubirds.com

                  • [^] # Re: Un peu de nuance

                    Posté par  (site web personnel) . Évalué à 0 (+0/-2).

                    1. tu as loupé le début de librairie qui aurait pu t'aider : une latinisation donc ? ;-) genre tennis c'est un anglicisme ou le jeu repris de France en Angleterre puis revenu en France ?
                    2. ah, mais je reprends régulièrement les autres ; qui a contribué le plus à traductions classiques crois-tu ? (indication : il y a un suivi de version du wiki sur le côté gauche de la marge)
                    3. bin, bibliothèque a une définition claire de l'appel à des fonction mutualisées en informatique (cf. 7 déjà évoqué)
                    4. là je te rejoins complètement : seras-tu le 1er à proposer mieux ? (paches welcome!)

                    à chiant, chiant 1/2

                    C'est triste de voir les traditions se perdre

                    avec les RTT, c'est tous les jours 'dredi :-)

  • # walkdir, la place est dans la bibliothèque standard ?

    Posté par  . Évalué à 5 (+3/-1).

    Dans ce cas particulier, certes c'est ptete pas la mort à réimplémenter, mais le fait que ça se retrouve dans ton logiciel à la fois et dans ses dépendances montre que ça a peut-être sa place dans la bibliothèque standard.

    • [^] # Re: walkdir, la place est dans la bibliothèque standard ?

      Posté par  . Évalué à 3 (+2/-0).

      Non, ça se fait en quelques lignes avec une fonction récursive et un itérateur.
      Je suppose que dans les 50 lignes produites par l'auteur, il y a plus que ça.
      Mais je suppose aussi que ces 50 lignes proposent beaucoup moins que walkdir.

      La std Rust n'a jamais eu pour but de répondre à toutes les demandes même basiques.
      Par contre, elle permet de créer les outils/lib appropriés.
      Dans le cas de walkdir, faudrait gérer les Linux/Max/Windows/.. et toutes les spécificités de ces plateformes.

      On en revient au même, c'est au dev de choisir ce qu'il a besoin.

      • [^] # Re: walkdir, la place est dans la bibliothèque standard ?

        Posté par  . Évalué à 5 (+3/-1).

        Ça pose la question de l'étendue souhaitable d'une bibliothèque standard. Si tu ne mets pas dedans certains trucs très utilisés en pratique par les devs, au delà d'essayer de maintenir ce qui est essentiel à un langage, tu mets le poids du développement et de la maintenance sur une communauté décentralisée, ça a des risques de fragmentation, de garantie de maintenance, ou de réinventage de roue sous prétexte d'éviter des dépendances qu'on peut illustrer ici.

        • [^] # Re: walkdir, la place est dans la bibliothèque standard ?

          Posté par  . Évalué à 1 (+1/-1).

          A l'inverse, trop en mettre dans la lib std peut décourager le développement d'alternatives.

          Rust a choisi de fournir une lib "minimaliste". Mais elle n'est pas figée.
          L'auteur du post parle de lazy_static qui était la ref du genre. Elle a été améliorée par la crate Once_cell qui maintenant se retrouve dans std.
          On peut aussi citer futures.
          Si Rust n'avait pas supprimé les greenthreads de la std, est-ce que tokio et les autres runtimes async auraient vu le jour?

          Il existe donc les 2 approches chacune avec leurs avantages/inconvénients, faut bien en choisir une.

      • [^] # Re: walkdir, la place est dans la bibliothèque standard ?

        Posté par  (site web personnel, Mastodon) . Évalué à 3 (+2/-0). Dernière modification le 02 juillet 2024 à 15:08.

        Il y a une issue pour ça : https://github.com/rust-lang/rust/issues/69684

        Le souci, c'est que les cas simples (comme le mien) sont faciles à implémenter, mais fournir une API qui couvre à peu près bien tous les cas intéressants est beaucoup, beaucoup plus compliqué. Il faut notamment penser à : ce qui se passe quand on rencontre un symlink vers un dossier, ce qui se passe quand on n'a pas les permissions, proposer une manière de limiter la profondeur de recherche, ou de filtrer des dossiers au fur et à mesure qu'ils sont lus (pour éviter de descendre dedans), etc. Donc je peux comprendre que ce soit trop pour la stdlib, même si ça se discute.

        Je suppose que dans les 50 lignes produites par l'auteur, il y a plus que ça.

        Non, il n'y a vraiment rien de plus que la base de la base (OK, 40 lignes, pas 50) :

        use anyhow::Result;
        
        struct WalkDir {
            stack: Vec<std::fs::ReadDir>,
        }
        
        impl WalkDir {
            fn new(dir: &Path) -> Result<Self> {
                Ok(Self { stack: vec![std::fs::read_dir(dir)?]  })
            }
        }
        
        impl Iterator for WalkDir {
            type Item = Result<std::fs::DirEntry>;
            fn next(&mut self) -> Option<Self::Item> {
                macro_rules! iter_try {
                    ($expr:expr) => {
                        match $expr {
                            Ok(x) => x,
                            Err(e) => return Some(Err(e.into())),
                        }
                    }
                }
                loop {
                    let Some(top) = self.stack.last_mut() else {
                        return None;
                    };
                    let Some(next) = top.next() else {
                        self.stack.pop();
                        continue;
                    };
                    let next = iter_try!(next);
                    if iter_try!(next.file_type()).is_dir() {
                        self.stack.push(iter_try!(std::fs::read_dir(next.path())));
                    } else {
                        return Some(Ok(next));
                    }
                }
            }
        }

        C'est juste que les itérateurs sont un poil verbeux, mais rien de très notable.

        • [^] # Re: walkdir, la place est dans la bibliothèque standard ?

          Posté par  . Évalué à 2 (+1/-0).

          On pourrait vouloir inclure ce code minimaliste en std et pourtant il est déjà opiniâtre, il force la récursivité.
          Faudrait une option pour gérer ce cas, et tant qu'on y est ajoutons aussi ce cas et ….

          Pas facile de décider, mais on a le choix des crates.

          Au passage, parfois (cas géré par le dev de ta dépendance) tu peux réduire les dépendances de tes dépendances en jouant avec les features,
          tu désactives default-features et tu n'actives que celles nécessaires.

          • [^] # Re: walkdir, la place est dans la bibliothèque standard ?

            Posté par  . Évalué à 8 (+6/-0).

            En fait, il faudrait un pack de libs qui s'occupent des trucs de base qu'on voudrait voir inclus dans la std, mais qu'on ose pas trop. Genre on appellerait ça "boost" pour le gain en productivité de ceux qui ont l'habitude de piocher dedans.

  • # Le cas d'école JQuery de Javascript

    Posté par  (site web personnel, Mastodon) . Évalué à 4 (+3/-0). Dernière modification le 02 juillet 2024 à 23:46.

    Le cas d'école JQuery de Javascript représente, je pense, bien un autre problème non abordé des dépendances : La lourdeur inutile ou inefficience.

    Typiquement en Javascript, on a longtemps eu le problème de la compatibilité du code entre Mozilla Firefox et IE de Microsoft. Pour régler ce problème est arrivé JQuery, qui a vraiment été une bénédiction. Avec lui tout devenait facile. Il a même inventé des choses génial pour parcourir le DOM ou le modifier… Oui mais cela avait un coup en terme de perfs… et il a été sur-utilisé… pire 2 librairies peuvent dépendre de JQuery mais de versions différentes, résultat le navigateur est obligé de charger les 2 différentes ce" qui est autant de coût en terme de réseau (Pas de cache), de RAM et même de processeur.

    Heureusement, IE, s'est mis à respecter les standard et en plus Javascript s'est amélioré et à intégré des fonctionnalité JQuery… mais les développeurs continue a l'utiliser alors qu'il n'apporte plus grand chose. Enfin au moins dans la plupart des cas.

    En Rust ce problème ce retrouve un peu moins au niveau de l'exécution proprement dites car c'est compilé… cependant cela se retrouve au niveau du temps de compilation (et calcul de dépendances) et surtout cela se retrouve en terme de lourdeur. Pour prendre l'exemple des Regexp, est-il bien nécessaire d'embarquer tout le code hyper optimisé de regexp avec cache si comme tu le dis un split ou deux suffisent. Parce que certes le binaire n'embarquera pas le code mort, mais toutes la gestion de cache et des optims ne sont pas du code mort juste du code qui n'a aucun intérêt pour un cas simple

    Sous licence Creative common. Lisez, copiez, modifiez faites en ce que vous voulez.

    • [^] # Re: Le cas d'école JQuery de Javascript

      Posté par  (site web personnel) . Évalué à 2 (+0/-0).

      pire 2 librairies peuvent dépendre de JQuery mais de versions différentes

      La faute à celui qui audit pas ses dépendances ;)

      mais les développeurs continue a l'utiliser alors qu'il n'apporte plus grand chose

      Il y a d'abord l'argument subjectif : l'API de jQuery est plus sexy/concise/lisible que l'API vanilla.

      Et ensuite, il y a l'argument un peu moins subjectif : jQuery apporte encore beaucoup, notamment tout un écosystème de plugin :

      • des carousels
      • des date/time pickers
      • des flowcharts

      Quand tu as un site majoritairement statique, avec quelques petits endroit ou un widget interactif peu être sympa, ne pas avoir à utiliser React/Vue/Angular qui est bien plus intrusif, c'est pas déconnant.

      https://link-society.com - https://kubirds.com

      • [^] # Re: Le cas d'école JQuery de Javascript

        Posté par  (site web personnel, Mastodon) . Évalué à 1 (+0/-0).

        jQuery apporte encore beaucoup

        Oui mais généralement, les IHM web sont développées avec d'autres framework qui embarquent leurs propre solutions.
        Sinon, pour un datepicker par exemple, ok, mais la librairies peut-être compilé avec seulement les dépendances du date-picker.

        Une grande partie de l'explication est surtout dans l'habitude voire la méconnaissance.

        Sous licence Creative common. Lisez, copiez, modifiez faites en ce que vous voulez.

  • # Framework

    Posté par  (site web personnel) . Évalué à 3 (+3/-1).

    Les framework sont pour moi une bonne alternative, j'utilise beaucoup Qt (C++ est inutilisable de base de toute façon) et quand je code en Rust ou autre je regrette de pas avoir autant de fonctionnalité disponible en un seul endroit.

    Je pense que ça va à l'encontre de la pensée de gens qui sont en mode "mais rust compile que ce que tu utilises, et pourquoi j'utiliserais un truc de 100mb pour avoir 3 boutons". D'ailleurs c'est un peu aller à l'encontre de ça de tout séparer, genre la dépendance regex à plein de sous dépendance qui pourrait surrement être groupé dans la même crate.

    • [^] # Re: Framework

      Posté par  (site web personnel, Mastodon) . Évalué à 2 (+1/-0).

      • C++ fonctionne très bien sans Qt ou sans framework. C'est juste une surcouche qui apporte une solution unifié. Et aussi tente de palier les "manques" de C++ (introduction de smart-pointer et autres) un peu comme JQuery en son temps pour Javascript. C'est bien mais pas obligatoire.

      • Rust est encore récent, il commence à avoir des framework dans certains domaine (Web ou graphiques). Mais Rust ne souffre pas des défauts de C++, il n'a donc pas besoin d'un framework général comme l'est Qt.

      Sous licence Creative common. Lisez, copiez, modifiez faites en ce que vous voulez.

Envoyer un commentaire

Suivre le flux des commentaires

Note : les commentaires appartiennent à celles et ceux qui les ont postés. Nous n’en sommes pas responsables.