1 points par GN⁺ 2025-09-09 | 4 commentaires | Partager sur WhatsApp
  • Par le passé, les environnements de développement Ada avaient déjà résolu le problème du formatage du code
  • Les développeurs manipulaient le code sous forme de représentation intermédiaire (IR) DIANA, puis l’affichaient avec les réglages de pretty-printing de leur choix
  • Aujourd’hui encore, des inefficacités et débats récurrents subsistent autour des linters et des politiques de formatage
  • À l’époque, la station de travail Rational R1000 offrait un environnement de développement et des fonctionnalités innovants
  • À partir de cette approche d’il y a une génération pour le problème du formatage du code, l’article propose des idées pour faire évoluer les pratiques de développement actuelles

Le débat sur le formatage du code — la solution des années 1980

  • L’auteur évoque son expérience avec M. Paige, professeur d’informatique qui avait participé à un projet de compilateur Ada lorsqu’il était au lycée
  • En 2016, alors qu’il se plaignait des difficultés de configuration d’un outil de linter en demandant « pourquoi doit-on encore subir ce genre de problème ? », on lui a raconté qu’une solution existait déjà depuis plus de 40 ans

L’émergence d’Ada et de DIANA

  • Au lieu de stocker du code source textuel, les développeurs Ada utilisaient une représentation intermédiaire appelée DIANA (Descriptive Intermediate Attributed Notation for Ada)
  • Chaque développeur pouvait consulter le source selon ses propres réglages de pretty-printing
  • Il n’y avait ni débats sur le formatage ni problèmes de linter, et l’éditeur permettait de modifier directement l’arbre du programme, de manière similaire à l’édition projectionnelle moderne

Rational R1000 — un environnement de développement pionnier

  • La station de travail Rational R1000 intégrait de nombreuses fonctions avancées, comme la compilation incrémentale, l’analyse statique, la gestion de versions et le débogage
  • Elle a été utilisée pour des projets logiciels critiques, notamment pour le DoD, la Station spatiale internationale (ISS) et le chasseur F-22, et a aussi contribué à la naissance d’UML
  • Selon Grady Booch, le R1000 était une machine fondée sur DIANA qui ne stockait pas le code source, mais utilisait uniquement le pretty-printing de l’arbre DIANA

Les avantages du développement fondé sur DIANA

  • Plus besoin de débats sur le formatage, de configuration de linter ou d’uniformisation de l’environnement d’édition
  • Grâce à l’accélération matérielle, il offrait une expérience de développement innovante avec compilation incrémentale, refactorisation aisée et intégration rapide
  • Cela a eu un impact important sur l’efficacité de développement et le travail sur les grands systèmes

Ce que cela implique aujourd’hui

  • La compilation accélérée par le matériel est moins importante aujourd’hui, mais le problème du formatage reste encore insuffisamment résolu
  • Même si l’approche dominante n’est ni l’édition projectionnelle ni les environnements live, il est peut-être temps de réfléchir, comme autrefois, à l’adoption de pratiques de développement plus efficaces et moins sujettes aux débats

Références

  • En étudiant ce sujet, l’auteur cite divers documents et rapports techniques sur le R1000

4 commentaires

 
ndrgrd 2025-09-10

À ma connaissance, il existe déjà une fonctionnalité qui formate automatiquement le code partagé à l’aide d’une configuration unifiée, et il me semble que les entreprises l’utilisent beaucoup.

 
euphcat 2025-09-10

Il me semble que le sujet n’est pas le formatage automatique, mais plutôt l’idée qu’un formatage donné serait supérieur, ou même le fait de devoir abandonner son propre formatage pour s’adapter à un formatage étranger, ce qui en soi serait inutile. La logique est qu’il suffirait de stocker une représentation intermédiaire indépendante du formatage, puis de faire un pretty-printing selon les préférences de chaque utilisateur, dans la forme qui lui convient.

 
ndrgrd 2025-09-10

Je voulais dire qu’avec le formatage automatique, on peut accomplir exactement la même chose avec les langages existants, même sans expressions intermédiaires, mais mon explication n’était pas assez claire.

 
GN⁺ 2025-09-09
Avis Hacker News
  • Je ne comprends pas pourquoi les gens accordent autant d’importance au paramétrage du linter, c’est clairement un faux débat inutile : il suffit de choisir un seul réglage, de lancer automatiquement le linter et c’est tout ; j’ai l’impression qu’il est plus important d’avoir du temps pour faire de la vraie ingénierie logicielle. Quel que soit le format, si l’équipe le choisit et l’utilise, on s’y habitue en une semaine.
    • Il faut rappeler qu’un formateur de code source et un programme de linting sont deux choses différentes : le formateur ne s’occupe que de la mise en forme du code, tandis que le linter aide à repérer des bugs ou erreurs potentiels dans le code. Certains outils font les deux, mais c’est un détail d’implémentation. Pour savoir ce qu’est le lint, on peut consulter https://en.wikipedia.org/wiki/Lint_(software).
    • Je passe la plupart de mon temps à « lire » du code, et sa mise en page influe sur ma vitesse de lecture. On peut s’habituer à différentes mises en page, mais elles ne sont pas toutes aussi faciles à lire. Je mémorise le code via des motifs visuels, et je le lis en le découpant selon sa disposition. Paradoxalement, même si j’ai de l’aphantasie et que je ne peux pas visualiser mentalement, je retiens mieux grâce aux indices visuels.
    • Certains réglages de linter ont clairement des avantages. Par exemple, utiliser des trailing commas dans un tableau permet de n’éditer qu’une seule ligne quand on ajoute un nouvel élément à la fin, et le diff est plus simple. Donc un mauvais choix me complique la vie. C’est pareil pour les listes triées ou les include : si on ne trie pas, on ajoute toujours à la fin et cela provoque beaucoup de conflits de fusion. Comme avec les autoformatteurs, le tri devrait aussi faire gagner du temps. Et je suis sensible aux styles incohérents : le plus important est d’uniformiser sur un seul style.
    • Je ne m’attache pas tant que ça aux options de détail, mais je pense qu’un paramétrage commun du linter est indispensable pour réduire le bruit inutile lors des PR. Je trouve peu élégant que git ou divers langages ne traitent les choses qu’au niveau des lignes. En vingt ans de carrière, je n’ai vu qu’une seule fois un exemple plus raffiné, comme en Ada. Il est difficile de construire quelque chose de vraiment élégant et efficace, et quand il existe déjà des alternatives suffisamment bonnes, c’est encore plus dur de les faire adopter largement.
    • Moi aussi, je suis tombé dans ce débat quand j’étais plus jeune. Si c’était le cas, c’est parce que je m’imaginais être le plus intelligent de l’équipe. Je pensais que mon avis était le plus important. J’étais convaincu que tout le monde devait m’écouter. Mais j’avais tort.
  • Le compromis à considérer ici, c’est que si on utilise un format autre que du texte, on perd en compatibilité avec des outils génériques comme grep, diff, sed ou le contrôle de version. Au final, on devient plus dépendant d’outils, de formats ou d’extensions d’IDE spécialisés. La force de la philosophie Unix, c’est la composabilité via le texte brut. Il y a une question qui tranche facilement ce débat : si l’éditeur permettait librement de configurer uniquement la largeur des espaces, est-ce qu’il resterait vraiment des arguments chez les partisans des tabulations ?
    • L’approche textuelle a des avantages, mais j’ai l’impression qu’au lieu de gravir une montagne plus haute juste un peu plus loin, celle de l’édition projectionnelle, on reste coincés à errer au pied. Tous les exemples cités fonctionnent mieux sur du code qui possède des informations structurelles : par exemple, pour la recherche de symboles, que j’utilise bien plus souvent que du grep texte, on peut utiliser ast-grep ; pour les diff, on peut avoir quelque chose comme semanticdiff.com qui gère les déplacements structurels et ignore les changements sans signification ; à la place de sed, on peut utiliser @codemod/cli ; côté contrôle de version, des langages comme Unison ont beaucoup expérimenté l’évitement automatique des conflits dus à des changements non sémantiques comme l’ordre ou les espaces.
    • Cette idée revient régulièrement, mais elle a un mauvais rapport coût/bénéfice puisqu’elle exige des outils extrêmement complexes au lieu d’un simple passage de formateur. Que chaque développeur voie le code à sa sauce n’a en réalité pas beaucoup d’intérêt. Dans toutes les équipes avec lesquelles j’ai travaillé, on a défini des règles communes et on les a fait appliquer par un formateur ; même quand on n’était pas d’accord au départ, on s’y habituait vite. Les débats sur le formatting sont un exemple typique de perte de temps.
    • grep, diff, sed et les fusions ligne par ligne sont en réalité de mauvais outils pour manipuler du code. Plutôt que de débattre de ça, il vaudrait mieux réfléchir à de meilleurs outils.
    • Si la représentation intermédiaire (Intermediate Representation) est conservée sous forme de texte, grep/diff/sed peuvent tous fonctionner. Si on n’utilise que des formateurs basés sur l’AST, le code peut être stocké sous une forme normalisée correspondant à un AST donné ; l’éditeur parse ensuite cet AST, l’affiche selon le format souhaité par l’utilisateur, puis au moment de sauvegarder le reconvertit dans cette forme normalisée.
    • Tout le système d’exploitation a été produit en s’appuyant sur ce type de fichiers source. La philosophie Unix ne brille vraiment que si tous les outils ne considèrent que du texte brut et savent le parser.
  • Je pense qu’il y a clairement une dimension typographique dans le formatting du code source. Je ne suis pas d’accord avec l’idée que ce serait uniquement une question de goût personnel. Certains formats sont des outils efficaces pour transmettre le sens et la structure. Si un outil automatisé sérialise uniquement le minimum de tokens puis restaure le tout, cette valeur disparaît. https://naildrivin5.com/blog/2013/05/17/source-code-typograp...
    • Les professionnels de l’imprimerie ont longtemps apporté beaucoup de soin aux espacements et aux alignements dans les tableaux ou les formules. Les personnes extérieures s’en rendent mal compte, mais c’était extrêmement important. Je pense qu’il est possible de faire progresser le formatting du code source vers quelque chose de plus raffiné.
    • Par exemple, certains se plaignent que le formateur black pour Python découpe les requêtes SQLAlchemy en trop de lignes, au point de nuire à la lisibilité.
    • J’ai toujours trouvé étrange que tant de gens ne perçoivent pas l’importance de la typographie du code.
    • Je trouve qu’accorder de l’attention à la typographie tout en suivant sans recul les conventions des langages de programmation est au contraire la pire direction possible : par exemple, on accepte volontiers des mots comme register, tout en gardant la convention qui note les pointeurs avec un astérisque (*). Pourtant, chaque notation pourrait être plus intuitive et plus claire, mais on s’obstine à conserver des façons complexes et difficiles à lire. On pourrait aussi remplacer des symboles ou mots-clés réservés par des termes plus familiers et naturels, mais on est trop attachés aux conventions traditionnelles ou existantes, au prix de la lisibilité. L’auteur explique par exemple que la fonction strcpy en C pourrait être entièrement repensée avec des termes et une syntaxe plus clairs et plus faciles à lire.
    • Il explique que les déclarations de paramètres en C sont composées de modificateurs, du type de données et du nom, puis pointe les problèmes de lisibilité des déclarations complexes avec des exemples comme char *argv[]. Il estime aussi que le style de formatting à la C++ (par exemple char* a, b) peut induire en erreur, et qu’il vaut mieux l’éviter.
  • Je ne suis pas d’accord avec la prémisse de ce débat. Le formatting du code est un moyen de communication extrêmement important. Un bon formatting signale qu’un développeur (1) comprend l’importance du formatting, (2) respecte bien les règles, (3) a du goût et (4) sait faire preuve de jugement dans les cas exceptionnels. Ces quatre points sont des compétences importantes qui dépassent largement le simple formatting et influencent les capacités de développement dans leur ensemble. Or les autoformatteurs et les règles de linter affaiblissent ce signal et, comme avec la loi de Goodhart, finissent par faire perdre l’intention d’origine.
    • Il recommande vivement de lire directement le billet de blog, car il est court et simple, et de ne pas réagir négativement au seul titre ; il vaut mieux comprendre le contexte des mots « should » et « unnecessary ».
    • À mon avis, quelqu’un d’indifférent au formatting n’a soit (1) jamais connu l’édition d’un même fichier par plusieurs personnes, soit (2) jamais fait de fusion de branches, soit (3) jamais maintenu une grosse base de code, soit (4) jamais fait de refactoring à grande échelle, soit (5) jamais exploré l’historique du code ni utilisé d’outils de diff/comparaison, soit (6) jamais développé d’outils d’automatisation pour une base de code, soit (7) a une façon de travailler centrée uniquement sur soi sans conscience de la collaboration.
    • Si la réponse à tous ces points est « non », alors il suffit simplement d’automatiser le formatting au moment du passage des tests ou du commit, et d’échouer dans la CI si l’automatisation n’a pas été appliquée. Au lieu d’obséder sur les détails, il est même avantageux de suivre les réglages par défaut et d’abandonner son style personnel. Si on laisse les valeurs par défaut, le code paraît familier à quiconque le lit. De plus, même si formatting et linting sont différents, on peut résoudre les deux d’un coup avec des outils d’automatisation.
    • Il ajoute en plaisantant qu’on pourrait apprendre à faire la même évaluation à partir de l’écriture manuscrite, et qu’il faudrait donc désormais soumettre les PR en écriture cursive.
    • Compter sur le « goût » pour choisir de bonnes règles de formatting risque au contraire de provoquer des débats et de faire perdre du temps. Mieux vaut s’en remettre à un formateur intégré comme en Go ou en Rust.
  • Les tentatives de stocker le code sous forme d’arbre syntaxique, puis de traiter le code visible par les humains comme un rendu, existent depuis 20 à 25 ans. Ce courant remonte aux années 90, lorsque le refactoring est devenu populaire. Des IDE comme Visual Age ont déjà adopté un modèle où le code est stocké dans une base de données plutôt que dans le système de fichiers. L’intentional programming ou le développement dirigé par les modèles font aussi partie de ce cycle. L’essence du refactoring, c’est la transformation d’AST : renommer un symbole devient très simple, sans avoir besoin de chercher/remplacer directement dans le code source. Pourtant, les gens restent habitués à éditer des fichiers, et il existe une résistance et des frictions qui empêchent une approche stockant directement la structure de se généraliser. Si l’on continue à débattre du formatting après tout ce temps, c’est justement que cela montre le besoin de cette alternative. Il est courant de voir des cas où même un renommage de symbole robuste n’est pas correctement fourni au niveau du langage ou de l’éditeur.
    • Selon un autre avis, c’est un mélange de couches d’abstraction. L’AST doit de toute façon être stocké dans un fichier, donc cela ne diffère pas tant que ça du fait d’exécuter des outils conscients de l’AST sur un fichier lisible par les humains. Le format de stockage n’est pas si important ; le vrai sujet, ce sont des outils plus intelligents. L’exemple de Roslyn chez Microsoft ou l’orientation des compilateurs modernes vers des API d’interaction avec les bases de code vont dans ce sens.
  • Un exemple concret montre qu’un certain formatting ne peut pas être déduit uniquement à partir de l’AST. Par exemple, quand plusieurs lignes d’assignation sont présentes, il existe différentes possibilités : aligner trois lignes les unes sous les autres, aligner sur =, ou insérer des tabulations pour faire davantage ressortir la profondeur de la structure. Selon qu’on veuille mettre en valeur les valeurs elles-mêmes, on peut aligner les nombres à droite, ou bien aligner les champs membres pour faire ressortir la structure. L’auteur soutient que sans métadonnées supplémentaires, ces informations ne sont pas extractibles depuis l’AST.
    • Je vois ce que ça veut dire, mais en pratique on n’utilise que les deux premières méthodes. Le but réel n’était pas tant l’emphase que la lisibilité. Il y a bien une perte quand on convertit vers un AST, mais dans ce cas on gagne bien davantage. En plus, on peut tout à fait conserver des variantes d’emphase dans l’AST. On pourrait par exemple utiliser setValue([bar, glob], 1) ou une syntaxe de commentaires pour surcharger le style, parmi d’autres solutions possibles.
    • Le « bon formatting du code » reste au fond subjectif : comme dans l’exemple, certains préfèrent 2/4/8 espaces, d’autres l’alignement par colonnes. L’AST ne contient pas les informations de formatting du code source, donc on ne peut pas les déduire automatiquement.
    • Les deuxième et troisième exemples de formatting relèvent en réalité d’un problème de conception structurelle, une violation de la loi de Déméter, et non d’une question de formatting.
  • L’édition projectionnelle peut aussi s’appliquer à du code source textuel. Il existe même une vidéo montrant un exemple dans JetBrains MPS où du code est rendu sous forme de tableau : https://www.youtube.com/watch?v=XolJx4GfMmg&t=63s. L’auteur dit souhaiter une fonctionnalité d’IDE qui rendrait un dictionnaire sous forme de tableau. Il existe déjà aujourd’hui certains équivalents partiels, comme le code folding, les inlay hints ou les docstrings rendues en HTML. https://x.com/efortis/status/1922427544470438381
  • Il est avancé que nous avons une limite qui nous empêche d’accepter immédiatement quelque chose de plus abstrait que le plain text. Même quand on essaie, on finit toujours par rétrograder vers une projection en texte brut. Selon cette idée, une « gigantesque table de correspondance (GLUT) » accumulée de Morse à Unicode a façonné notre culture actuelle du décodage des symboles. Si on élève le niveau d’abstraction, on peut créer des jeux de symboles plus adaptés aux applications, mais les outils correspondants n’émergent pas. Au final, on reconvertit simplement en texte à transmettre puis à parser, comme avec CSV ou Markdown. XML a aussi parfois ses éditeurs dédiés, mais les gens veulent malgré tout l’éditer en texte brut. Cela dit, l’auteur ne voit pas non plus le texte brut comme une solution parfaitement positive, à cause notamment des encodages de caractères et des caractères spéciaux.
  • Je me demande souvent pourquoi l’artefact stocké et la projection du code que nous voyons réellement devraient être identiques. J’aimerais même pouvoir consulter git diff via une projection IR (représentation intermédiaire). L’apparition d’outils AST comme treesitter permet d’imaginer des interfaces où les humains manipuleraient plus efficacement les AST ou les IR. Par exemple, la structure de compilation ordonnée de F# aide à simplifier les revues de code. À l’inverse, dans les langages ou structures qui autorisent un ordre libre, il faut souvent naviguer entre plusieurs endroits pour comprendre le contexte global d’un petit diff, ce qui est fastidieux.
  • Quelqu’un partage son inconfort avec eslint-config-airbnb, en citant des problèmes représentatifs : #1271, #1122. Il explique avoir perdu plus d’une heure à galérer pour appliquer la configuration airbnb à un projet existant, alors que le code était déjà parfait à l’origine. À cause de règles inutiles, cela lui a semblé contre-productif. Il a fini par désactiver localement ces règles, et ne l’a plus jamais réutilisé sur les projets suivants. Cet exemple montre à quel point de mauvaises règles de lint peuvent ruiner la productivité.