5 points par GN⁺ 5 일 전 | 1 commentaires | Partager sur WhatsApp
  • Un projet se divise facilement entre un flux où l’on construit tout de suite pour terminer et un flux où la recherche et la conception prennent trop d’ampleur jusqu’à faire perdre de vue le problème initial ; dans la pratique, essayer simplement de le faire fait souvent avancer davantage
  • Même en construisant une recherche fuzzy de chemins pour Emacs, les fonctionnalités annexes d’une bonne bibliothèque ont fait émerger de nouvelles exigences, ont fait gonfler la conception, et ont fini par conduire à jeter tout le code de fonctionnalité d’ancrage qui n’était finalement pas nécessaire, ce qui a rappelé YAGNI
  • Dans les diff de code, la comparaison ligne par ligne ne capture pas correctement les structures de plus haut niveau comme les fonctions ou les types, et même les outils basés sur treesitter peuvent devenir difficiles à lire si l’appariement des entités rate, en affichant de longues suppressions et ajouts
  • La bonne direction consiste d’abord à construire un outil au périmètre minimal adapté à la revue tour par tour des sorties d’un LLM, en commençant par l’extraction d’entités en Rust et un appariement simple, afin d’obtenir rapidement une vue d’ensemble des changements de haut niveau

Trop réfléchir et élargir le périmètre

  • Les projets se séparent facilement entre le flux où l’on construit tout de suite pour finir, et celui où l’on creuse des précédents jusqu’à élargir le périmètre sans finalement résoudre le problème de départ
  • Une étagère de cuisine fabriquée pendant le week-end a été conçue autour d’un café, avec quelques itérations sur un support imprimé en 3D, puis terminée dans le week-end en utilisant des matériaux restants et de la peinture
    • Le CAD du support pour bac Ikea est publié sur OnShape CAD
    • Les matériaux ont été réutilisés à partir de restes de l’atelier, et les coins ont été poncés à l’œil avec une palm sander
  • Pour cette étagère, le principal critère de réussite n’était pas tant de fabriquer exactement l’objet parfait pour la cuisine que de prendre plaisir à faire du bois avec un ami, ce qui a réduit le besoin de trop débattre des critères de détail
  • À l’inverse, dans la recherche d’un outil de diff structurel, le résultat de difftastic semblait insuffisant, ce qui a conduit à quatre heures de recherche sur les outils et workflows associés, avant de revenir au critère initial : un meilleur workflow de diff dans Emacs
  • Des centres d’intérêt de longue date, comme une interface de prototypage matériel, un langage mêlant Clojure et Rust, ou un langage pour la CAO, ont consommé des centaines d’heures en recherche de fond et en petits prototypes, sans encore déboucher sur un résultat qui réponde directement à la motivation de départ
  • Dans les projets de langage et de CAO, les critères de réussite restent flous : faut-il remplacer Rust ou Clojure, ne traiter qu’une partie du problème, se contenter d’un terrain de jeu pour apprendre, remplacer une CAO commerciale, ou créer quelque chose d’utile aussi pour d’autres personnes ?
  • Examiner ce type de questions a de la valeur, mais il semble préférable de construire beaucoup de choses concrètement plutôt que de simplement en examiner beaucoup
  • Même si, avec le recul, le résultat s’avère clairement mauvais, le simple fait d’essayer fait globalement davantage progresser

La loi de conservation de l’élargissement du périmètre

  • Le temps passé à construire sans trop réfléchir a aussi ses limites et demande un équilibre, et l’expérience d’avoir fait écrire beaucoup de code par un agent LLM avant de tout jeter a ravivé l’idée de YAGNI
  • L’objectif était de créer dans Emacs une recherche fuzzy sur tout le système de fichiers, dans le style de Finda ; une version similaire avait déjà été codée à la main auparavant, donc l’idée était qu’en supervisant un LLM cela pourrait être bouclé en quelques heures
  • Au départ, une conversation de planification a recommandé Nucleo, adopté parce qu’il était bien conçu et bien documenté, et permettait de récupérer les fonctionnalités smart case et Unicode normalization
    • Par exemple, la requête foo correspond à Foo comme à foo, mais Foo ne correspond pas à foo
    • Le traitement de cafe et café suit la même logique
  • Le problème n’était pas la bonne bibliothèque elle-même, mais le fait que Nucleo prenne aussi en charge une fonctionnalité d’ancrage
  • Dans un corpus composé uniquement de chemins de fichiers, un ancrage de début de ligne semblait inutile ; l’idée a donc été de l’interpréter comme un ancrage sur segment de chemin
    • Par exemple, ^foo devait correspondre à /root/foobar/ mais pas à /root/barfoo/
  • Pour traiter cela efficacement, l’index devait mémoriser les frontières de segments et permettre de tester rapidement une requête sur chaque segment
  • À cela s’ajoutait la nécessité de gérer des requêtes ancrées avec slash comme ^foo/bar, et une vérification segment par segment ne suffisait plus pour faire correspondre correctement un chemin comme /root/foo/bar/baz/
  • Quelques heures supplémentaires ont été consacrées à cette conception, à échanger des idées avec le LLM, puis à écrire du code enveloppant les types de Nucleo, avant de conclure que le code était devenu trop gros et peu satisfaisant, et de réécrire finalement un wrapper plus petit
  • Après une pause, il est revenu à l’esprit qu’il n’y avait pas de souvenir d’avoir réellement eu besoin de la fonctionnalité d’ancrage dans Finda, et que dans un corpus de chemins, ajouter / au début ou à la fin d’une requête remplaçait la plupart des usages de l’ancrage
    • Seul l’ancrage sur la fin d’un nom de fichier restait comme exception
  • Tout le code lié à l’ancrage a donc été supprimé, et il reste difficile de savoir si cela a malgré tout été plus avantageux que d’écrire directement depuis le début, sans discussions avec un LLM ni avec d’autres personnes
  • Plus la vitesse de programmation augmente, plus il semble exister une sorte de loi de conservation faisant croître en parallèle les fonctionnalités inutiles, les rabbit holes et les détours

Diff structurel

  • Dans le code, un diff désigne généralement un résumé des modifications ligne par ligne entre deux versions d’un fichier, et la vue unifiée marque les ajouts et suppressions avec + et -
  • Le même diff peut aussi être rendu en comparaison côte à côte, et cette présentation peut devenir plus facile à lire quand les changements se complexifient
  • Le problème du diff ligne par ligne est qu’il ne reconnaît pas les structures de plus haut niveau comme les fonctions ou les types ; si les accolades finissent par s’aligner d’une manière ou d’une autre, des marqueurs peuvent être omis alors même qu’il s’agit de fonctions différentes
  • difftastic tente de réduire ce problème à l’aide de l’arbre de syntaxe concret fourni par treesitter, mais l’appariement des entités entre versions ne fonctionne pas toujours bien
  • Dans le diff qui a servi de déclencheur, struct PendingClick n’était pas mis en correspondance entre les deux côtés, et apparaissait comme supprimé à gauche puis ajouté à droite
  • Sans creuser la cause exacte de cet échec d’appariement, le jugement était qu’il valait mieux voir PendingClickRequest et PendingClick comme des éléments correspondants de part et d’autre, même si cela allongeait l’ensemble du diff

Outils et références sur le diff structurel

  • Parmi les outils de semantic diff les plus aboutis et soigneusement polis, semanticdiff.com est cité en premier
    • Le service est proposé par une petite entreprise allemande, avec un plugin VSCode gratuit et une web app affichant les diff de PR GitHub
    • En revanche, aucun code de bibliothèque n’est fourni comme base pour le workflow souhaité
    • L’article semanticdiff vs. difftastic contient de nombreux détails utiles, dont le problème de difftastic qui n’affiche même pas les changements d’indentation significatifs en Python
    • Dans un commentaire HN, l’un des auteurs explique qu’ils ont fini par s’éloigner de treesitter pour le traitement sémantique, car des mots-clés dépendants du contexte et le comportement du lexer pouvaient faire échouer le parsing, au point de casser l’outil même si un nom comme async était utilisé comme paramètre
  • diffsitter est basé sur treesitter et inclut un serveur MCP
    • Le dépôt a beaucoup d’étoiles GitHub, mais la documentation ne semblait pas particulièrement claire, et il était difficile de trouver des explications sur son fonctionnement
    • Le wiki de difftastic indique qu’il effectue une longest-common-subsequence sur les feuilles de l’arbre
  • gumtree est un outil issu d’un contexte de recherche universitaire datant de 2014
    • Il nécessite Java, ce qui ne convient pas à un usage personnel visant un outil rapide à utiliser depuis Emacs
  • mergiraf est un merge-driver basé sur treesitter écrit en Rust
    • Son architecture overview est bien structurée, et le projet utilise en interne l’algorithme Gumtree
    • La documentation et les schémas donnent l’impression d’un projet rédigé avec soin
    • Dans un commentaire HN, l’auteur de semanticdiff.com indique que GumTree produit rapidement des résultats, mais que même avec plusieurs améliorations proposées par des articles ultérieurs, il renvoyait encore assez souvent de mauvais appariements, ce qui les a conduits à passer à une approche basée sur Dijkstra minimisant le coût de mapping
  • weave est un autre merge-driver basé sur treesitter, écrit en Rust
    • Son landing page très tape-à-l’œil, son grand nombre d’étoiles GitHub et son serveur MCP donnent une impression générale un peu exagérée
    • Le crate d’extraction d’entités sem a aussi été examiné
    • Le code central du diff est correct mais un peu verbeux, et l’appariement des entités repose sur un algorithme glouton
    • Le modèle de données ne détecte pas les déplacements à l’intérieur d’un fichier, alors que ce type de déplacement peut avoir du sens
    • Il contient aussi beaucoup d’analyse d’impact heuristique qui semble nécessiter une intégration linguistique plus forte pour inspirer confiance
      • En exécutant sem diff --verbose HEAD~4, un bug a même produit une sortie où des lignes inchangées apparaissaient comme modifiées
    • L’ensemble contenait trop de fonctionnalités hypothétiquement utiles mais encore à 80 % d’achèvement pour servir de base, même si le niveau atteint en trois mois reste impressionnant
  • diffast calcule la tree edit-distance d’AST à partir d’un algorithme issu d’un article académique de 2008
    • Il prend en charge Python, Java, Verilog, Fortran et C/C++ via des parseurs dédiés
    • La example AST differences gallery est bien organisée
    • Il peut exporter l’information sous forme de tuples pour l’exploiter en datalog
  • autochrome est un outil de diff spécifique à Clojure, fondé sur la programmation dynamique
    • Son explication visuelle et son parcours d’exemples sont excellents
  • L’article de Tristan Hume, Designing a Tree Diff Algorithm Using Dynamic Programming and A*, reste une référence utile sur la conception d’algorithmes de tree diff

Workflow visé et plan au périmètre minimal

  • Le cas d’usage principal est la revue tour par tour des sorties d’un LLM, sans laisser un agent générer d’un coup plus de 10 000 lignes de code
  • L’idée est de confier à l’agent des tâches au périmètre borné, de revenir quelques minutes plus tard, de regarder une vue d’ensemble des changements, puis de corriger directement dans Emacs, de tout jeter pour recommencer, ou d’en réécrire une partie soi-même
  • Le workflow souhaité consiste d’abord à voir une vue d’ensemble de haut niveau indiquant quels types, fonctions et méthodes ont été ajoutés, supprimés ou modifiés
  • À partir de là, il faut pouvoir déplier rapidement un diff textuel par entité, et étendre naturellement le résumé vers le diff détaillé
  • Il faut aussi pouvoir corriger immédiatement sans passer les changements dans un autre endroit, avec une édition inline évitant de basculer de l’écran de diff à l’écran de fichier
  • L’objectif est de transposer le workflow de revue et de staging de Magit du niveau fichier/ligne au niveau entité
  • En accord avec cette leçon redécouverte sur le périmètre minimal, le plan est de commencer par construire rapidement un framework d’extraction d’entités basé sur treesitter visant uniquement Rust
  • L’appariement commencera par une approche gloutonne simple, et le diff sera rendu en ligne de commande
  • Si cela produit de meilleurs résultats que difftastic sur certains commits, l’étape suivante sera de le relier à un workflow Emacs plus interactif de type Magit
    • La possibilité de réutiliser Magit lui-même reste ouverte si c’est faisable
    • La prise en charge de nouveaux langages sera ajoutée au fur et à mesure des besoins
    • Plus tard, une fois la base en place, une mise en correspondance globale fondée sur un score pourra être explorée à la place du simple glouton
  • Si le résultat devient suffisamment satisfaisant, il pourrait être publié, mais accumuler des étoiles GitHub ou du karma HN n’est pas l’objectif ; cela peut aussi rester un outil utilisé seul, discrètement
  • La conclusion rappelle qu’il arrive qu’on ne veuille qu’une simple étagère, et réaffirme ainsi l’attitude consistant à ne construire que ce qui est nécessaire plutôt qu’à trop étendre

1 commentaires

 
GN⁺ 5 일 전
Avis sur Hacker News
  • Je trouve que ça illustre très bien la plus grande difficulté de la recherche en doctorat
    On choisit un sujet intéressant, on lit autant que possible les travaux antérieurs, puis on réalise combien de choses proches de ce qu’on voulait faire existent déjà, ce qui favorise facilement le scope creep
    Une fois l’énergie et l’enthousiasme du début épuisés, il faut encore forcer sur les 20 à 30 % restants pour amener le tout à un état publiable

    • Au jour 1, on commence en se disant qu’on va appliquer un catalyseur industriel existant à un nouvel usage pour réduire le coût de production d’un précurseur de médicament essentiel
      Au jour 400, après avoir presque expliqué la théorie du tout, on essaie de construire un dispositif expérimental en orbite autour d’un point de Lagrange pour détecter la particule universelle qui médie toutes les forces de l’univers connu
    • Cette sensation me parle de façon extrêmement concrète
      Je me demande comment on peut atténuer ça
    • Si la plupart des doctorants traversent ça, c’est à mon avis parce que le but d’un PhD est au fond de prouver qu’on est capable de faire de la science normale
      En pratique, c’est souvent un travail qui consiste à faire passer l’observabilité d’un système de 1 % à 1,001 %, et ça ressemble davantage à un rite de passage pour entrer dans une carrière académique
      C’est pour ça qu’on voit rarement des thèses vraiment passionnantes, extraordinairement nouvelles ou directement applicables à la science
    • Et en plus, il faut supporter tout ça alors que le regret d’avoir commencé un PhD devient de plus en plus lourd
    • Commencer en essayant de lire absolument toute la littérature existante me semble clairement être une mauvaise approche
      En réalité, j’ai rarement vu quelqu’un faire de la recherche ainsi ; en général, on lit deux ou trois articles puis on construit à partir de là
      Il vaut mieux approfondir la littérature une fois qu’on a déjà obtenu quelques résultats et qu’on commence à les mettre en forme par écrit
  • L’idée que mieux, ça suffit me revient sans cesse
    Les petites améliorations s’accumulent avec le temps, et comme rien n’est parfaitement nouveau dès le départ, vouloir rester assis à concevoir une architecture parfaite produit souvent l’effet inverse
    L’idée selon laquelle l’obstacle devient le chemin s’applique aussi très bien ici

    • La formule disant qu’il ne faut pas laisser le parfait devenir l’ennemi du suffisamment bon est exactement juste
      Un collègue avec qui je travaillais critiquait les changements de code en disant parfois, quand il sentait qu’il pinçait sur des détails trop mineurs : « c’est mieux qu’avant »
      Ça permettait de signaler ce qui pouvait être amélioré tout en donnant en même temps l’autorisation d’avancer même s’il restait quelques défauts mineurs, et je soutiens fortement cette attitude
    • Au fond, c’est du perfectionnisme
      Avant, je pensais que le perfectionnisme se limitait à poursuivre des accomplissements excessivement élevés de manière forcée, mais le fait de ne pas pouvoir accepter quelque chose d’imparfait au point d’abandonner sans progresser peut aussi être une forme de perfectionnisme
      La procrastination sur les gros sujets a souvent la même racine
  • J’ai bien aimé ce qu’a dit le CEO de Rec Room
    Les équipes disent toujours qu’elles auraient aimé rendre un projet plus court ; elles disent rarement qu’elles auraient voulu repousser davantage la sortie, le rendre plus complexe et encore plus peaufiné
    Ça ne s’applique sans doute pas à 100 % à toutes les situations, mais s’il faut se tromper, je pense qu’il vaut mieux faire petit et lancer tôt que voir trop grand et gaspiller du temps

  • Les humains ont naturellement tendance à avoir des idées similaires, donc quand on termine un projet sans savoir ce qui existe déjà, on finit facilement par réinventer certaines choses
    À l’inverse, si on se renseigne d’abord, on peut perdre son élan en découvrant qu’une partie de l’idée n’est qu’une répétition de quelque chose d’existant
    Malgré tout, aller jusqu’au bout pour apprendre soi-même peut être la chose la plus importante
    Bien sûr, c’est plus compliqué quand il faut produire un résultat académique nouveau ou gagner de l’argent avec un projet véritablement original, mais même dans ces domaines, on est souvent étonnamment tolérant dès qu’on tord un peu l’existant

  • Je vis exactement ça en ce moment sur un side project
    Le domaine est l’Information Retrieval, donc j’ai peu d’expérience et il y a naturellement énormément de prior art à apprendre ou à intégrer
    Du coup, après avoir lu ce billet, je penche davantage vers l’idée de construire d’abord mon propre truc, puis de ne regarder les précédents que lorsque je bloque ou que j’ai besoin d’idées
    En même temps, dans le documentaire récent sur Clojure, Rich Hickey donnait plutôt l’impression d’avoir travaillé après avoir longuement creusé les travaux antérieurs, les articles et d’autres langages
    Mais il avait déjà créé d’autres langages auparavant, donc dans l’ensemble, l’image plus large commence quand même par l’apprentissage en fabriquant soi-même
    Il ne faudrait peut-être pas passer trop de temps à seulement réfléchir, mais commencer par construire, accumuler des leçons dans la pratique, se heurter à des murs, puis seulement ensuite aller plus loin dans l’enquête quand cela devient nécessaire

  • Se fixer une deadline a résolu la plupart de mes problèmes de scope creep
    D’après mon expérience, les projets avec une échéance dure, comme les game jams ou les compétitions de programmation, sont plus faciles à terminer, alors que les projets ouverts sont bien plus difficiles à mener au bout
    J’y vois un parallèle avec le fait que le standard C++ sorte tous les trois ans au lieu d’attendre que toutes les fonctionnalités souhaitées soient prêtes
    https://news.ycombinator.com/item?id=20428703

  • Le texte était intéressant, mais la pensée de l’auteur m’a semblé un peu éparpillée

    • Le cœur du sujet ici, c’est finalement le scope creep
    • Ce n’est pas vraiment un billet de blog qui creuse un thème précis, mais plutôt une mise à jour de newsletter destinée aux personnes qui suivent cet auteur
  • Pour quelqu’un qui dit être dépassé par le scope creep, l’auteur semble malgré tout accomplir énormément de choses, au point d’avoir à la fin du texte une grande quantité de liens sur toutes sortes de sujets
    Au fond, il a l’air d’aimer sincèrement apprendre et expérimenter plein de choses, et le processus même de tomber dans des rabbit holes semble lui procurer une stimulation intellectuelle agréable

  • En travaillant seul, j’ai eu une prise de conscience qui m’a beaucoup aidé
    La plupart de ce qui semblait être des abstractions indispensables n’était en fait que du scope creep renommé
    À force d’ajouter des flags pour chaque nouvelle fonctionnalité, j’ai fini par voir un motif dans mon code et j’ai posé une règle
    Une fonctionnalité ne serait pas déployée sans test du comportement flag-off
    À partir de là, j’ai cessé de voir les flags comme une échappatoire pour les considérer comme une partie du produit, et trois fonctionnalités qui étaient dans le backlog ont naturellement disparu dès que j’ai commencé à les voir ainsi

  • Le surcroît de planification et le scope creep sont bien des problèmes, mais à l’inverse il faut aussi se méfier d’un basculement excessif vers le développement à l’instinct
    Parmi mes projets les plus réussis, certains venaient du fait que j’avais planifié et revu à l’avance la plupart des fonctionnalités en modélisant les données avant même de construire un logiciel réellement fonctionnel
    À cette étape, on ne sait souvent pas bien ce qui est excessif, et si j’enlève des fonctionnalités que moi ou les utilisateurs risquons de vouloir, je perds ensuite beaucoup de temps à repenser profondément le cœur du code
    À l’inverse, si je me trompe dans l’autre sens, le projet devient trop vaste et on appelle ça du scope creep
    Au final, ce jugement dépend de la qualité de votre compréhension du domaine
    Si vous connaissez moins bien le domaine que vous ne le pensez, il y aura beaucoup de refonte ; si vous le connaissez mieux que vous ne le pensez, vous auriez en fait pu viser beaucoup plus grand et vous aurez perdu du temps à avancer à petits pas
    Quel que soit le côté où l’on se trompe, il reste des regrets, donc ça me semble au fond être une grande question de jugement

    • La méthode idéale consiste sans doute à passer suffisamment de temps en phase d’analyse pour remplir son esprit du bon contexte, tout en restant prêt, au moment de construire, à abandonner une solution surconçue et à implémenter directement ce qui paraît le plus naturel
      Il ne faut pas tomber dans le sophisme des coûts irrécupérables, et ce n’est pas parce qu’on a passé quelques heures à étudier un sujet de niveau doctorat qu’il faut absolument l’utiliser dans le projet
      Si ça ne correspond pas exactement au problème présent, mieux vaut l’écarter franchement
    • Il ne faut pas trop craindre de se tromper ; il vaut mieux essayer, puis ajuster si nécessaire