1 points par GN⁺ 8 시간 전 | 1 commentaires | Partager sur WhatsApp
  • Haskell a été adopté dans le cadre de la modernisation de la chaîne d’approvisionnement de plus de 435 magasins et centres logistiques ; huit ans plus tard, environ un million de lignes de code maintenues par plusieurs équipes tournent dans des systèmes de production critiques.
  • Haskell réduit certaines catégories d’erreurs à l’exécution et prend en charge le refactoring basé sur GHC ainsi que l’intégration avec le legacy, mais il faut accepter la maintenance interne liée au manque de SDK et la complexité des fonctionnalités de typage avancées.
  • La réussite a dépendu bien davantage des compétences et de la culture des équipes que du langage ; faute d’experts Haskell, des fuites d’espace et le départ de développeurs clés ont fait que deux projets n’ont pas réussi à ancrer l’adoption.
  • Le runtime GHC n’a jamais été la cause d’un incident de production chez H-E-B ; avec les progrès de l’écosystème — HLS, OpenTelemetry, profiling — Haskell en production est devenu une option compétitive.
  • Il faut cantonner les fonctionnalités avancées derrière de petites bibliothèques et des interfaces claires, tout en combinant tests, observabilité et partage des connaissances ; à l’ère des agents de codage, la validation par les types de GHC et le feedback rapide deviennent encore plus importants.

Le défi de la modernisation du mainframe

  • Les clients de H-E-B, distributeur et plus grande entreprise privée du Texas, se soucient davantage de trouver les rayons remplis que des systèmes internes.
  • Pendant des décennies, un mainframe COBOL a fonctionné de manière fiable, mais ces dix dernières années ont vu apparaître des fonctionnalités centrées sur la technologie comme le retrait en drive, la livraison à domicile, l’inventaire en temps réel et la recherche en magasin.
  • En étendant les opérations de supply chain à plus de 435 magasins et aux centres logistiques qui les soutiennent, les systèmes cœur historiques ont dû répondre à des exigences dépassant largement leur périmètre de conception initial.
  • La principale difficulté de la modernisation d’un mainframe n’est pas de déplacer du code vers le cloud, mais de préserver les connaissances propres à l’organisation accumulées pendant des décennies dans la logique métier legacy.
  • Découper un monolithe manipulant des centaines de tables en microservices détenus par des équipes d’ingénierie autonomes est une tâche immense, techniquement et politiquement, et coûteuse.

Adoption de Haskell et échelle d’exploitation

  • Des consultants ont proposé Haskell comme langage commun pour un nouveau projet visant à remplacer la plus grande application mainframe de l’entreprise.
  • Ce qui avait commencé comme une expérimentation est devenu plusieurs systèmes de production critiques pour la supply chain.
  • Huit ans après l’adoption, plusieurs équipes sur différents domaines maintiennent environ un million de lignes de code Haskell.
  • L’exploitation en production sur le long terme a mis en évidence à la fois des résultats concrets et des difficultés techniques et organisationnelles.

Avantages obtenus côté métier

  • Ce que les entreprises recherchent, ce ne sont pas l’évaluation paresseuse, les fonctions pures ou les données immuables en elles-mêmes, mais un système de type COBOL nouvelle génération, capable de fonctionner 40 ans sans null pointer exception et avec de faibles coûts de maintenance.
  • Les applications Haskell éliminent par défaut des catégories d’erreurs à l’exécution courantes dans les programmes impératifs et à typage dynamique.
    • Les bugs ne disparaissent pas totalement, mais les problèmes restants se concentrent davantage sur les erreurs de logique métier que sur les null pointer exceptions ou les confusions de types.
  • Dans une migration legacy progressive sur plusieurs années, de type strangler fig, GHC aide à refactorer en toute sécurité.
    • Il permet d’itérer au fil de la formation des exigences, pour migrer de manière agile plutôt que selon un modèle en cascade.
    • L’entreprise peut mesurer progressivement les résultats au lieu d’investir d’avance dans un livrable figé à tort.
  • Les parseurs Haskell permettent d’utiliser directement comme contrats des formats legacy de plusieurs milliers de lignes, comme les IBM copybooks à largeur fixe.
  • Une puissante interface de fonctions étrangères (FFI) permet aussi de s’intégrer à des services existants ne fournissant que des bibliothèques C.
    • H-E-B a écrit des bibliothèques Haskell enveloppant simdjson C++, Oracle ODPI-C et IBM MQ.

Manque de SDK et propriété des contrats

  • Quand les SDK Haskell manquent, il faut construire soi-même les clients et le code d’intégration nécessaires, puis les maintenir dans la durée.
  • En contrepartie, on possède directement les contrats, on évite le verrouillage fournisseur et on n’attend pas qu’un mainteneur amont publie un correctif.
  • H-E-B a jugé que cet échange valait largement le coût pour les dépendances critiques.
  • Les agents de codage gèrent bien le travail mécanique de portage de bibliothèques Go vers Haskell, ce qui réduit l’écart de vitesse de développement entre langages.
    • Toutefois, une traduction simple peut ne pas exploiter pleinement les avantages du système de types de Haskell sans prompt élaboré.

Intégration multilangage via DSL embarqués

  • Haskell est un excellent langage hôte pour les DSL embarqués (eDSL).
    • Une équipe centrale peut définir une fois un modèle de domaine ou une logique métier, puis générer du code typé sûr dans les langages utilisés par d’autres équipes.
    • Ces équipes peuvent s’intégrer au système sans écrire directement de Haskell.
  • Hydra est un framework DSL open source issu des travaux d’Uber sur les données de graphe.
    • Il est bootstrappé en Haskell et génère des implémentations sémantiquement équivalentes en Java, Python, Scala, etc.
    • Une suite de tests partagée garantit l’équivalence des implémentations selon les langages.
  • H-E-B a prototypé un DSL Haskell permettant de partager des calculs financiers sensibles entre des équipes Haskell, TypeScript et Java.
  • L’entreprise a aussi construit un DSL de schéma JSON bidirectionnel.
    • Semblable à autodocodec, il utilise toutefois un encodage tagless final permettant aux utilisateurs d’étendre la sémantique centrale avec leurs propres classes de types.
    • Il standardise la gestion des versions de schémas, la génération de documentation et d’OpenAPI, ainsi que les tests de régression et golden tests.
    • Des interpréteurs ad hoc peuvent convertir un schéma JSON en définition de table PostgreSQL, ou remplacer aeson par simdjson avec des validations supplémentaires.

Recrutement et culture d’ingénierie

  • Les langages modernes offrent eux aussi de nombreuses fonctionnalités inspirées de Haskell en matière de sûreté de typage, pureté et concurrence ; la vraie différence tient donc à la culture d’ingénierie que le langage favorise.
  • Haskell attire des développeurs qui accordent de l’importance à l’exactitude et à la conception d’abstractions.
  • Recruter pour des postes Haskell n’a pas été aussi difficile que la direction l’anticipait.
    • Certains candidats postulaient pour Haskell lui-même, même sans intérêt particulier pour la supply chain.

Les limites du budget de complexité

  • Haskell est un langage ancien avec plusieurs défauts, d’où l’importance de suivre les versions récentes de GHC.
  • Si une équipe ne compte pas d’expert, un seul défaut linguistique peut se propager à tout le projet.
  • Au départ, des consultants expérimentés ont mis en place des garde-fous pour éviter l’usage excessif des extensions de langage et des opérateurs personnalisés.
  • Avant l’existence des éditions de langage GHC2021 et GHC2024, chaque équipe maintenait son propre ensemble d’extensions par défaut.
    • Cela servait de budget de complexité, limitant le périmètre du langage qu’un nouvel arrivant devait assimiler avant de contribuer.
  • Les dépendances consomment elles aussi ce budget de complexité, ce qui rend difficile une contrainte à l’échelle de l’organisation.
    • servant exprime les API sous forme de DSL au niveau des types, et l’extension par combinateurs personnalisés s’accompagne de type families et d’erreurs difficiles à comprendre.
    • haxl modélise toutes les sources de données comme des GADT indexés par type de résultat afin de regrouper les opérations concurrentes.
  • Plus les développeurs gagnent en expertise, plus la tentation augmente d’introduire GADT, type families, generics, tagless final, arrows, free structures et patrons de higher-kinded data types.
    • Quand ces concepts s’empilent sur un domaine métier déjà complexe, la promesse d’une maintenance facile s’affaiblit.
    • Comme les fonctionnalités avancées s’accumulent progressivement à mesure que l’équipe se familiarise avec l’écosystème, l’augmentation de la complexité peut n’apparaître que tardivement.

Principes d’exploitation pour un Haskell ennuyeux

  • Il est facile de recommander un Haskell ennuyeux au niveau de l’organisation, mais difficile de l’imposer.
  • Encapsuler le Haskell avancé derrière des interfaces raisonnables réduit sa portée et limite le budget de complexité à de petites bibliothèques gérées par quelques experts.
  • La complexité au niveau du langage n’est pas propre à Haskell, mais l’éventail d’outils avancés disponibles y est particulièrement large.
  • Le nombre de lignes de code ou la consommation de tokens reflètent moins bien la complexité d’un projet Haskell que la quantité de code qui cassera lors de la prochaine mise à niveau de GHC.

Deux projets où l’adoption n’a pas pris

  • Haskell peut renforcer les capacités d’une équipe tout en constituant une barrière pour une autre ; chez H-E-B, deux projets n’ont pas réussi à l’adopter durablement pour des raisons différentes.
  • Dans le premier cas, des développeurs expérimentés sans expérience Haskell ont suivi le template de projet et les conventions d’une autre équipe, mais une fuite d’espace (space leak) a bloqué tout le programme.
    • Faute d’un développeur Haskell solide pour guider l’équipe, ce seul problème a entraîné l’arrêt du projet.
  • Dans le second cas, les ingénieurs qui défendaient Haskell et avaient construit l’application ont été déplacés vers d’autres projets à la suite d’un changement de priorités.
    • La raison était indépendante du langage lui-même.
  • Dans les deux cas, les équipes avaient une solution de repli vers leurs technologies existantes et n’étaient pas convaincues que Haskell améliorait leur productivité.
  • Quand une issue de secours comme un template Spring Boot existe, la motivation à diagnostiquer jusqu’au bout une fuite d’espace difficile peut diminuer.
  • À mesure que les LLM deviennent capables de traduire mécaniquement des codebases entières, les options de réécriture s’élargissent encore.
  • La défense de long terme n’est pas un code si intelligent qu’il est difficile à réécrire, mais une équipe qui veut continuer à maintenir Haskell.

Incidents de production et diagnostic

  • Même les équipes ayant adopté Haskell ont rencontré plusieurs problèmes graves.
  • Le runtime GHC n’a jamais été la cause racine d’un incident de production chez H-E-B.
  • Le débit et l’usage mémoire en régime normal étaient suffisamment compétitifs pour les workloads de H-E-B, et les problèmes rencontrés relevaient de l’exception plutôt que de la situation générale.
  • Les ingénieurs ont résolu les problèmes en analysant des core dumps de segmentation fault, des métriques de garbage collection et des profils de heap.
  • Il ne faut pas sacrifier la couverture de tests sous prétexte d’avoir un système de types puissant.
  • Dans les applications Haskell, les catégories d’erreurs simples étant éliminées à la compilation, le chaos engineering peut faire apparaître plus directement les problèmes réels de logique et de ressources.

Des outils de développement et un écosystème transformés

  • Les premiers systèmes ont commencé avec GHC 8.2 ; à l’époque, il fallait écrire soi-même la plupart des clients API et SDK pour les plateformes populaires.
  • Haskell Language Server n’existait pas, GHCup venait à peine d’apparaître, et le profiling runtime était difficile.
  • Les développeurs habitués aux IDE Java trouvaient l’environnement d’outillage Haskell inconfortable, et H-E-B a même sponsorisé le développement d’un support Debug Adapter Protocol pour les utilisateurs de VS Code.
  • Aujourd’hui, le développement Haskell de niveau production a progressé au-delà du simple “possible” pour devenir compétitif.
  • Les outils de développement incluent HLS, ghcid, ghciwatch, static-ls, tricorder et des plugins d’éditeur.
    • Certains utilisent des plugins GHC pour un développement riche centré sur GHCi, d’autres utilisent VS Code et HLS.
    • L’objectif est de laisser les développeurs choisir les outils qu’ils préfèrent.
  • Pour l’observabilité, H-E-B utilise hs-opentelemetry et opentelemetry-auto.
    • opentelemetry-auto est un plugin GHC qui insère automatiquement des spans OTel dans les fonctions Haskell.
    • Il permet de fournir une instrumentation comparable à celle de Java ou Python.

Bibliothèques de production et améliorations du runtime

  • Les services utilisent des bibliothèques comme warp, aeson, attoparsec, stm, conduit, servant et orville-postgresql.
  • Quand l’écosystème ne fournit pas une fonctionnalité nécessaire, H-E-B développe ses propres bibliothèques.
    • arbiter est une file de travail PostgreSQL transactionnelle issue des travaux de H-E-B et actuellement utilisée en production.
  • GHC améliore les diagnostics runtime, les performances du compilateur, les fonctions de monitoring comme l’eventlog streaming et les annotations d’exceptions.
  • Depuis l’introduction de l’info table profiling dans GHC 9.2, les inquiétudes liées aux fuites d’espace ont nettement diminué.

Communauté interne et diffusion des connaissances

  • H-E-B accorde une grande importance aux bibliothèques internes et encourage les développeurs à contribuer à la fois aux projets internes et open source.
  • Pendant des années, l’entreprise a organisé des réunions Haskell toutes les deux semaines afin que les ingénieurs partagent leurs explorations et forment les autres.
  • Pour réduire les silos dans une organisation d’entreprise, les idées et les patterns doivent circuler entre les équipes.
  • En faisant en sorte que davantage d’ingénieurs lisent et possèdent la codebase, on réduit le risque de bus factor lié au départ d’une seule personne.

Critères pour autoriser les fonctionnalités avancées

  • Les règles par défaut sont souples, mais le tech lead décide en dernier ressort où dépenser le budget de complexité.
  • Si des informations personnelles identifiables (PII) stockées doivent être chiffrées, une garantie au niveau des types transformant une fuite de données sensibles en erreur de compilation plutôt qu’en incident runtime peut valoir l’investissement.
  • Unifier quatre contrats API via le pattern trees-that-grow peut ne pas valoir le coût de cacher des schémas externes derrière des type families.
  • Le Haskell ennuyeux n’interdit ni la programmation au niveau des types ni les fonctionnalités avancées de GHC ; il définit des conventions de principe puis évalue le coût des écarts.
  • La convention principale est : “pas d’action inattendue à distance”.
    • Éviter la génération de code TemplateHaskell et la logique de sérialisation basée sur Generic.
    • Écrire le boilerplate à la main afin que le comportement soit explicite pour les programmeurs.
    • Cela n’interdit pas totalement les quasiquoters ni le deriving via Generically.
  • Implémenter une machine à états au niveau des types pour un formulaire web, ou utiliser un GADT là où un ADT ordinaire suffirait, exige un scepticisme sain et une objection collective de l’équipe.
  • Le Haskell avancé existe à la fois dans les bibliothèques et dans les applications de production, mais il faut limiter le périmètre des expérimentations.
  • Le vrai travail d’ingénierie se joue dans l’équilibre entre le travail et le jeu technique.

L’avenir de Haskell et des agents de codage

  • Après plusieurs années d’utilisation de GHC, H-E-B a découvert et signalé quelques bugs, mais aucun n’a bloqué le travail.
  • Les incidents de production sont rares et surviennent beaucoup plus souvent dans la logique métier que dans les erreurs de type ou le runtime.
  • À mesure que la part de code écrite par des agents de codage augmente, le goulot d’étranglement se déplace de l’écriture du code vers sa validation.
  • Le système de types de GHC aide les humains à refactorer en sécurité tout en fournissant une boucle de feedback rapide qui rejette avant exécution le code halluciné par les agents.
  • Pour étendre le potentiel de Haskell dans l’industrie, davantage de réussites réelles en production doivent être partagées.

1 commentaires

 
GN⁺ 8 시간 전
Avis sur Lobste.rs
  • On connaît peut-être mal l’enseigne en dehors du Texas, mais H-E-B est une institution emblématique du Texas, d’une taille et d’une influence telles qu’on pourrait presque la considérer comme un autre département de l’État.
    Beaucoup de magasins disposent d’installations de fabrication de tortillas, et leur qualité est excellente pour une production à grande échelle. En plus, il paraît qu’ils utilisent aussi Haskell.

    • Le nom vient des initiales H.B. de Howard Butt, la famille fondatrice. Ils auraient pu reprendre le nom du fondateur comme Wegmans, Hannaford Market ou Walmart, mais heureusement ils ne l’ont pas appelé Buttmart.
    • Je me demande si c’est une sorte de Costco régional.
  • Le fait qu’une entreprise comme H-E-B ait choisi Haskell pour remplacer COBOL est vraiment surprenant.
    Les deux phrases disant qu’un agent de codage peut porter mécaniquement des bibliothèques Go vers Haskell, ce qui réduit l’écart de vitesse de développement, tout en reconnaissant aussitôt que, sans prompts astucieux, il risque de ne pas exploiter pleinement le système de types, mettent en évidence un problème contradictoire.
    En revanche, comme les petites erreurs sont éliminées à la compilation, le fait que, lors de l’injection de pannes d’infrastructure via du chaos engineering, on fasse apparaître de véritables erreurs de logique ou de ressources plutôt que le bruit d’un langage à typage dynamique semble être l’argument le plus convaincant pour envisager Haskell.

    • H-E-B dispose, comme Walmart, d’une organisation d’ingénierie de grande taille et plutôt réputée, donc ce n’est pas si surprenant. L’entreprise exploite même un bureau dédié au logiciel à Austin pour attirer les talents logiciels réticents à travailler au siège de San Antonio.
  • La semaine dernière, j’ai essayé de configurer des builds Haskell isolés avec Bazel, mais je n’ai pas trouvé de solution directement exploitable.
    rules_haskell n’est pas isolé par défaut, et l’approche courante semble dépendre fortement de nixpkgs. Haskell semble dépendre du linker C++ du système ; je me demande si c’est bien l’état actuel des choses ou s’il existe une alternative que j’aurais manquée.