📖 Manuel
Go Concurrency Guide
Workflow
- Fondamentaux Go : Structurer le code avec des structs et méthodes (value vs pointer receivers), définir des comportements avec des interfaces implicites (duck typing), gérer les erreurs comme des valeurs de retour (
func f() (T, error)), utiliserdeferpour le cleanup garanti (close, unlock, log), comprendre lesinit()functions et leur ordre d'exécution dans les packages.
- Goroutines et channels : Lancer des goroutines légères avec
go func(), créer des channels typés unbuffered (synchrone) ou buffered (make(chan T, n)), utiliserselectpour multiplexer plusieurs channels, implémenter le done pattern avecchan struct{}pour signaler l'arrêt, appliquer fan-in (merge de plusieurs channels) et fan-out (distribution vers plusieurs workers).
- Patterns de concurrence : Implémenter le worker pool (N goroutines lisant depuis un channel de jobs), le pipeline (chaîne de stages transformant des données via channels), le semaphore avec un buffered channel (
make(chan struct{}, n)) pour limiter la concurrence, le rate limiting avectime.Ticker, propager l'annulation et les deadlines aveccontext.Context.
- Sync primitives : Protéger les données partagées avec
sync.Mutex(exclusion mutuelle) etsync.RWMutex(lecture concurrente), synchroniser la fin de goroutines avecsync.WaitGroup, exécuter une initialisation unique avecsync.Once, utilisersync.Mappour les maps concurrentes, les opérations atomiques avecsync/atomicpour les compteurs haute performance.
- Error handling Go : Propager les erreurs avec wrapping (
fmt.Errorf("context: %w", err)), définir des sentinel errors avecvar ErrNotFound = errors.New("not found"), créer des erreurs custom en implémentant l'interfaceerror, tester le type avecerrors.Is(valeur) eterrors.As(type), toujours handler les erreurs sans_dans le code de production.
- Testing Go : Structurer les tests table-driven (
testCases := []struct{...}{{...}}), benchmarker avecfunc BenchmarkXxx(b testing.B)etb.ResetTimer(), utiliser le fuzzing (func FuzzXxx(f testing.F)) pour les parseurs et fonctions critiques, tester les handlers HTTP avecnet/http/httptest, utilisertestify(assert,require,mock) pour des assertions expressives.
- Packages et modules : Initialiser avec
go mod init module/path, organiser en packages cohésifs (éviter les packagesutils/common), utiliserinternal/pour le code non-exporté hors du module, gérer les versions avecgo get module@v1.2.3, utilisergo.workpour le développement multi-modules en local, respecter les conventions de nommage des packages (court, sans underscore).
- Production Go : Logger structuré avec
log/slog(Go 1.21+) ouzap/zerolog, exposer les métriques avecprometheus/client_golang, profiler avecnet/http/pprof(CPU, mémoire, goroutines), linter avecgolangci-lint(configuration.golangci.yml), automatiser avec unMakefile(build,test,lint,docker), structurer les binaires aveccmd/etinternal/.
Règles
- Écrire du Go idiomatique : interfaces petites (1-2 méthodes), composition plutôt qu'héritage, nommage court en contexte local (
ipasindexdans une boucle courte). - Ne jamais ignorer une erreur ; si une erreur est vraiment ignorable, commenter pourquoi avec
//nolint:errcheck // reason. - Respecter la règle "Don't communicate by sharing memory; share memory by communicating" : préférer les channels aux mutexes pour la coordination, les mutexes pour la protection de state.
- Utiliser
context.Contextsystématiquement pour la propagation des deadlines, timeouts et annulations dans toutes les fonctions I/O-bound. - Expliquer les invariants de concurrence : documenter quel goroutine possède quelle donnée, quels channels communiquent quoi, et pourquoi le design évite les race conditions.