10 points par GN⁺ 2026-03-15 | 1 commentaires | Partager sur WhatsApp
  • L’IRS américain a publié en open source son nouveau Tax Withholding Estimator (TWE), dont le principe de conception central est une structure qui modélise le droit fiscal américain sous forme de spécification déclarative basée sur XML
  • La logique de calcul fiscal de TWE est construite sur un moteur logique appelé Fact Graph, qui représente chaque élément fiscal comme un graphe de dépendances de « faits » définis en XML
  • Implémenter la logique fiscale dans un langage impératif comme JavaScript entraîne des problèmes de gestion de l’ordre d’exécution, de perte des valeurs intermédiaires et d’exposition des détails d’implémentation, ce qui rend une approche déclarative indispensable
  • JSON n’est pas adapté au traitement d’expressions imbriquées arbitraires, alors qu’avec XML, les balises elles-mêmes indiquent le type d’objet, ce qui le rend bien plus avantageux pour construire un DSL
  • XML permet aussi de tirer gratuitement parti d’un écosystème d’outils mature comme XPath, ce qui en fait l’option la plus rentable pour des spécifications déclaratives multiplateformes

Fact Graph : le droit fiscal américain exprimé en XML

  • Le Tax Withholding Estimator (TWE) publié par l’IRS est un outil permettant aux contribuables de saisir leurs revenus et déductions afin d’estimer leur impôt et leur retenue à la source
    • Le projet est publié en open source et accepte aussi les contributions du public
  • TWE est un site statique généré à partir de deux configurations XML, dont la première est un Fact Dictionary qui représente le droit fiscal américain
  • Fact Graph est un moteur logique initialement conçu pour le projet IRS Direct File, qui calcule l’obligation fiscale et la retenue à la source d’un contribuable à partir des faits définis dans le Fact Dictionary
  • Chaque fait est défini en XML ; par exemple, /totalOwed est représenté comme un fait dérivé (Derived) qui soustrait /totalPayments de /totalTax
    • Le « montant total dû » (total owed) est la différence entre l’impôt total sur le revenu (total tax) et les montants déjà payés (total payments)
  • Les crédits remboursables (refundable credits) sont des crédits d’impôt pouvant rendre le solde fiscal négatif ; des éléments comme l’Earned Income Credit, le Child Tax Credit et l’American Opportunity Credit sont additionnés avec <Add>
  • Les crédits non remboursables (non-refundable credits) ne peuvent réduire la charge fiscale que jusqu’à 0 ; l’opérateur <GreaterOf> sert à choisir la plus grande valeur entre 0 et (impôt provisoire - crédits non remboursables)
  • Les valeurs saisies par l’utilisateur utilisent la balise <Writable> au lieu de <Derived>, avec des types comme <Dollar/> et <Boolean/> pour indiquer le type de valeur
  • Les faits dépendent les uns des autres et forment une structure en graphe qui produit les chiffres fiscaux finaux

Pourquoi la logique fiscale a besoin de spécifications déclaratives

  • En JavaScript, on pourrait écrire le même calcul de manière concise, comme const totalOwed = totalTax - totalPayments, mais cela relève d’une approche impérative où l’exécution est séquentielle et où les étapes intermédiaires disparaissent ensuite
  • Quand les dépendances deviennent profondes, des problèmes d’ordre d’exécution apparaissent : une fonction de saisie utilisateur comme getInput() bloque tous les calculs suivants, et les questions elles-mêmes doivent changer selon, par exemple, la présence d’un conjoint
  • Dans la logique d’agrégation des revenus de Social Security, des détails d’implémentation JavaScript comme map et reduce deviennent visibles, alors que <CollectionSum> en XML exprime le concept mathématique fiscal lui-même
    • <Dependency path="/socialSecuritySources/*/totalFederalTaxesPaid"/> permet de sommer les éléments d’une collection
  • Le Fact Dictionary adopte une approche déclarative, où l’on décrit uniquement les calculs nommés et leurs dépendances, sans spécifier les étapes concrètes ni leur ordre d’exécution ; le moteur décide automatiquement de la manière d’exécuter
  • L’avantage le plus important d’un modèle fiscal déclaratif est l’auditabilité et l’introspection : on peut demander au programme « comment ce nombre a-t-il été obtenu ? »
    • Dans un programme impératif, les valeurs intermédiaires sont déjà jetées et ne peuvent être examinées qu’au moyen de logs ou d’un débogueur, ce qui ne passe pas à l’échelle lorsqu’il existe des centaines de calculs intermédiaires comme dans le droit fiscal américain
  • Selon Chris Given, auteur initial de Fact Graph, Fact Graph est « un moyen de prouver que les éléments non demandés n’ont pas modifié le résultat fiscal, et que toutes les aides fiscales auxquelles on a droit sont bien prises en compte »
  • Intuit, créateur de TurboTax, est arrivé à la même conclusion et a publié en 2020 un livre blanc sur un « Tax Knowledge Graph », mais son implémentation n’est pas publique
    • Le Fact Graph de l’IRS est open source et dans le domaine public, ce qui permet à chacun de l’étudier, le partager et l’étendre

Pourquoi XML est bien mieux adapté aux DSL que JSON

  • Si l’on tente d’utiliser JSON comme format de représentation déclarative du droit fiscal, le traitement d’expressions imbriquées arbitraires devient très peu pratique
    • Comme la seule structure de données composite de JSON est l’objet, chaque objet enfant doit indiquer sa propre nature avec "type", "kind", etc.
    • En XML, le nom de la balise indique directement le type d’objet, sans déclaration supplémentaire
  • La représentation JSON du même fait /tentativeTaxNetNonRefundableCredits est en fait plus longue et plus complexe que sa version XML
  • XML prend en charge les commentaires et gère raisonnablement les espaces et retours à la ligne, évitant ainsi plusieurs désagréments courants de JSON
  • Les attributs et les éléments enfants nommés offrent, dans la conception du langage, une expressivité qui permet de choisir ce qu’il faut mettre en avant
  • Il est possible de définir des types de données propres au domaine, comme la distinction entre « dollar » et « entier »
  • Pour les textes descriptifs longs, XML est bien plus agréable à lire et à éditer manuellement que JSON

La polyvalence de XML et son écosystème d’outils

  • Des syntaxes alternatives comme les S-expressions, Prolog ou KDL peuvent être plus agréables à lire que XML, mais utiliser XML permet d’obtenir gratuitement un parseur et tout un écosystème d’outils génériques
    • Les S-expressions fonctionnent bien en Lisp, les termes Prolog en Prolog, mais XML peut être converti vers pratiquement n’importe quel format
  • En Prolog, convertir du XML en termes Prolog est possible avec un seul prédicat
  • La question d’un utilisateur de Hacker News, ok123456, demandant « pourquoi ne pas utiliser Prolog/Datalog ? » est aussi mentionnée ; c’est possible, mais XML l’emporte en polyvalence
  • À propos de YAML, Chris Given indique qu’il ne faut « absolument jamais essayer d’exprimer la logique du droit fiscal américain en YAML »
  • Exemple concret avec XPath : un script en une ligne de shell permet de faire une recherche floue dans les chemins des faits et d’afficher immédiatement la définition du chemin sélectionné
    • cat facts.xml | xpath -q -e '//Fact/@path' | grep -o '/[^"]*' | fzf pour rechercher un fait
    • Une fonction a aussi été ajoutée pour remonter la chaîne de dépendances et voir quels faits dépendent d’un fait donné
    • Environ 60 lignes de script bash ont suffi pour créer un outil de débogage utilisé presque tous les jours
  • Les membres de l’équipe ont eux aussi créé des outils de débogage rapides comparables, chacun dans son propre langage, en parsant trivialement le XML sans toucher à l’implémentation Scala de Fact Graph
  • Le principal enseignement est que les formats génériques de représentation de données ont énormément de valeur, et que cette catégorie ne comprend en pratique que JSON et XML
    • Dans la plupart des cas, il faut choisir JSON ; mais lorsqu’un DSL est nécessaire, XML est l’option la moins coûteuse, et cette efficacité économique permet à l’équipe de réserver son budget d’innovation à d’autres sujets

Points complémentaires

  • Même des non-programmeurs peuvent lire du XML si le schéma est bien conçu, même s’il reste souhaitable de construire séparément des vues alternatives
  • L’intérêt pour XML semble repartir récemment : grex, l’outil de Jake Low qui convertit des documents XML en représentation plate orientée lignes, ou encore Xee de Martijn Faassen, un moteur XPath/XSLT moderne implémenté en Rust
  • Les faits de TWE sont destinés à l’estimation de la retenue à la source et ne doivent pas être utilisés directement pour une déclaration fiscale

1 commentaires

 
GN⁺ 2026-03-15
Réactions sur Hacker News
  • XML est un format coûteux à parser correctement dans plusieurs langages
    En pratique, pour une implémentation proche du standard, il faut s’appuyer sur trois implémentations open source comme libxml2, expat et Xerces
    L’idée centrale des langages de la famille SGML est de traiter la « liste » comme un objet de première classe, et l’imbrication comme un objet de seconde classe ; on peut aussi ajouter des métadonnées selon deux axes : le nom des balises et les attributs
    XML reste utile comme DSL, mais si on veut utiliser du vrai XML, il faut abandonner le mot « cheap »
    On peut aussi faire en sorte qu’un DSL déclaratif ressemble à une formule impérative. Par exemple, une expression comme totalOwed = totalTax - totalPayments peut avoir exactement la même signification qu’un DSL XML
    Des langages comme METAFONT montrent cette approche (lien d’exemple)

    • Je vois souvent XML refaire encore et encore les mêmes erreurs
      On oublie fréquemment cette vérité simple : plus on ajoute de fonctionnalités à un format, plus il devient difficile à parser
      Si JSON est populaire, c’est parce qu’il a peu de fonctionnalités et qu’il est donc facile à parser
      À l’inverse, XML a accumulé trop d’éléments : attributes, namespaces, CDATA, DTDs, etc.
      Il y a aussi eu des discussions sur l’idée d’utiliser SQLite comme format d’échange, mais cela risquerait lui aussi de devenir aussi complexe qu’XML
      C’est aussi pour cela que CSV reste apprécié : sa simplicité
      Les tentatives actuelles pour forcer des commentaires ou des informations de type dans JSON sont une reproduction des mauvais travers d’XML

    • En tant qu’auteur, je suis d’accord
      Il est possible de faire ressembler une spécification déclarative à une formule mathématique, mais au fond cela revient à créer un nouveau langage
      Cela pose alors le problème de devoir porter le parseur dans tous les environnements
      Il faut aussi prendre soi-même des décisions syntaxiques, comme la priorité des opérateurs ou les expressions switch, et la complexité explose vite
      C’est précisément pour cela que j’ai utilisé le mot « cheap » : utiliser un format pour lequel des parseurs et des outils existent déjà partout réduit les coûts
      On y perd en expressivité, mais c’est un choix judicieux pour une petite équipe

    • J’ai beaucoup utilisé XML dans le Java d’entreprise, et c’était une cause majeure de goulets d’étranglement mémoire et CPU
      XML n’a absolument rien de cheap

    • Le cœur de SGML, c’est le modèle de contenu basé sur des expressions régulières
      Il ne s’agit pas seulement d’une structure de listes : on peut aussi définir des règles de production grammaticales comme en BNF

    • Dire « XML proper » au lieu de « XML lookalike », c’est une formulation un peu trop tatillonne
      Même sans utiliser toutes les fonctionnalités d’XML, cela reste de l’XML
      C’est comme appeler un car scolaire « imitation de bus » simplement parce qu’il n’a pas de porte-gobelets

  • Je pense qu’il suffit d’utiliser un langage qui prend bien en charge les eDSL au lieu d’XML
    Des langages comme Haskell, OCaml ou Scala permettent d’exprimer facilement des calculs parallèles avec des concepts comme les applicatives ou les arrows
    Même en JavaScript, il suffit de créer des abstractions comme sum au lieu de .reduce()
    Si l’on construit un DSL XML, on finit de toute façon par devoir résoudre à nouveau des problèmes de parallélisation, de lisibilité et d’invention d’une nouvelle syntaxe
    Dans les domaines complexes, on risque fort de se heurter à la dixième loi de Greenspun

    • Le problème, toutefois, c’est que des langages comme Haskell sont difficiles à apprendre
      Même des développeurs avec 30 ans d’expérience peuvent trouver la barrière d’entrée élevée

    • Raku est aussi une bonne option
      Il est parti de bases inspirées de Haskell et prend en charge les Grammar intégrées et un style fonctionnel, ce qui le rend pratique pour écrire des DSL

    • HTML ! (courte réaction sur le ton de la plaisanterie)

    • Lisp aussi convient
      Quand on voit les S-expressions, on comprend immédiatement à quel point XML peut paraître verbeux et lourd

  • On peut mieux concevoir la structure de JSON
    Si chaque nœud est composé d’une seule clé de type et d’une valeur tableau, on peut obtenir une représentation proche des S-expressions
    Cela permet un parsing en streaming et donne le type dès le départ
    C’est utile sur de très gros jeux de données

    • JSON est bien plus simple qu’XML et coûte moins cher à parser
      XML impose une gestion d’état plus complexe, avec l’appariement des balises, le traitement des attributs, etc.
      Avec JSON, il suffit essentiellement d’apparier {} et []
      Cette simplicité accumulée finit par se traduire par une latence plus faible

    • Mais JSON contient tellement de guillemets qu’il donne une impression de bruit visuel
      Personnellement, je trouve l’EDN de Clojure plus propre

    • Cette structure JSON me semble esthétiquement être une forme dégénérée
      Si les données ont besoin de balises, il vaut mieux utiliser une représentation adaptée

  • L’article The Lost Art of XML m’a semblé plus intéressant
    J’ai trouvé marquante l’idée qu’une grande partie des outils du développement web sont nés de la défaite d’XML dans la guerre des navigateurs

    • En revanche, j’ai du mal à adhérer à l’idée selon laquelle « XML a été abandonné parce que JavaScript a gagné »
      Les navigateurs prenaient déjà en charge XML à l’origine (le X de AJAX signifie XML)
      C’est simplement que les développeurs n’aimaient pas XML
      À mon avis, XML a été rejeté à cause de sa surconception et de sa complexité excessive

    • Ayant connu directement l’époque des API XML, je peux dire qu’XML était vraiment pénible
      Il fallait fabriquer des encodeurs/décodeurs séparés pour chaque langage, et la maintenance était difficile
      JSON se mappe simplement sur des tableaux et des objets, ce qui lui donne une excellente compatibilité entre langages
      Quand je repense au temps perdu dans les réunions de conception de schémas XML, JSON a simplifié la conception d’API comme Prettier a mis fin au débat tabulations vs espaces

    • Au fond, tout part de l’attitude consistant à dire « je n’ai pas envie d’apprendre quelque chose de complexe », mais avec le temps, on finit par avoir de nouveau besoin de ces fonctionnalités

  • L’administration fiscale polonaise adore XML
    Mais leur XML est si obscur qu’un humain ne peut pas le lire
    Les noms de champs sont du type P_19N, et il faut consulter le schéma pour en comprendre le sens réel
    Il y a même des numéros d’articles de loi dedans
    Ironie du sort, le rédacteur de la loi sur la TVA fait aujourd’hui du conseil fiscal

  • J’utilise moi-même un DSL basé sur les S-expressions
    Il joue le rôle de HTML et CSS dans un runtime de navigateur desktop basé sur WebAssembly,
    et il est aussi réutilisé dans un langage de balisage maison qui résout des problèmes de synchronisation de documents
    On peut en voir des exemples dans le code d’exemple CanvasUI, le fichier de style et l’outil de documentation

    • Les S-expressions ont un parseur extrêmement simple à implémenter, au point que je m’en servais comme exercice d’entretien
      La réaction des candidats lorsqu’ils arrivaient à implémenter eux-mêmes un petit langage était mémorable
  • XML n’est pas tant un DSL qu’un outil générique de parsing/lexing
    Il transforme simplement du texte en AST ; le véritable DSL est la spécification définie au-dessus
    C’est riche en fonctionnalités et complexe, mais cela a l’avantage d’un écosystème d’outils très fourni
    C’est plus adapté au traitement de texte généré qu’à l’écriture manuelle

  • La validation de schéma XSD est intégrée, ce qui permet de vérifier immédiatement la cohérence d’un document
    Se plaindre qu’XML est difficile sans utiliser d’outils d’automatisation, c’est comme manipuler du binaire sans désassembleur

    • Mais la validation par schéma ne peut pas garantir la justesse du contenu
      C’est le même principe que le typage : il ne garantit pas qu’un programme soit correct

    • XSD est utile, mais complexe et plein de contraintes
      C’est pourquoi une partie de la communauté XML s’est tournée vers RELAX-NG, sans qu’il ne remplace complètement XSD

    • Je me demande pour quels types de tâches la validation XSD est réellement indispensable

  • XML convient comme langage de balisage, et reste utilisable comme format d’échange de données, mais en faire un langage de programmation est horrible
    JSON aussi : très bien pour l’échange de données, regrettable comme langage
    Les langages basés sur YAML, comme Ansible, en sont un bon exemple
    En revanche, les S-expressions de Lisp ont une structure proche de JSON tout en ayant évolué en excellent langage

  • Le problème d’XML, ce n’est pas tant XML lui-même que la difficulté de produire du bon XML
    Le standard est complexe, et chaque producteur exprime les choses différemment, donc la cohérence est faible
    Avec JSON, cet écart-type est bien plus faible
    Face à l’XML de certaines institutions financières, on en viendrait presque au désespoir

    • Au fond, le problème d’XML venait surtout de la lenteur des outils et de validateurs incomplets
      Plus que la complexité de la représentation des données, c’est la qualité des outils qui constituait le vrai goulet d’étranglement

    • En réalité, le problème n’était pas tant le « bon XML » que le fait qu’il était trop facile de produire de l’XML bancal
      C’est pourquoi la communauté a tenté d’assurer l’interopérabilité avec les namespaces, la validation, les transformations, le web sémantique, etc.
      C’était un compromis pour continuer à avancer, même dans un environnement où un consensus parfait est impossible