3 points par GN⁺ 2024-01-05 | 1 commentaires | Partager sur WhatsApp
  • Depuis sa publication en open source le 10 novembre 2009, Go a évolué pendant 14 ans avec pour objectif non pas le langage lui-même, mais une manière de créer plus facilement des logiciels de production
  • Une spécification formelle, plusieurs implémentations de compilateur, une cross-compilation simple, une garantie de compatibilité après Go 1.0, ainsi que la bibliothèque standard et gofmt ont soutenu son adoption
  • La concurrence, point fort pour structurer les logiciels serveur, a aussi semé la confusion au départ faute d’explications suffisantes sur la différence avec le parallélisme et sur les bons cas d’usage
  • Les interfaces sont devenues la base des bibliothèques, des tests, de la gestion des dépendances et d’une conception centrée sur la composition, tandis que l’absence de génériques a compliqué pendant plus de dix ans la conception polymorphe
  • La gestion des paquets, la documentation et la collaboration avec la communauté ont donné lieu à beaucoup de tâtonnements, mais Go vise un environnement où le code se ressemble quel que soit son auteur ou son ancienneté, et continue à se compiler

L’objectif de Go : une manière de développer des logiciels, plus qu’un langage

  • Le 10 novembre 2023 marquait le 14e anniversaire de la publication de Go en tant que projet open source
  • Lors de l’ouverture en 2009, Ken Thompson, Robert Griesemer, Russ Cox, Ian Taylor, Adam Langley, Jini Kim et d’autres ont assisté au lancement du projet
  • L’objectif initial de Go n’était pas de créer un nouveau langage de programmation pour lui-même, mais de mieux écrire des logiciels de haute qualité
  • À l’époque, le principal goulot d’étranglement ne venait pas des fonctionnalités du langage, mais de la complexité de la création de logiciels serveur modernes chez Google
    • contrôle des dépendances
    • grandes équipes et évolution des effectifs
    • facilité de maintenance
    • tests efficaces
    • exploitation des CPU multicœurs et du réseau
  • Go se définit encore aujourd’hui comme un projet visant à rendre la construction de logiciels de production plus simple et plus productive

Une identité communautaire façonnée par la mascotte Gopher

  • Le Go gopher a été l’un des premiers facteurs du succès de Go
  • Créé par Renee French, le gopher est devenu à la fois un symbole partagé par les programmeurs Go et l’étendard de la communauté
  • Comme le montre une conférence appelée GopherCon, le gopher a contribué à créer l’atmosphère d’un projet alliant excellence technique et plaisir
  • Le choix de le publier sous licence Creative Commons Attribution a eu des avantages et des inconvénients
    • il a encouragé les remixes et les variations, renforçant l’esprit communautaire
    • mais la clause d’attribution a aussi suscité des débats, ou entraîné des crédits erronés sur des travaux que Renee French n’avait pas réalisés
  • La gestion de la mascotte pour qu’elle conserve son esprit d’origine reste un défi

Les bons choix techniques de Go

  • Le projet a commencé par rédiger une spécification formelle afin de fixer le comportement des implémentations du compilateur et de permettre à plusieurs implémentations de converger vers le même comportement
    • il était considéré qu’un compilateur seul ne pouvait pas faire office de spécification
    • le premier brouillon de la spécification a été rédigé au 18e étage d’un immeuble de Darling Harbour à Sydney
  • Plusieurs implémentations de compilateur ont aidé à affiner le langage et la spécification
    • le 7 juin 2008, Ian Taylor a envoyé un message indiquant qu’il avait lu le brouillon de la spécification Go et créé un frontend gcc
    • d’autres implémentations compatibles sont ensuite apparues
  • Le fait d’avoir rendu la cross-compilation simple a permis aux développeurs de travailler sur la plateforme de leur choix et de déployer sur celle dont ils avaient besoin
  • Le choix d’introduire une garantie de compatibilité après avoir stabilisé le langage dans Go 1.0 a eu un impact majeur sur l’adoption de Go
    • maintenir une forte compatibilité a un coût, mais réduit la crainte qu’une nouvelle version de Go casse un projet
  • La bibliothèque standard fournit l’essentiel de ce qu’il faut pour écrire du code serveur du XXIe siècle et a permis à la communauté de travailler avec une boîte à outils commune
    • à ses débuts, la bibliothèque a aussi grossi parce qu’il n’existait pas vraiment d’autre endroit pour installer du code Go
    • cela a aidé à limiter la prolifération de bibliothèques concurrentes et à unifier la communauté

Les outils et gofmt au cœur de l’expérience de développement

  • Go a été conçu comme un langage facile à parser, ce qui a facilité la création d’outils
  • Au départ, on pensait qu’un IDE serait nécessaire, mais la facilité d’outillage a permis avec le temps aux IDE de prendre en charge Go, et gopls est aussi apparu
  • En plus du compilateur, des outils de support ont été fournis pour les tests automatiques, la couverture et la vérification du code
  • La commande go a unifié tout le processus de build, et beaucoup de projets ont pu l’utiliser pour couvrir l’essentiel de la construction et de la maintenance du code Go
  • gofmt est devenu un outil qui a influencé non seulement Go, mais l’ensemble de la communauté du développement
    • Robert Griesemer a insisté dès le départ pour créer gofmt
    • avant gofmt, la qualité des formateurs automatiques était trop faible pour qu’ils soient vraiment utilisés
    • cela a réduit le temps perdu dans les débats sur les espaces et les retours à la ligne
    • lorsque l’intérieur de gofmt est devenu une bibliothèque, il est devenu possible d’analyser et modifier l’AST, puis de régénérer une sortie lisible par un humain
    • cela a aussi permis d’autres outils, comme un simplificateur, un analyseur ou des outils de couverture de code

La concurrence : puissante, mais expliquée trop tard

  • En 2002, les logiciels de Google évitaient largement les threads, dans un climat influencé par la position de John Ousterhout selon laquelle “threads were bad”
  • Go est né de l’expérience qu’il existait une meilleure manière d’utiliser la concurrence qu’avec des paquets bas niveau comme pthread
  • Go a joué un rôle important dans l’acceptation de la concurrence comme outil puissant dans le monde de la programmation
    • notamment dans les environnements multicœurs et réseau
    • aujourd’hui, la plupart des langages grand public prennent en charge la concurrence
  • Go n’a pas repris des termes comme coroutine, task ou thread, et a introduit un nouveau terme : goroutine
  • async/await est une nette amélioration par rapport à pthread, mais comparé à goroutine, channel et select, il peut être plus simple et plus léger pour l’implémenteur tout en reportant une partie de la complexité sur le programmeur
    • le problème décrit par Bob Nystrom dans “What Color is Your Function?” en est un exemple
    • le modèle CSP de Go s’adapte bien aux langages procéduraux, mais sa bonne implémentation exige une certaine complexité d’exécution
    • comme plusieurs implémentations de la concurrence dans un même environnement peuvent poser problème, Go a intégré cela au langage plutôt que d’en faire une simple bibliothèque

Deux erreurs autour de la concurrence

  • L’équipe Go n’a pas assez tôt indiqué clairement où utiliser la concurrence
    • le principal cas d’usage consistait à simplifier les logiciels serveur dans des bibliothèques centrales comme net/http
    • ce n’était pas une fonctionnalité à utiliser partout dans tous les programmes
  • Le fait d’avoir tardé à expliquer la différence entre parallélisme et concurrence a aussi posé problème
    • beaucoup de développeurs ont tenté de paralléliser leur code avec des goroutines pour le rendre plus rapide, avant de découvrir avec surprise qu’il devenait plus lent
    • le code concurrent ne peut gagner en vitesse via la parallélisation que lorsque le problème lui-même est parallélisable, par exemple dans le traitement de requêtes HTTP
  • Pour corriger cela, la présentation “Concurrency is not Parallelism” a été donnée à Waza en 2012
  • Cette explication aurait dû arriver plus tôt
  • Malgré cela, Go a contribué à populariser la concurrence comme manière de structurer les logiciels serveur

Interfaces et conception centrée sur la composition

  • Les interfaces sont, avec la concurrence, l’une des idées clés qui distinguent Go
  • Les interfaces Go constituent en quelque sorte la réponse de Go à la conception orientée objet centrée sur le comportement
  • L’approche dynamique où il n’est pas nécessaire de déclarer à l’avance quel type implémente quelle interface a été critiquée au départ, mais s’est révélée essentielle au style de programmation Go
  • La bibliothèque standard, les tests et la gestion des dépendances reposent fortement sur le caractère ouvert des interfaces
  • Le sort de Go est implémenté comme une fonction opérant sur des interfaces
    • cela diffère du style orienté objet auquel beaucoup étaient habitués, mais c’était une idée puissante
  • De petites interfaces comme Reader, Writer et l’interface vide sont devenues la base des bibliothèques Go
    • ces trois interfaces bien connues comptent en moyenne respectivement 2 ou 3 méthodes
    • de petits ensembles de méthodes sont devenus un idiome typiquement Go

Le long détour des génériques

  • L’équipe Go avait observé que la programmation générique tend à faire passer les types avant les algorithmes
    • elle préférait une conception organique plutôt qu’une abstraction prématurée
    • et accordait plus d’importance aux fonctions qu’aux conteneurs
  • Go a intégré au langage des conteneurs génériques comme map, slice, array et channel, sans exposer directement cette généricité aux utilisateurs
  • Il a été estimé que ces types suffisaient pour la plupart des tâches de programmation simples, mais pas dans tous les cas, et cette frontière a été source de frustration pour certains utilisateurs
  • Comme les interfaces étaient au cœur de la programmation Go, tout nouveau modèle de polymorphisme devait nécessairement bien s’y intégrer
    • il y a eu plusieurs tentatives et des implémentations abandonnées
    • après de nombreuses discussions, l’aide de théoriciens des types dirigés par Phil Wadler a aussi été sollicitée
  • Au final, Go a conçu ses génériques en généralisant les interfaces de “jeu de méthodes” à “jeu de types”
  • Le terme “generics” vient d’un polymorphisme centré sur les structures de données et ne désigne pas parfaitement le parametric polymorphism proposé par Go, mais en pratique c’est bien le mot generics qui s’est imposé

Compilateur : d’abord en C, puis en Go

  • Le fait que les premiers compilateurs Go aient été écrits en C a dérangé une partie de la communauté du langage
    • certains estimaient qu’il aurait fallu utiliser une boîte à outils comme LLVM ou pratiquer le self-hosting en Go
  • Le choix d’écrire d’abord le compilateur en C était pragmatique
    • pour amorcer un nouveau langage, il fallait utiliser un langage existant
    • Ken Thompson avait déjà écrit un compilateur C, dont la structure interne pouvait servir de base au compilateur Go
    • écrire le compilateur dans le langage en cours de conception risquait d’orienter ce langage vers ce qui convient à l’écriture d’un compilateur
  • Le compilateur initial produisait un code ordinaire et n’était pas très propre en interne, mais il était petit, familier et facile à modifier rapidement
  • L’ajout de segmented stack à croissance automatique a montré l’intérêt de ce choix
    • avec une boîte à outils comme LLVM, l’intégration aurait été plus difficile, car elle aurait aussi impliqué des changements d’ABI et de prise en charge du garbage collector
  • La structure issue à l’origine de la famille de compilateurs Plan 9 convenait également bien à la cross-compilation
  • Dans Go 1.5, Russ Cox a écrit un outil traduisant semi-automatiquement le compilateur de C vers Go
    • à ce stade, le langage était achevé et l’inquiétude d’une conception centrée sur le compilateur avait disparu
    • une fois porté en Go, il est devenu possible d’appliquer au développement du compilateur les avantages de Go en matière de tests, d’outillage, de réécriture automatique et d’analyse de performance
  • Il existe aujourd’hui aussi bien un compilateur Go fondé sur LLVM que plusieurs autres compilateurs

Open source et collaboration avec la communauté

  • Dès le départ, il a été considéré que Go devait être un projet open source pour réussir
  • Mais il paraissait plus productif de le développer en privé jusqu’à ce que les idées clés et le comportement de l’implémentation soient clarifiés
    • les deux premières années avant l’ouverture publique ont été importantes pour clarifier les objectifs
  • Après le passage en open source, les retours de la communauté ont été massifs, et Ian Taylor a notamment passé beaucoup de temps à répondre aux questions
  • Le port Windows a été réalisé entièrement par la communauté sous la conduite d’Alex Brainman
  • L’équipe Go a mis du temps à comprendre la meilleure manière de collaborer avec la communauté
    • elle pensait bien communiquer, mais des malentendus et des écarts d’attente ont fait perdre du temps
  • Le projet Go a choisi de ne pas intégrer le code rapidement pour le nettoyer ensuite, mais d’exiger une haute qualité de code avant fusion
    • revue de code obligatoire
    • attention minutieuse aux détails
  • Cette méthode impose davantage de charge à la communauté ; si les contributeurs n’en perçoivent pas la valeur, ils peuvent avoir l’impression de ne pas être les bienvenus
  • L’historique du dépôt du projet Go est passé par SVN, Perforce, Mercurial puis Git, mais Russ Cox a conservé l’historique, de sorte que les anciens changements SVN restent visibles dans le dépôt Git actuel
  • Google soutient Go, mais ne fixe pas l’agenda de l’équipe Go
    • l’importante base de code Go interne à Google sert à tester et valider les versions
    • le flux va du dépôt public vers Google, et non l’inverse
    • l’équipe centrale de Go est salariée par Google mais agit de manière indépendante

Les tâtonnements de la gestion des paquets

  • Si la conception même des packages dans le langage Go était excellente, le développement de la gestion des paquets s’est mal déroulé
  • Le choix de spécifier un chemin dans les instructions import sous forme de chaîne ordinaire était important et flexible
  • Le problème est venu de la transition difficile entre un monde limité à la bibliothèque standard et un modèle où l’on récupérait du code sur le Web
  • Au début, l’équipe Go était habituée au monorepo de Google et à une manière de builder depuis head
    • elle n’avait pas assez d’expérience avec les gestionnaires de paquets manipulant plusieurs versions d’un même package
    • elle n’a pas traité dès le départ toute la complexité technique de la résolution de graphes de dépendances
  • Le travail autour de deps.dev est présenté en quelque sorte comme une compensation pour ce problème
  • Les tentatives de résoudre la gestion des dépendances avec la communauté étaient animées de bonnes intentions, mais lorsque la conception finale est arrivée, beaucoup de membres de la communauté se sont sentis exclus
  • Cette expérience a servi de leçon sur la manière dont la participation communautaire doit réellement se dérouler, et beaucoup de choses se sont améliorées depuis
  • Aujourd’hui, la conception paraît stabilisée, techniquement excellente et fonctionne bien pour la plupart des utilisateurs

Documentation et exemples exécutables

  • Une grande quantité de documentation a été écrite au début, mais elle ne correspondait pas à ce que voulait la communauté
  • Le point le plus manquant était le besoin d’exemples d’usage, même pour les fonctions les plus simples
    • montrer comment utiliser quelque chose avait plus de valeur que simplement dire ce que cela fait
  • La documentation actuelle contient de nombreux exemples, fournis en grande majorité par des contributeurs open source
  • Très tôt, Go a rendu ses exemples exécutables sur le Web
    • lors d’une présentation à Google I/O en 2012, il était possible d’exécuter dans le navigateur des extraits de code montrant la concurrence
    • Andrew Gerrand a écrit la technologie Web qui rendait cela possible
    • cela a ensuite été déployé sur le blog et dans la documentation en ligne des packages
  • The Go playground est proposé comme sandbox publique où chacun peut tester et développer librement du code

Où en est Go après 14 ans

  • Grâce aux décisions prises dans la conception du langage et son processus de développement, Go s’est imposé comme bien plus qu’un simple langage de programmation : une manière d’écrire du logiciel
  • Les éléments suivants ont contribué à la position atteinte par Go
    • une bibliothèque standard solide, couvrant l’essentiel des fonctions de base nécessaires au code serveur
    • la concurrence comme élément de première classe du langage
    • une approche fondée sur la composition plutôt que sur l’héritage
    • un modèle de packaging clarifiant la gestion des dépendances
    • des outils intégrés pour des builds et des tests rapides
    • un formatage strict et cohérent
    • une préférence pour la lisibilité plutôt que pour l’astuce
    • une garantie de compatibilité
  • La communauté Go est composée de Gophers divers et très actifs, qui jouent un rôle central dans le succès du projet
  • En conséquence, le code Go a tendance à se ressembler et à se comporter de façon similaire quel que soit son auteur, il existe relativement peu de clans utilisant des sous-ensembles différents du langage, et le code continue à se compiler et s’exécuter avec le temps
  • Ce type de résultat reste rare parmi les grands langages de programmation

1 commentaires

 
GN⁺ 2024-01-05
Avis sur Hacker News
  • C’est vraiment appréciable que des personnes clés prennent le temps de laisser une rétrospective, et c’est très utile pour ceux qui veulent réellement provoquer des changements aujourd’hui.
    Cela dit, je ne pense pas que Rob Pike ait exprimé assez clairement ce que Go a bien fait. Go n’a pas seulement bien géré le langage lui-même, mais aussi les forces qui s’exerçaient sur le projet : il a limité son usage cible à la programmation système, défini clairement le langage et ses principes, maintenu une priorité à la qualité en corrigeant les problèmes avant la diffusion, et, tout en contrôlant strictement le langage, les releases et le message central, il a laissé de la place à la communauté pour piloter des domaines plus périphériques.
    Un point sous-estimé est que Google lui-même n’est pas intervenu de manière excessive. C’est peut-être parce que Go contribuait réellement aux objectifs de Google et était important. Je me demande si ce serait encore possible aujourd’hui avec un nouveau projet.
    Dart a été très peu adopté en dehors de Flutter, ce qui est intéressant si l’on compare cela au fait qu’il y a beaucoup plus de code applicatif que de code système. Go a été une technologie clé pour faire passer les logiciels côté serveur de l’environnement lourd de Java vers des conteneurs natifs, et il est devenu la base de la majeure partie de l’infrastructure des applications web de la dernière décennie. Malgré cette croissance, l’équipe est restée réduite et les personnes clés sont restées en place, mais je ne sais pas si cela continuera.

    • Go a un garbage collector et un runtime lourd incluant des green threads, ce qui rend l’interopérabilité avec C pénible et lente.
      Pour cette raison, par conception, ce n’est pas un langage adapté à la programmation système. Comme il s’est présenté ainsi au début, un mythe étrange a persisté longtemps, mais il semble que cette formulation ait été retirée il y a quelques années.
      Go est plus proche d’un concurrent de la famille Java que d’un concurrent de C ou Rust, ce que montrent ses usages réels. Cela dit, en raison de son système de types limité et de son excellent support de la concurrence, il se place souvent un peu plus bas dans la stack.
    • J’ai du mal à être d’accord avec l’idée que la communauté pilote le projet. On a encore fortement l’impression que Google décide.
      C’était particulièrement vrai pour la gestion des versions. Au début, Go ne reconnaissait même pas le problème, puis, quand le consensus de la communauté a grandi, les discussions précédentes ont été oubliées et il a été décidé qu’on passerait désormais aux modules.
      Je me souviens aussi qu’ils ne voulaient pas faire du temps monotone (monotonic time) une API publique avant que Cloudflare ne subisse une panne liée à l’heure d’été.
    • J’étais développeur Java et j’aime maintenant Go, mais je ne suis pas sûr que mes anciens collègues Java aimeraient Go. Même quand c’était un nouveau langage, Go était un langage un peu ennuyeux.
      Dans l’univers Java, il y a un certain plaisir à refactorer une base de code avec de nouvelles fonctionnalités, par exemple d’excellents streams. Avec Go, le plaisir vient du fait de trouver l’abstraction la plus simple et la plus banale possible.
    • Je travaille sur Dart. Je ne vois pas la critique selon laquelle Dart n’est pas adopté en dehors de Flutter comme si fatale.
      Tout langage a besoin de bibliothèques et de frameworks adaptés à un domaine donné. Flutter est un framework pour écrire des applications clientes en Dart ; sans Flutter, même si l’on adore le langage Dart, il faudrait consacrer énormément de temps rien qu’à comprendre comment dessiner des pixels à l’écran sur Android et iOS.
      Toute personne qui écrit une application construit au-dessus d’une stack de bibliothèques et de frameworks. La différence entre Go et Dart associé à Flutter tient surtout au fait que, pour Go, les bibliothèques de domaine nécessaires côté serveur, comme le réseau, la sérialisation ou la cryptographie, font partie de la bibliothèque standard.
      Dart dispose d’éléments de base comme les collections et l’asynchrone dans ses bibliothèques intégrées, mais dépend de paquets externes comme Flutter pour les fonctionnalités propres à un domaine. C’est en grande partie parce que Dart a eu, dès ses tout débuts, un système solide de gestion de paquets. De nombreuses bibliothèques centrales écrites et maintenues par l’équipe Dart sont elles aussi distribuées via le gestionnaire de paquets plutôt qu’intégrées au langage, ce qui les rend beaucoup plus faciles à faire évoluer.
      Les frameworks d’UI ont tendance à avoir une durée de vie plus courte que les langages ; je pense donc qu’il vaut mieux que Flutter ne soit pas incrusté dans la bibliothèque standard de Dart. Flutter est excellent, mais je ne serais pas surpris qu’une meilleure solution apparaisse dans 20 ans, et si Flutter n’est pas intégré, les utilisateurs de Dart pourront alors migrer plus facilement.
    • Lors des licenciements, ils ont supprimé des équipes FOSS essentielles, et la direction déteste le vrai FOSS. Parce que cela ne rend pas bien dans les tableurs de Ruth.
      Le faux FOSS comme Android est toléré pour des raisons stratégiques, mais en dehors de cela, l’ambiance est que si cela ne mène pas à des clics publicitaires, c’est inutile.
  • En 2012, en tant que développeur Python, j’ai pris Go parce que je devais faire de la manipulation de bits pour Modbus. Je n’ai jamais déployé ce code, mais j’ai été stupéfait de voir à quel point toucher aux bits et aux octets était simple et fonctionnait tout simplement.
    Dix ans plus tard, après plusieurs expériences de travail Go presque à plein temps, je trouve toujours étonnant que la plupart des choses fonctionnent tout simplement.
    J’aime le langage Go et la communauté Go. Je suis reconnaissant envers Rob, Ian, Russ et les autres personnes qui créent Go pour leur travail, et j’apprécie aussi que cette présentation et cet article abordent honnêtement les « passages difficiles » avec la communauté.
    Cela dit, pour avoir traversé cette période, j’ai beaucoup de mal à croire qu’ils ne savaient pas exactement comment ils se comportaient, en particulier dans le chaos de la gestion des paquets. Mais l’article a aussi raison de dire qu’ils sont maintenant arrivés à une bonne solution.
    J’espère que Go continuera à évoluer sainement au cours des dix prochaines années, tout comme des langages similaires inspirés par lui, comme Zig et Deno, avec des communautés en bonne santé.

    • Ce que je préfère dans l’équipe cœur de Go, c’est qu’elle a su dire « non » à toutes sortes de demandes, et dire à propos des génériques : « attendons la bonne implémentation ».
      Je suis plus biologiste computationnel que programmeur, donc mon usage de Go est irrégulier, mais quand je reviens à Go, mon ancien code compile et le langage se comporte comme prévu.
      En même temps, j’apprécie que Rob Pike reconnaisse les erreurs commises en apprenant à impliquer la communauté, tout en n’acceptant pas toutes les fonctionnalités brillantes qui passaient.
    • Je viens de Python. Ces temps-ci, avec des outils d’IA comme Bard et GPT-4, je convertis directement d’anciens utilitaires Python en Go.
      Certains ont fonctionné immédiatement, d’autres ont nécessité quelques ajustements parce que le modèle d’IA avait des informations d’API un peu obsolètes.
      Malgré tout, le fait de copier un programme sur un serveur avec scp et de le voir fonctionner tout simplement est incroyable comparé à la danse qu’il fallait refaire à chaque fois avec Python autour du « c’est quoi le système de venv à la mode cette fois-ci ? »
    • Je ne pense pas que Zig et Deno soient de très bons points de comparaison avec Golang. Elixir et ReasonML sont plutôt plus proches, et, si l’on regarde du côté interne à Google, il y a aussi Dart.
  • Excellent article, mais il donne aussi une impression assez auto-congratulatoire. Je m’attendais à une reconnaissance des problèmes plus profonds du langage ; au fond, le message semble être que, pour eux, le langage est parfait et que le problème, c’est moi
    C’est pourquoi j’ai du mal à recommander Go. Il y a des problèmes avec le système de types, la gestion des erreurs, la concurrence non sûre, une syntaxe trop simpliste, nil, les valeurs zéro par défaut, et beaucoup de packages courants laissés à l’abandon
    Aujourd’hui, j’utilise Rust comme langage principal. Son écosystème est actif et il a une vision sur plusieurs aspects où Go n’en a pas
    Pour le dire plus crûment, Go a sans doute eu son époque quand il était en concurrence avec PHP comme langage backend

    • Je ne trouve pas que ça apporte grand-chose au débat. Ça se lit comme une défense de Rust, sans points précis
      Le premier paragraphe dit « je n’aime pas », le deuxième est sarcastique, le troisième aussi « je n’aime pas », le quatrième dit « Rust est meilleur », et le cinquième est encore sarcastique
    • Les scientifiques de la lignée Plan 9 aiment vraiment trop leur propre marque. J’ai commencé à utiliser Go en 2012, mais j’ai abandonné après la suppression de deps.dev
      Quelques années plus tard, au travail, j’ai essayé d’introduire Go dans l’équipe pour faire avancer les choses, mais un autre ingénieur a pris le temps d’examiner le langage et a listé les raisons pour lesquelles il n’était pas terrible ; il avait raison
      Le point essentiel était que, même s’il est simple, de petites choses comme la gestion des erreurs et les imports inutilisés rendent son usage pénible. Personnellement, j’aimais bien la gestion des erreurs, mais je détestais le système de types
    • J’ai utilisé Go avant d’apprendre Rust, et voir la différence entre les deux a profondément changé ma façon de penser
      Comme j’avais déjà utilisé OCaml, je connaissais la valeur des types Option et Result par rapport à try/catch ou nil, mais j’utilisais Go parce qu’il était facile. Cette facilité a toutefois un coût de maintenance à long terme. Mieux vaut bien faire les choses dès le départ et ne pas affronter les difficultés plus tard
      Je ne veux pas le dire à la légère, mais j’ai souvent entendu Go décrit comme un langage qui a pris les 50 dernières années de progrès des langages de programmation et les a jetées à la poubelle
    • Je suis d’accord avec ce ressenti sur les langages de programmation, mais pour défendre Go, c’est plutôt un langage fait par et pour des gens qui ne s’intéressent pas vraiment aux langages de programmation en tant que tels
      Ce n’est pas péjoratif. Rob Pike ne se préoccupe pas du fait que la concurrence ne soit pas sûre ou que nil soit l’erreur à un milliard de dollars, et la plupart des utilisateurs de Go non plus
      Est-ce que cela fait de Go un bon langage ? Non. Mais ce n’est pas le sujet. Go est un langage pratique et suffisamment correct, associé à des outils convaincants qui le rendent facile à utiliser. C’est un peu les Crocs des langages de programmation
    • J’ai appris Rust, mais la communauté des utilisateurs de Rust rend impossible d’aimer le langage. Des années ont passé et ça n’a pas changé ; si ça a évolué, ce serait plutôt en pire qu’en mieux
      Si j’ai besoin d’une forte intégrité et de sécurité, j’utiliserais Ada, ou Ada/SPARK avec vérification formelle. Pour le reste, Go offre une productivité bien supérieure à Rust
      Personnellement, je vois Rust comme un cas emblématique de sur-ingénierie, à la manière de C++
  • Ça va paraître amer, mais il y a 10 ans, sur go-nuts, on s’est moqué de moi, et Rob Pike m’a répondu avec mépris. J’avais osé dire que la manière dont go get et les imports de modules via le réseau fonctionnaient, étaient promus dans toute la documentation pour débutants et utilisés par l’ensemble de la communauté, finirait par être nuisible et à courte vue

    • Le système de packages de Go, surtout avant les modules, donne l’impression d’un hack qui greffe de force un comportement externe sur un système plus limité conçu pour fonctionner uniquement dans le monorepo de Google
      L’étrange arbre d’espace de noms global a du sens dans ce contexte, et l’insistance sur les artefacts générés versionnés se comprend aussi si l’on considère que Google inclut même des produits de build dans son monorepo
    • Il reste intéressant de constater que ce que Go a produit est meilleur que ce que proposent d’autres langages
      Bien sûr, il y a le problème de v2 ou celui du v0 éternel. Mais c’est quand même mieux que d’utiliser npm, ou que de devoir gérer un truc Python qui vous donne envie de faire un signe de croix
    • Rob Pike a surtout révélé au monde à quel point il ignorait la théorie des langages de programmation découverte après 2000
  • Cet article ressemble à une version plus personnelle de l’article publié dans l’ACM [1]. Les deux reconnaissent qu’ils n’ont pas créé un nouveau langage de programmation remarquable du point de vue de la spécification du langage, mais qu’ils ont très bien construit tout ce qui entoure le langage, ce qui peut finalement être plus important
    Dans l’article soumis, ils disent avoir inventé l’approche des interfaces et celle de la concurrence. Mais les goroutines sont équivalentes aux threads de Haskell, et les interfaces, lorsqu’elles prennent en charge des paramètres génériques comme aujourd’hui, ressemblent beaucoup aux typeclasses de Haskell. Comme Haskell est antérieur à Go, il est intéressant de voir des programmeurs impératifs redécouvrir indépendamment la puissance d’idées issues de la programmation fonctionnelle
    Une véritable innovation de Go est que l’implémentation d’une interface n’a pas besoin de déclarer l’interface qu’elle implémente. Du point de vue de la sûreté, c’est horrible, mais en pratique cela pose rarement problème, et cela élimine les terribles problèmes de dépendances circulaires que l’on rencontre avec Haskell et Rust
    [1] https://cacm.acm.org/magazines/2022/5/260357-the-go-programm...

    • Je pense que tu sous-estimes à quel point le fait que les interfaces soient des types structurels a été important dans l’effet global de cette fonctionnalité sur le langage, puis sur les idiomes et l’écosystème
      Si les types avaient dû déclarer à l’avance les interfaces qu’ils implémentent, Go aurait été un langage complètement différent. C’était l’un des principaux éléments différenciateurs de Go. Du moins jusqu’à ce que TypeScript arrive avec des interfaces structurelles pour d’autres raisons
    • Le typage structurel est déjà un concept vieux de plus de 25 ans, et il était déjà utilisé dans des langages comme OCaml et Scala
    • Je ne vois pas en quoi c’est une innovation. Tous les langages grand public antérieurs à Go qui me viennent à l’esprit fonctionnent de cette façon
      Peux-tu citer ne serait-ce qu’un langage de programmation digne d’intérêt qui, lorsque tu définis une interface, t’oblige à fournir son implémentation ?
  • Il me semble que les problèmes liés à la cryptographie de Go n’ont pas encore été beaucoup évoqués. Après qu’OpenSSH a abandonné SHA1, il a fallu un an à l’équipe Go pour ajouter la prise en charge de SHA2 dans x/crypto/ssh [1]. Gitea en a été une victime notable [2]
    De plus, voir un mainteneur crypto attaquer GnuPG [3] et tenter d’entamer la confiance envers Dan Bernstein [4] n’inspire pas confiance
    [1]: https://github.com/golang/go/issues/49269
    [2]: https://github.com/go-gitea/gitea/issues/17798
    [3]: https://twitter.com/FiloSottile/status/1127643698676797441
    [4]: https://twitter.com/FiloSottile/status/1555669786826244096

    • Le problème, c’est que les packages x/ sont souvent laissés à l’abandon et suivent un modèle de développement qui rend difficile, pour de nouveaux contributeurs, de faire accepter des correctifs
      En revanche, je considère que le package crypto de la bibliothèque standard est l’une des grandes réussites de Go. OpenSSL a longtemps été une catastrophe, et Go, en particulier agl, a créé et diffusé une implémentation de remplacement très largement utilisée, d’une qualité moyenne élevée. C’est particulièrement vrai du point de vue du nombre bien plus réduit de pièges dans l’API publique
  • L’article cite gofmt comme quelque chose de « réussi », et cela mérite vraiment d’être souligné
    Pour beaucoup de concepteurs et de défenseurs de langages, cela peut sembler anodin, mais cela apporte une valeur énorme en éliminant complètement, dès le premier jour du projet Go, l’un des débats de peinture du local à vélos les plus courants
    J’ai vu plusieurs langages plus récents le copier délibérément, ou l’adopter en se disant que, puisque Go l’avait, il leur en fallait un aussi
    J’ai vu des règles de formatage assez étranges, mais très peu auxquelles il soit impossible de s’habituer. À l’inverse, dans les bases de code sans règles de formatage imposées, le résultat rendait souvent le code plus difficile à comprendre

    • J’ai tendance à bricoler le formatage du code, et j’apprécie que go fmt rende cela en grande partie inutile
  • Je suis d’accord avec l’idée selon laquelle « l’existence d’une bibliothèque solide et bien conçue, couvrant l’essentiel de ce qu’il faut pour écrire du code serveur au XXIe siècle, a été un atout majeur ».
    Go a été financé par Google parce que Google avait un problème. Il fallait écrire beaucoup de code applicatif côté serveur, Python était trop lent et C++ trop fragile. Go s’insérait très bien dans cet entre-deux.
    Le gros bonus, c’est que des gens de Google ont écrit les bibliothèques nécessaires à ce genre de travail et les utilisaient aussi en interne. Donc, quand on utilisait ces bibliothèques, même les chemins d’erreur avaient souvent été réellement exercés par du code en production.
    J’ai des désaccords techniques avec le langage. En particulier, au début, l’accent mis sur l’usage de files pour tout, jusqu’à construire des mutex avec des files. Mais pour le cas d’usage visé, les green threads étaient le bon choix. Le problème de la couleur des fonctions est un vrai problème, et les astuces alambiquées qu’il faut employer en Rust pour faire cohabiter asynchrone et threads vont beaucoup trop loin. Go sacrifie un peu de performance et gagne énormément en simplicité.
    L’ancienne aversion pour les threads est aussi intéressante. J’ai commencé sur des mainframes UNIVAC, où les threads existaient depuis 1967 et s’appelaient alors des « activities ». En 1972, il y avait non seulement des threads en espace utilisateur, mais ils tournaient aussi sur des multiprocesseurs symétriques. Il y avait aussi des E/S asynchrones, des fonctions de complétion en espace utilisateur, des instructions intégrées pour les verrous, et un système d’exploitation lui-même threadé en interne.
    Les threads et les multiprocesseurs étaient considérés comme normaux, et en passant à UNIX, j’ai eu l’impression de les perdre. Il a fallu des décennies à UNIX/Linux pour rattraper ce retard dans ce domaine, et plusieurs générations de programmeurs n’ont pas su utiliser les multiprocesseurs à mémoire partagée.
    La théorie initiale de la concurrence de Dijkstra a souvent été réinventée avec une autre terminologie et des conceptions parfois pires. Les gens de Go comprenaient le bounded buffer de Dijkstra, et pourquoi les bounded buffers de longueur 0 et 1 sont utiles. C’était agréable de revoir cela. Avec les bonnes primitives, la concurrence n’est pas si difficile. Si l’on essaie de résoudre le problème à la manière classique de pthreads, en saupoudrant des verrous un peu partout, ça ne fonctionne pas correctement. Le fait qu’aux débuts d’UNIX/Linux, l’ordonnanceur CPU était vraiment médiocre et que le déblocage des threads se comportait de façon atroce n’a pas aidé non plus.

    • Des commentateurs HN quelconques répètent souvent des choses comme « Go a été financé parce que Google avait un problème », mais c’est parce qu’ils ne savent pas vraiment comment Google fonctionne ni à quel point l’entreprise est grande.
      Go a été créé parce que Rob Pike avait un problème. Il n’aimait pas C++, Java ni Python, et comme il était Rob Pike, Google l’a autorisé à passer plusieurs années à travailler sur un nouveau langage. Ce n’est pas Larry, Sergey, Sundar ou Eric qui sont allés voir Rob pour lui demander de faire quelque chose.
      En gros, Go a été financé parce que Rob Pike a demandé du soutien, que Google voulait garder Rob Pike, et qu’on pensait qu’il ferait presque certainement quelque chose d’intéressant. Dans Google Engineering, l’argent de l’entreprise revient en pratique surtout à autoriser des gens à travailler.
      Comme Rob Pike était un ingénieur exceptionnel, Go s’est révélé plutôt bon à certains égards, et correspondait bien à son problème initial : devoir utiliser C++, Python ou Java pour écrire des applications opérationnelles chez Google. Certaines personnes en interne chez Google étaient d’accord et ont commencé à utiliser Go, dont quelques personnes influentes qui ont « encouragé » les autres à utiliser Go plutôt que Python.
    • Go n’est pas simplement un projet Google : c’est en fait la philosophie de compilateur de Plan 9 et CSP pour Unix/Linux.
    • Cela ne correspond pas à mes souvenirs de l’époque où je travaillais chez Google. Comme le mème selon lequel « Go était destiné à la programmation système », c’est plutôt une croyance qui ne tient pas très bien quand on l’examine.
      En 2009, chez Google, à l’exception du cas de l’acquisition de YouTube, Python était très peu utilisé pour des serveurs au-delà de quelques utilitaires internes ; on peut donc écarter cette idée immédiatement. Le plus gros serveur Python développé par Google lui-même était Mondrian, l’outil de revue de code écrit par Guido van Rossum, qui a ensuite été remplacé par Critique, écrit en Java.
      À l’époque, Google avait une politique des trois langages assez stricte afin d’éviter les guerres de langages de programmation. On pouvait utiliser C++, Java et Python ; Python servait aux scripts, C++ à l’infrastructure, et Java aux serveurs web.
      Il y avait aussi des zones de recouvrement. Java avait été introduit plus tard que C++, et certains serveurs web étaient restés en C++ parce qu’ils étaient difficiles à réécrire. Il y eut aussi des tentatives de migration progressive vers Java, mais elles ne se sont pas vraiment imposées. Certains serveurs d’infrastructure, comme Megastore, étaient écrits en Java, tandis que les bibliothèques de base étaient généralement en C++ avec des bindings JNI et Python.
      Il y avait aussi des failles dans la politique : certaines équipes ont créé leurs propres langages pour l’infrastructure interne, et la base de code réelle utilisait aussi des langages de configuration personnalisés ainsi que Sawzall, créé par Rob Pike. Sa syntaxe ressemblait un peu à celle de Go.
      Dans l’ensemble, les gens avaient beaucoup de liberté de choix, et les nouveaux serveurs web étaient principalement écrits en Java, tandis que les nouveaux moteurs de base de données, par exemple, étaient principalement écrits en C++.
      Écrire du code asynchrone était certainement difficile, et il est vrai que Go a correctement résolu ce problème. Mais Go n’était pas un projet lancé par la haute direction pour résoudre les problèmes de Google. Non pas que la direction aurait eu peur de ce genre de projet : il existait énormément de projets d’infrastructure internes créés et dotés en personnel par les équipes concernées pour résoudre directement les difficultés des développeurs. Les grandes mises à niveau réseau menées à l’époque en sont un exemple. Ces projets étaient annoncés à l’avance.
      Je ne me souviens pas qu’il y ait eu une grande insatisfaction vis-à-vis de la situation. Les temps de build étaient un problème jusqu’à ce que Bazel/Blaze fonctionne avec des clusters de build distants ; ensuite, tout était mis en cache à distance, si bien que même d’immenses bases de code pouvaient être compilées en quelques secondes. La vitesse du compilateur local est devenue presque insignifiante, et javac était aussi très rapide.
      L’annonce de Go a été assez surprenante. S’il avait vraiment été développé pour résoudre un problème de Google, la manière habituelle de Google aurait été de le lancer d’abord en interne, de le faire évoluer pendant quelques années avec des utilisateurs internes, puis de le rendre public. Mais Go a d’abord été rendu public. Les gens autour de moi se demandaient à quoi cela pouvait bien servir, une réaction qu’on aurait difficilement attendue si une demande interne avait réellement été le moteur du projet.
  • Le passage sur la décision d’utiliser le compilateur C de Ken Thompson plutôt que LLVM est intéressant. Les gens s’en sont plaints, et surtout dans les premières versions, cela a aussi eu pour effet de produire du code moins optimisé
    En contrepartie, cela a permis de créer rapidement des piles segmentées. S’il avait fallu les implémenter dans LLVM et se conformer à l’ABI LLVM, il est possible qu’ils ne l’aient tout simplement pas fait
    Dans l’article, ce n’est pas présenté comme le seul bénéfice de cette décision, mais comme un exemple de bénéfice

    • Le contenu de l’interview au sujet de LLVM n’est pas exact. Pour Rust, nous avons implémenté des piles segmentées avec LLVM, et en pratique c’était assez simple
      X86FrameLowering avait déjà une prise en charge, qui existait aussi au moment de la sortie de Go. Quand on activait le fractionnement de pile, LLVM émettait un test dans le prologue de fonction et, si nécessaire, appelait __morestack pour allouer davantage de pile. L’ABI Windows MSVC a elle aussi besoin d’un code très similaire pour prendre en charge _chkstk, ce qui s’articulait naturellement avec la prise en charge de __morestack
      En réalité, faire en sorte que GDB comprenne les piles segmentées a été plus difficile que n’importe quelle partie de l’implémentation du compilateur. C’est indépendant du backend
      Ce que l’auteur a probablement confondu, ce sont les piles relocalisables. À l’époque, c’était difficile à implémenter parce qu’il fallait un ramasse-miettes précis, mais Azul l’a désormais implémenté dans LLVM. À ce moment-là, la façon la plus simple d’implémenter un ramasse-miettes précis consistait à spiller tous les registres à travers les appels de fonction ; cela demandait plus d’efforts d’implémentation, mais rien d’excessif. Comme le compilateur Plan 9 semble de toute façon faire cela, il n’y aurait probablement pas eu de régression de performances par rapport à 6g/8g. Quoi qu’il en soit, la prise en charge du ramasse-miettes d’Azul dispose maintenant d’une vraie implémentation capable de stocker les racines dans les registres
    • Au final, Go n’a-t-il pas abandonné les piles segmentées ? C’était avec Go 1.3, sorti en 2014. À cause du problème des « hot spots » [1]
      La capacité à expérimenter avait donc bien de la valeur, mais cet exemple précis n’est pas un cas parfait
      [1]: https://go.dev/doc/go1.3#:~:text=Go%201.3%20has%20changed%20...
  • En imaginant un langage statiquement typé de loisir, j’essaie quelque chose qui traite à la fois les interfaces et les génériques, et j’ai pu constater par moi-même que Rob a raison. Faire bien fonctionner les deux ensemble est vraiment difficile
    Je pense tout de même que cela en vaut la peine. Personnellement, je trouverais peu gratifiant d’utiliser un langage statiquement typé dans lequel les utilisateurs ne peuvent pas définir eux-mêmes de types génériques
    J’ai déjà programmé dans un environnement BASIC où il y avait GOSUB pour les sous-routines, mais aucun moyen d’écrire une sous-routine prenant des arguments. Je n’ai pas envie de revivre cette expérience au niveau du système de types
    Je comprends donc que l’équipe Go ait mis du temps à trouver un bon design. Concevoir un bon langage est difficile ; concevoir un bon langage avec un système de types l’est 10 fois plus ; concevoir un système de types avec des génériques l’est encore 10 fois plus

    • Je ne suis pas d’accord. La partie la plus difficile dans l’implémentation des génériques, c’est quand on prend en charge l’héritage d’implémentation, ce que Go ne fait pas
      Go s’est donc attaqué à la partie la plus facile de l’implémentation des génériques. La raison pour laquelle cela n’a pas été fait plus tôt n’était pas technique. Elle était idéologique, fondée uniquement sur l’ignorance, et tenait au fait que la plupart des concepteurs de Go ne suivaient plus le domaine de la théorie des langages de programmation depuis la fin des années 1990
    • Les langages de la famille ML et les langages fonctionnels ne semblent pas avoir ce problème, et beaucoup d’entre eux ont des systèmes de types bien plus sophistiqués et puissants que Go
    • Scala est sorti avant Golang et était déjà en train de gagner en popularité au moment où Golang est apparu. Il ne disposait pas non plus des ressources à l’échelle de GOOG derrière lui