Aller au contenu

Histoire de Go

Go est ne en 2007 dans les bureaux de Google, conçu par Rob Pike, Ken Thompson et Robert Griesemer pour résoudre des problèmes concrets rencontres à grande échelle : compilations C++ de plusieurs minutes, difficulté a maîtriser la concurrence et une base de code devenue ingerable. Le langage est rendu public en novembre 2009, et Go 1.0 est publie en mars 2012 avec une promesse de compatibilité ascendante qui tient encore aujourd'hui.


Origines et motivations

En 2007, Google compile des millions de lignes de C++ chaque jour. Les builds prennent parfois trente minutes. Rob Pike, Ken Thompson (co-créateur d'Unix et du C) et Robert Griesemer decidient de partir d'une feuille blanche.

Les problèmes a résoudre :

  • Compilation lente : C++ avec ses headers inclus en cascade est lent a compiler
  • Gestion de la concurrence : les threads POSIX et les mutex sont difficiles a utiliser correctement
  • Lisibilite : les grandes bases de code C++ ou Java deviennent difficiles a naviguer
  • Dépendances : la gestion des dépendances C/C++ est fragmentee et fragile

Go répond a chacun de ces points :

Problème Solution Go
Compilation lente Import explicite, pas de headers, compilation rapide
Concurrence complexe Goroutines et channels (CSP)
Lisibilite dégradée Syntaxe minimaliste, gofmt impose
Dépendances fragiles Go modules (depuis 1.11), sum database
// Premier programme Go — Hello, World
// go run hello.go
package main

import "fmt"

func main() {
    fmt.Println("Hello, World")
}

Go 1.0 et la promesse de compatibilité

Go 1.0 est publie le 28 mars 2012. Avec cette version, l'équipe annonce une garantie forte : tout programme qui compile avec Go 1.0 doit continuer a compiler et s'exécuter correctement avec toutes les versions ultérieures de Go 1.x.

Cette promesse est tenue depuis plus de douze ans. Elle est l'un des piliers de la confiance de l'écosystème : les entreprises peuvent adopter Go sans craindre de migrations cassantes.

La compatibilité Go 1

La garantie de compatibilité couvre le langage, la bibliotheque standard et les outils. Elle ne couvre pas les comportements non définis, les fonctions marquées internal, ni les APIs experimentales sous golang.org/x/.


Chronologie des versions majeures

Version Date Événements clés
1.0 Mars 2012 Première version stable, promesse de compatibilité
1.1 Mai 2013 Performances ameliorees, race detector
1.4 Dec 2014 Runtime reecrit en Go (suppression du C), go generate
1.5 Aout 2015 Garbage collector à faible latence, compilateur Go en Go pur
1.6 Fev 2016 HTTP/2 natif dans net/http
1.7 Aout 2016 Package context officiel, compilation plus rapide
1.9 Aout 2017 sync.Map, test parallèles avec t.Parallel()
1.11 Aout 2018 Go modules (experimental), GOPATH moins obligatoire
1.13 Sep 2019 Go modules stables, errors.Is et errors.As, proxy par défaut
1.14 Fev 2020 Goroutines preemptibles, defer plus rapide
1.16 Fev 2021 embed, io/fs, modules par défaut sans GOPATH
1.17 Aout 2021 Passage des arguments via registres (ABI), lazy loading des modules
1.18 Mars 2022 Génériques (type parameters), fuzzing natif, workspace mode
1.19 Aout 2022 Documentation Go doc avec liens, atomic types
1.20 Fev 2023 PGO (profile-guided optimization), comparable constraint
1.21 Aout 2023 Package log/slog (logging structure), slices, maps, cmp
1.22 Fev 2024 Range over integers, range over functions (experimental), fix boucle for
1.23 Aout 2024 Range over functions stable, iterators dans la stdlib

L'introduction des génériques (Go 1.18)

L'absence de génériques etait la critique la plus recurrente adressee a Go depuis sa création. Go 1.18 (mars 2022) introduit les type parameters, permettant d'écrire des fonctions et des types parametres par leur type.

// Avant Go 1.18 — fonction repetee pour chaque type
func SommeInts(s []int) int {
    total := 0
    for _, v := range s {
        total += v
    }
    return total
}

// Depuis Go 1.18 — fonction generique
// Contrainte Number definie avec une union de types
type Number interface {
    int | int64 | float64
}

func Somme[T Number](s []T) T {
    var total T
    for _, v := range s {
        total += v
    }
    return total
}

// Utilisation — l'inference de type evite de specifier [int] explicitement
total := Somme([]int{1, 2, 3, 4, 5})        // => 15
totalF := Somme([]float64{1.1, 2.2, 3.3})   // => 6.6

Génériques avec moderation

Les génériques Go sont moins expressifs que ceux de Rust ou Haskell. L'équipe Go recommande de ne les utiliser que pour des structures de données génériques (slices, maps, sets) et des algorithmes purs. Pour la logique métier, les interfaces restent preferables.


Gouvernance et processus de proposals

Go est développé par une équipe Google (Go team) mais le processus est ouvert :

  • Proposals : toute proposition de changement passe par un issue GitHub avec le label Proposal
  • Review : l'équipe Go et la communauté discutent publiquement
  • Décision : l'équipe Go tranche (pas de vote communautaire, contrairement a Rust RFC)
  • Implémentation : le changement est soumis via Gerrit (pas GitHub PRs pour le core)

Le dépôt principal est sur go.googlesource.com/go, avec un miroir en lecture seule sur GitHub.

# Contribuer a Go — setup du depot
git clone https://go.googlesource.com/go
cd go/src
./all.bash   # Lance la suite de tests complete (~10 minutes)

Le cycle de release est semestriel (fevrier et aout), avec des patch releases entre les deux pour les corrections de sécurité.


Positionnement actuel

Go s'est impose comme le langage de référence pour l'infrastructure cloud et les outils système. Son empreinte dans l'écosystème cloud native est considérable :

Domaine Outils phares en Go
Orchestration Kubernetes, Docker, containerd, CRI-O
Infrastructure as Code Terraform, OpenTofu, Pulumi
Observabilité Prometheus, Grafana, Jaeger, OpenTelemetry
Réseau / proxy Envoy data plane (Go control plane), Traefik, Caddy
CLI DevOps kubectl, helm, gh, k9s, lazygit
Bases de données CockroachDB, TiDB, BadgerDB, etcd
Services web GitHub Copilot backend, Dropbox, Cloudflare, Uber

Pourquoi Go domine le cloud native

Go compile en un binaire statique sans dépendance externe. Ce binaire tient dans une image Docker scratch de quelques megaoctets. La latence de démarrage est quasi nulle et la consommation mémoire est faible. Ces caractéristiques sont idéales pour les conteneurs et les fonctions serverless.


Philosophie du langage

Go est délibérément minimaliste. Certaines fonctionnalités absentes d'autres langages sont absentes par choix :

  • Pas d'héritage : uniquement la composition par embedding et les interfaces implicites
  • Pas d'exceptions : la gestion d'erreurs est explicite via les valeurs de retour
  • Pas de surchargé de fonctions : une fonction, une signature
  • Pas de macro : le code est ce qu'il est, sans metaprogrammation cachee
  • Pas de gestionnaire de versions du langage : go.mod pointe vers une version minimale

Cette philosophie produit un code uniforme et prévisible. Un développeur Go peut lire du code écrit par n'importe quelle équipe sans surprises syntaxiques.


Go et la concurrence — modèle CSP

La concurrence est une fonctionnalité de première classe dans Go, inspirée du modèle CSP (Communicating Sequential Processes) de Tony Hoare (1978). Le principe est simple : les goroutines communiquent en s'echangeant des messages via des channels plutôt qu'en partageant de la mémoire.

"Do not communicate by sharing memory; instead, share memory by communicating."
— Rob Pike
// Exemple de concurrence idiomatique Go
// Deux goroutines communiquent via un channel
package main

import (
    "fmt"
    "time"
)

func producteur(ch chan<- int, n int) {
    for i := 0; i < n; i++ {
        ch <- i * i  // Envoi dans le channel
        time.Sleep(10 * time.Millisecond)
    }
    close(ch) // Signal de fin : fermeture du channel
}

func main() {
    ch := make(chan int, 5) // Channel buffere de capacite 5
    go producteur(ch, 10)  // Lancement d'une goroutine

    // range sur un channel lit jusqu'a sa fermeture
    for valeur := range ch {
        fmt.Println(valeur)
    }
}

Une goroutine consomme environ 2 Ko de pile au démarrage (contre plusieurs Mo pour un thread OS). Un programme Go peut lancer des millions de goroutines sans épuiser la mémoire.


Comparaison avec les langages contemporains

Critère Go Rust Java Python
Vitesse de compile Très rapide Lente Rapide N/A (inter)
Concurrence CSP natif async/await Threads JVM asyncio/GIL
Gestion mémoire GC Ownership GC JVM GC CPython
Binaire statique Oui Oui Non (JVM) Non
Courbe d'app. Douce Abrupte Modérée Douce
Génériques Depuis 1.18 Depuis 1.0 Depuis 1.5 Duck typing

Go se distingue par son équilibre : performances proches du C sans la complexité de Rust, simplicité proche de Python sans sacrifier les performances statiques.