Skill de Maîtrise de Go
Écrivez du Go idiomatique de qualité production pour tout usage. Ce skill encode la sagesse collective de l'écosystème Go à partir de Go 1.22+ (2024-2026).
Version de base Go : 1.22 | Fonctionnalités jusqu'à : 1.26 | Mis à jour : février 2026
Avant d'écrire du code Go, intériorisez les principes ci-dessous. Pour des plongées approfondies sur des sujets spécifiques, lisez les fichiers référencés.
Fichiers de Référence — À Lire au Besoin
| Fichier | Quand le lire |
|---|---|
references/concurrency.md | Goroutine, canal, primitive de synchronisation, travail parallèle |
references/http-and-apis.md | Serveurs HTTP, routeurs, middleware, API REST/gRPC, WebSockets |
references/database.md | SQL, ORM, pools de connexions, migrations, transactions |
references/testing.md | Tests unitaires, tests d'intégration, benchmarks, fuzzing |
references/errors-and-resilience.md | Gestion des erreurs, tentatives, circuit breakers, dégradation gracieuse |
references/performance.md | Profilage, réduction d'allocation, réglage GC, benchmarking |
references/cli-and-config.md | Frameworks CLI, configuration, gestion d'environnement |
references/project-patterns.md | Disposition de projet, DI, systèmes de plugins, génération de code |
references/platform-and-build.md | Cross-compilation, spécificités Windows, intégration, distribution |
references/security.md | Auth, secrets, validation d'entrée, TLS, modèles OWASP |
references/modern-go.md | Fonctionnalités Go 1.21–1.26, modèles dépréciés, ce que le pré-entraînement se trompe |
references/advanced-patterns.md | Génériques, machines d'état, streaming, ordonnancement, intégration IA/LLM |
references/advanced-resources.md | Ressources externes organisées : internes du compilateur/exécution, assembleur, unsafe, cgo, Raft, opérateurs K8s, Wasm, cryptographie, profilage, livres, conférences, articles académiques |
references/observability.md | Configuration OpenTelemetry, traçage, métriques, journalisation structurée avec corrélation de traces, contrôles de santé, enregistreur de vol, check-list d'instrumentation de production |
references/ecosystem-and-tooling.md | Listes organisées (awesome-go), comparaisons de frameworks (web, ORM, CLI, DI, config), guides de style, CI/CD, Docker, gestion de release, analyse de vulnérabilités, plateformes d'apprentissage, gouvernance Go |
references/internals.md | Planificateur GMP, ramasse-miettes, modèle mémoire, gestion de pile, allocateur mémoire, pipeline du compilateur, unsafe, réflexion, directives compilateur |
references/networking.md | Serveurs TCP/UDP, délais net.Conn, pooling de connexions, mTLS, sockets Unix, résolveurs DNS, protocoles binaires personnalisés, gnet |
references/mcp-and-agents.md | Serveurs MCP (mcp-go, SDK officiel), outils/ressources/invites, frameworks d'agents (ADK, langchaingo, eino), modèles multi-agents, gopls MCP |
references/api-design.md | Nommage REST, pagination (curseur/décalage), erreurs RFC 9457, limitation de débit, versionnement d'API, codegen OpenAPI (oapi-codegen), rétrocompatibilité, en-têtes de dépréciation |
references/cgo-and-interop.md | Bases CGo, mappage de types C, gestion mémoire à travers la frontière, règles de passage de pointeurs, callbacks, liaison statique/dynamique, cross-compilation, alternatives pure Go |
references/design-patterns.md | Modèles GoF en Go (factory, builder, strategy, observer, decorator), composition sur héritage, arbre de décision |
references/distributed-systems.md | Raft, modèle outbox, sagas, verrouillage distribué, idempotence, CRDTs, hachage cohérent |
references/cloud-native.md | Kubernetes client-go, opérateurs controller-runtime, webhooks d'admission, élection de leader, Helm/Kustomize |
references/debugging-and-diagnostics.md | Débogueur Delve, traces de pile, indicateurs GODEBUG, workflow de profilage, tableaux symptôme-diagnostic |
references/style-synthesis.md | Règles de style fusionnées Google + Uber + communauté, nommage, formatage, organisation du code |
references/modules-and-dependencies.md | Opérations go.mod, MVS, espaces de travail, GOPROXY, GOAUTH, vendoring, monorepos multi-modules |
references/encoding-and-serialization.md | JSON (v1/v2), Protocol Buffers, MessagePack, CBOR, CSV, YAML, TOML, tableau de décision de format |
references/wasm-and-embedded.md | WebAssembly (WASI, navigateur), go:wasmexport, TinyGo, modèles embarqués/IoT |
references/migration-guides.md | Traductions Go idiomatiques depuis Python, Java, TypeScript, Rust, C++ — cartes conceptuelles et pièges |
references/testing-advanced.md | Tests basés sur les propriétés (rapid), tests de contrat (Pact), tests de charge (Vegeta), chaos engineering, synctest avancé |
references/supply-chain-security.md | govulncheck, génération SBOM, framework SLSA, cosign, builds reproductibles, compatibilité GODEBUG |
references/ebpf.md | eBPF depuis Go (cilium/ebpf), workflow bpf2go, traçage, mise en réseau, profilage niveau noyau |
references/event-driven.md | Consommateurs/producteurs Kafka, RabbitMQ, NATS, framework Watermill, DLQ, modèles exactly-once |
references/data-structures-and-caching.md | container/heap, container/list, caches LRU, singleflight, cartes fragmentées, filtres bloom, caches à références faibles, modèles de stratégie de cache (aside/write-through/write-behind) |
references/ai-ml-beyond-llm.md | Inférence ONNX Runtime, Gonum, clients de bases de données vectorielles, pipelines d'incorporation, service ML depuis Go |
references/file-io.md | Opérations fichier, composition io.Reader/Writer, I/O bufferisé, streaming, gestion de chemin, os.Root, abstraction fs.FS, fsnotify |
Philosophie Centrale
Go est délibérément simple. Résistez à l'envie d'importer la complexité d'autres écosystèmes.
- Clarté avant l'astuce. Le code est lu 10x plus qu'il n'est écrit. L'explicite bat l'implicite — les mainteneurs futurs (y compris vous-même) vous remercieront.
- Composition sur héritage. Intégrez des interfaces et des structures ; évitez les hiérarchies profondes. Go n'a pas de classes, et c'est intentionnel — de petites pièces composables battent des arbres de types complexes.
- Acceptez des interfaces, retournez des structures. Les fonctions doivent dépendre du comportement (interfaces) et exposer des types concrets. Cela maintient les sites d'appel flexibles tout en rendant les implémentations découvrables et débogables.
- Rendez la valeur zéro utile. Concevez les types pour que
var x Tsoit prêt à l'emploi sans initialisation. Cela élimine toute une classe de bugs de pointeur nil et rend les API naturelles (bytes.Buffer,sync.Mutex,http.Clientfonctionnent tous à la valeur zéro). - Les erreurs sont des valeurs. Gérez-les ; ne les ignorez jamais. Enveloppez-les avec du contexte en utilisant
fmt.Errorf("doing X: %w", err). Les erreurs ignorées deviennent des échecs silencieux qui surgissent des heures plus tard en production. - Ne démarrez pas de goroutines que vous ne pouvez pas arrêter. Chaque goroutine a besoin d'un chemin d'arrêt via l'annulation de contexte ou la fermeture de canal. Les goroutines qui fuient consomment de la mémoire indéfiniment et rendent l'arrêt gracieux impossible.
- stdlib d'abord. La bibliothèque standard de Go est inhabituellement complète. Recourez à des bibliothèques tierces uniquement lorsque la stdlib échoue véritablement — moins de dépendances signifie moins d'audits de sécurité, moins de conflits de versions et des builds plus rapides.
- Le code n'est pas terminé tant qu'il n'est pas
gofmt-propre, ne compile pas et ne passe pas la vérification. Exécutezgofmt/goimports,go build,go vet,go test -race, etgolangci-lint— faites-les devenir des passerelles CI ; le détecteur de course trouve des bugs invisibles à la revue. Lors de l'émission de code sans accès aux outils, maintenez la même barre manuellement : gardez-le formaté gofmt et incluez uniquement les importations que vous utilisez réellement (une importation inutilisée est une erreur de compilation — le glissement classique juste après avoir échangé un idiome pour un autre). - Honorez le contrat de l'appelant, puis optimisez. Lorsqu'une tâche spécifie des identifiants, signatures, format de sortie ou types exacts, reproduisez-les exactement — même si vous les nommeriez ou structureriez différemment. Par défaut, choisissez la solution correcte la plus simple qui satisfait la spécification ; ajoutez de l'abstraction, de l'indirection ou des couches défensives uniquement lorsque la complexité de la tâche l'exige. Faire correspondre la surface requise fait partie de la correction — un renommage ou une restructuration gratuite brise les appelants et les tests.
Structure de Projet
Commencez simplement. Ajoutez de la structure uniquement lorsque le projet l'exige.
Binaire Unique (CLI ou petit service)
myapp/
├── go.mod
├── main.go # package main, point d'entrée
├── app.go # logique applicative centrale
├── app_test.go
└── internal/ # packages privés selon les besoins
└── parser/
├── parser.go
└── parser_test.go
Multi-Binaire / Service de Production
myproject/
├── go.mod
├── cmd/ # points d'entrée — fonctions main() légères
│ ├── api-server/
│ │ └── main.go
│ └── worker/
│ └── main.go
├── internal/ # code applicatif privé (imposé par le compilateur)
│ ├── auth/
│ ├── user/ # package domaine : handler + service + repo
│ │ ├── handler.go
│ │ ├── service.go
│ │ ├── repository.go
│ │ └── model.go
│ ├── platform/ # transversal : db, cache, logging
│ │ ├── postgres/
│ │ └── redis/
│ └── middleware/
├── pkg/ # OPTIONNEL : bibliothèques publiques réutilisables
├── api/ # Spécifications OpenAPI, définitions protobuf
├── migrations/ # Fichiers de migration SQL
├── scripts/ # Outils de build, déploiement, développement
├── configs/ # Fichiers de configuration par défaut
└── Makefile
Règles clés :
internal/est imposé par le compilateur Go — le code ici ne peut pas être importé par des modules externes.cmd/*/main.godoit être léger : analyser les indicateurs, câbler les dépendances, appelerrun(), gérer l'arrêt.- Regroupez par domaine/fonctionnalité, pas par couche technique. Évitez
models/,controllers/,services/— c'est une couche à la Java qui lutte contre le modèle de package de Go. - Évitez les packages
utils/,helpers/,common/— nommez les packages par ce qu'ils fournissent, car les noms vagues attirent du code non apparenté et rendent les importations dénuées de sens. - Un répertoire EST un package. Ne créez pas de répertoires juste pour l'organisation.
Conventions de Nommage
// Packages : courts, minuscules, un seul mot. Pas de tirets bas ni de mixedCaps.
package user // bien
package userService // mal — mixedCaps
// Exporté : MixedCaps. Non exporté : mixedCaps. Les tirets bas sont légaux mais la
// communauté les traite comme un bug de style — ils signalent un code non idiomatique.
func ParseRequest() // exporté
func parseHeader() // non exporté
// Interfaces : suffixe méthode + "-er" pour les interfaces à méthode unique
type Reader interface { Read(p []byte) (n int, err error) }
type Validator interface { Validate() error }
// Getters : Owner(), pas GetOwner(). Setters : SetOwner().
func (u *User) Name() string // getter — le préfixe "Get" est non-Go
func (u *User) SetName(n string) // setter
// Acronymes : tout en majuscules. URL, HTTP, ID, API — pas Url, Http, Id, Api.
type HTTPClient struct{}
var userID int
// Variables d'erreur : ErrXxx. Types d'erreur : XxxError.
var ErrNotFound = errors.New("non trouvé")
type ValidationError struct { Field string; Message string }
// Contexte : premier paramètre, toujours nommé ctx. C'est une convention Go universelle
// qui rend la propagation du contexte instantanément reconnaissable dans n'importe quelle base de code.
func (s *Service) GetUser(ctx context.Context, id string) (*User, error)
Gestion des Erreurs
C'est le modèle le plus distinctif de Go. Maîtrisez-le.
// Vérifiez chaque erreur — enveloppez avec du contexte en utilisant %w
f, err := os.Open(name)
if err != nil {
return fmt.Errorf("ouverture de la config %s : %w", name, err)
}
defer f.Close()
// errors.AsType — extraction d'erreur typée générique [Go 1.26+]
// Préféré à errors.As : type-safe, pas de variable pré-déclarée nécessaire.
if pathErr, ok := errors.AsType[*fs.PathError](err); ok {
fmt.Println("échec au chemin :", pathErr.Path)
}
Règles clés :
return errsans contexte rend le débogage douloureux — enveloppez toujours avecfmt.Errorf("doing X: %w", err).log.Fatal(err)dans le code de bibliothèque appelleos.Exit(1), sautant le nettoyage différé — retournez les erreurs aux appelants.panic()est pour les bugs de programmeur, pas pour les conditions d'exécution — retournez les erreurs à la place.- Enveloppez les erreurs tierces avec
%v(pas%w) pour éviter de coupler les appelants au type d'erreur sous-jacent. - Style de message d'erreur : minuscules, pas de ponctuation :
fmt.Errorf("lecture du fichier de configuration : %w", err).
Voir references/errors-and-resilience.md pour les erreurs sentinelles, les types d'erreur personnalisés, errors.Join, les modèles de tentative, les circuit breakers et la dégradation gracieuse.
Essentiels de la Concurrence
Voir references/concurrency.md pour des modèles complets incluant errgroup, les pools de workers et le fan-out/fan-in. Règles de base :
- Utilisez le contexte pour l'annulation. Chaque goroutine doit vérifier
ctx.Done()— sans cela, il n'y a aucun moyen de signaler "arrêtez le travail". - Préférez
errgroupàsync.WaitGroupbrut. Regroupe l'attente + la collecte d'erreurs + l'annulation de contexte. Voirconcurrency.mdpour des exemples complets avecSetLimit. - Protégez l'état partagé — canaux pour la communication, mutex quand c'est plus simple. Commentez ce que chaque mutex protège.
- Chaque goroutine a besoin d'un chemin d'arrêt. Pas de vérification d'annulation = goroutine qui fuit = fuite mémoire.
- Un panic dans une goroutine tue tout le processus. Récupérez dans les goroutines générées, ou utilisez
sourcegraph/conc.
Primitives de synchronisation nouvelles :
sync.OnceValue / sync.OnceValues [Go 1.21+] — initialisation différée type-safe remplaçant sync.Once + variable de package :
var loadConfig = sync.OnceValues(func() ([]byte, error) {
return os.ReadFile("config.json") // s'exécute exactement une fois, sûr depuis n'importe quelle goroutine
})
data, err := loadConfig() // les appels suivants retournent le résultat mis en cache
sync.WaitGroup.Go [Go 1.25+] — combine Add(1) + go func + Done() :
var wg sync.WaitGroup
wg.Go(func() { process(1) })
wg.Go(func() { process(2) })
wg.Wait()
Dimensionnement des canaux : non bufferisé (0) pour la synchronisation, bufferisé (1) pour les signaux, bufferisé (N) pour un travail connu et limité.
Interfaces
// Acceptez des interfaces, retournez des types concrets
type UserStore interface {
GetUser(ctx context.Context, id string) (*User, error)
}
func NewService(store UserStore) *Service { return &Service{store: store} }
// Gardez les interfaces petites — 1-3 méthodes. Composez des plus grandes à partir de petites.
type ReadWriter interface { Reader; Writer }
// Définissez l'interface