Modern Go Engineering
Chapitre 0
00 - Introduction à Go
00 - Introduction à Go
Cours 00 : Introduction à Go
1. Histoire de Go
1.1 Les origines (2007)
En septembre 2007, Robert Griesemer, Rob Pike et Ken Thompson (trois ingénieurs chez Google) ont commencé à esquisser les objectifs d'un nouveau langage. Les motivations principales étaient :
- Temps de compilation trop longs : Les gros projets C++ chez Google mettaient des heures à compiler
- Gestion des dépendances chaotique : Les systèmes de build comme make devenaient ingérables
- Concurrence difficile : Les threads et locks en C++/Java étaient source d'erreurs
- Manque d'outillage moderne : Pas de formatteur automatique, pas de gestionnaire de paquets standard
Le nom "Go" a été choisi pour sa simplicité et sa signification en anglais. Le logo (le gopher) a été conçu par Renée French (épouse de Rob Pike).
1.2 Les premières versions (2008-2011)
// Hello World en Go (2009)
package main
import "fmt"
func main() {
fmt.Println("Hello, 世界")
}
- Novembre 2009 : Go est annoncé publiquement en open source (licence BSD)
- Janvier 2010 : La documentation en ligne (golang.org) est lancée
- Mai 2010 : Go 1.0 est planifié, le compilateur est réécrit en Go (bootstrapping)
- Mars 2011 : Le
go toolest introduit (gofmt, gobuild, gotest)
1.3 La maturité (2012-2018)
- Mars 2012 : Go 1.0 est publié avec la promesse de compatibilité ascendante
- 2013 : Adoption par Docker, Kubernetes, Terraform
- 2015 : Go 1.5 réécrit entièrement en Go (fin du C)
- 2016 : Introduction de
vendorpour les dépendances - 2018 : Go modules expérimentaux (Go 1.11)
1.4 L'ère moderne (2019-2024)
- 2019 : Go 1.13, go modules par défaut
- 2020 : Go 1.15, améliorations du compilateur (20-30% plus rapide)
- 2021 : Go 1.17-1.18, generics enfin !
- 2022 : Go 1.19-1.20, améliorations de la sécurité
- 2023 : Go 1.21-1.22, boucles améliorées, toolchain management
- 2024 : Go 1.23, itérateurs de fonction, améliorations du runtime
// Go 1.18+ : Generics
func Map[T any](s []T, f func(T) T) []T {
result := make([]T, len(s))
for i, v := range s {
result[i] = f(v)
}
return result
}
// Go 1.22+ : Boucle for améliorée
for i := range 10 {
fmt.Println(i)
}
2. Philosophie de Go
2.1 La simplicité comme principe fondamental
Go a été conçu avec une philosophie radicale de simplicité :
// Pas de classes, pas d'héritage
type Animal struct {
Name string
}
// Les interfaces sont implicites
type Speaker interface {
Speak() string
}
func (a Animal) Speak() string {
return a.Name + " says hello"
}
// Utilisation
var s Speaker = Animal{Name: "Dog"}
fmt.Println(s.Speak())
Principes clés :
- Moins de features : Pas de classes, pas d'héritage, pas d'exceptions, pas de génériques (jusque 1.18)
- Lisibilité > brièveté : Pas de syntaxe implicite, pas de sucre syntaxique excessif
- Explicite > implicite : Les conversions sont explicites, les erreurs sont des valeurs
2.2 La concurrence comme citoyenne de première classe
// Une goroutine : un mot-clé
go func() {
fmt.Println("Exécuté en parallèle")
}()
// Les channels comme primitive de synchronisation
ch := make(chan string)
go func() {
ch <- "message"
}()
msg := <-ch
2.3 Les piliers philosophiques
1. Faites les choses correctement par défaut
// gofmt formate automatiquement
func add(x int, y int) int { return x + y }
2. Communiquez via la mémoire partagée
// "Do not communicate by sharing memory; instead, share memory by communicating."
ch := make(chan int)
3. Zéro valeur utile
var i int // 0
var s string // ""
var b bool // false
var p *int // nil
4. Les erreurs sont des valeurs
f, err := os.Open("file.txt")
if err != nil {
return fmt.Errorf("ouverture fichier: %w", err)
}
3. Écosystème et outils
3.1 La toolchain Go
go version # Version de Go installée
go env # Configuration Go
go fmt # Formattage automatique
go build # Compilation
go run # Compilation + exécution
go test # Tests unitaires
go mod init # Initialisation d'un module
go mod tidy # Nettoyage des dépendances
go vet # Analyse statique
go doc # Documentation
3.2 Les outils essentiels
gofmt / goimports
// Avant gofmt :
func add( x int, y int )int{ return x+y;}
// Après gofmt :
func add(x int, y int) int { return x + y }
go vet
func main() {
s := "hello"
fmt.Printf("%d", s) // go vet détecte cette erreur de format
}
3.3 Les modules Go (go mod)
// go.mod
module github.com/user/project
go 1.23
require (
github.com/gin-gonic/gin v1.9.1
github.com/go-sql-driver/mysql v1.7.1
)
3.4 Les outils communautaires
| Outil | Utilité | Commande |
|---|---|---|
| golangci-lint | Linting complet | golangci-lint run |
| delve | Debugger | dlv debug |
| go-swagger | Documentation API | swagger generate |
| mockgen | Génération de mocks | mockgen -source=file.go |
| wire | Injection de dépendances | wire |
4. Comparaison avec d'autres langages
4.1 Go vs Java
// Go : Simple, rapide à compiler
func sum(a, b int) int { return a + b }
// Équivalent Java
// public static int sum(int a, int b) { return a + b; }
| Aspect | Go | Java |
|---|---|---|
| Syntaxe | Minimaliste | Verbose |
| Compilation | ~1s | ~10s+ |
| Concurrence | Goroutines (2KB stack) | Threads (1MB stack) |
| Génériques | Depuis 1.18 | Depuis JDK 5 |
| Héritage | Composition | Classe |
| Runtime | Compilé natif | JVM |
4.2 Go vs Python
// Go : Statiquement typé, compilé
func process(items []string) ([]string, error) {
result := make([]string, 0, len(items))
for _, item := range items {
if len(item) > 0 {
result = append(result, item)
}
}
return result, nil
}
| Aspect | Go | Python |
|---|---|---|
| Typage | Statique | Dynamique |
| Performance | Compilé natif | Interprété |
| Concurrence | Goroutines | GIL-limited |
| Déploiement | Binaire unique | Runtime requis |
| Productivité | Modérée | Très élevée |
4.3 Go vs Rust
// Go : GC, simplicité, rapidité de développement
type Server struct {
addr string
pool *sync.Pool
}
| Aspect | Go | Rust |
|---|---|---|
| Gestion mémoire | GC | Ownership/Borrowing |
| Courbe apprentissage | Faible | Élevée |
| Concurrence | CSP (channels) | Async/Sync |
| Performance | Très bonne | Excellente |
| Cas d'usage | APIs, réseaux | Système, embarqué |
5. Roadmap et évolution
5.1 Go 1.x (2012-2024+)
Go 1.18 (2022) : Generics
func Max[T constraints.Ordered](a, b T) T {
if a > b {
return a
}
return b
}
Go 1.21 (2023) : Toolchain management
// toolchain directive dans go.mod
toolchain go1.23.0
Go 1.22 (2024) : Boucles améliorées
// Itération sur entiers
for i := range 10 {
// i va de 0 à 9
}
// Capture correcte dans les boucles
for _, v := range slice {
go func() {
fmt.Println(v) // v est correctement capturé
}()
}
Go 1.23 (2024) : Itérateurs de fonction
// Itérateurs personnalisés
func Backward[E any](s []E) func(func(int, E) bool) {
return func(yield func(int, E) bool) {
for i := len(s) - 1; i >= 0; i-- {
if !yield(i, s[i]) {
return
}
}
}
}
5.2 Futures directions
- Amélioration des generics : Meilleure inférence, types de type supérieur
- Zero-cost abstractions : Optimisation des interfaces et goroutines
- Meilleur support WASM : WebAssembly cible de première classe
- Telemetry : Collecte de données d'utilisation (opt-in)
- Tooling : Amélioration continue de l'éditeur LSP (gopls)
Résumé
- Go a été créé en 2007 chez Google pour résoudre des problèmes concrets
- La philosophie repose sur la simplicité, la lisibilité et la concurrence
- L'écosystème est riche avec gofmt, go mod, go test, etc.
- Go se positionne idéalement pour les APIs, le cloud, et les outils systèmes
- La roadmap montre une évolution prudente mais régulière
Exercices
- Installation : Installez Go 1.22+, configurez votre GOPATH
- Premier programme : Écrivez "Hello, 世界" et observez le support Unicode
- Outils : Testez gofmt, go vet, go doc sur un petit programme
- Benchmark : Comparez temps de compilation Go vs C++ vs Java
- Concurrence basique : Lancez 1000 goroutines et observez l'utilisation mémoire