Le Go idiomatique est remarquablement uniforme, parce que la communauté s’est mise d’accord sur des conventions et laisse les outils les faire respecter. Ce guide couvre celles qui comptent le plus au quotidien, pour que votre code se lise comme celui des autres.
Laissez gofmt décider du formatage
En Go, le formatage n’est pas une affaire de goût. gofmt (via go fmt)
réécrit votre code dans l’unique style canonique : tabulations pour
l’indentation, champs de struct alignés, imports triés. Configurez votre éditeur
pour l’exécuter à l’enregistrement, et ne débattez plus jamais des accolades ni
des espaces.
Nommage : MixedCaps et noms courts
Go utilise MixedCaps ou mixedCaps, jamais snake_case, pour les noms
composés.
const MaxRetries = 3
type HTTPClient struct {
baseURL string
timeout int
}
Préférez des noms courts, surtout pour les variables locales à courte durée de
vie : i pour un index de boucle, r pour un reader, buf pour un tampon. Un
nom long ne se justifie que sur une grande portée. Gardez les sigles tout en
majuscules : HTTPClient et userID, pas HttpClient ni userId.
Exporté ou non exporté
La visibilité dépend de la première lettre, pas d’un mot-clé. Un identifiant qui commence par une majuscule est exporté (visible des autres packages) ; en minuscule, il reste privé à son package.
// Message est exportée : les autres packages peuvent l’appeler.
func Message(name string) string {
return "Bonjour, " + name
}
// normalize n’est pas exportée : utilisable seulement dans ce package.
func normalize(name string) string {
return name
}
Exposez la plus petite surface utile. Tout ce qui est public est une promesse de compatibilité que vous devrez tenir.
Les commentaires de documentation
Un commentaire de doc est un commentaire ordinaire placé juste au-dessus d’une
déclaration ; par convention, il commence par le nom documenté. go doc et
pkg.go.dev en font automatiquement de la documentation.
// Message renvoie une salutation pour name. Elle ne renvoie jamais de chaîne vide.
func Message(name string) string {
return "Bonjour, " + name
}
Le style de gestion des erreurs
Renvoyez l’erreur en dernière valeur, vérifiez-la immédiatement, et ajoutez du
contexte en la remontant avec %w pour que l’appelant puisse toujours inspecter
l’originale.
data, err := os.ReadFile(path)
if err != nil {
return fmt.Errorf("lecture config %s : %w", path, err)
}
N’ignorez pas une erreur avec _ sauf intention réelle, et traitez-la là où vous
avez le contexte pour en faire quelque chose d’utile.
Accepter des interfaces, renvoyer des structs
Un principe très répandu : une fonction devrait accepter des interfaces (pour que l’appelant passe n’importe quelle implémentation) mais renvoyer des types concrets (pour offrir une API complète et explorable).
// Accepte n’importe quel io.Reader ; renvoie un *Scanner concret.
func NewScanner(r io.Reader) *Scanner {
return &Scanner{source: r}
}
Vos entrées restent souples et vos sorties honnêtes. Définissez les interfaces là où elles sont consommées, pas là où le type concret est défini.
Le nommage des packages
Les noms de packages sont courts, en minuscules, en un seul mot, et décrivent ce
qu’ils fournissent, pas ce qu’ils contiennent : time, http, greeting.
Évitez les fourre-tout utils ou common, et évitez le bégaiement :
greeting.Message, pas greeting.GreetingMessage.
Résumé
- Confiez le formatage à
gofmtet imposez-le en CI. - Utilisez MixedCaps et des noms courts ; gardez les sigles en majuscules.
- Contrôlez la visibilité par la casse, documentez les noms exportés, et ajoutez
du contexte aux erreurs avec
%w.
Mettez tout cela en pratique avec une bonne structure de projet Go, et voyez le parcours complet dans la roadmap développeur Go.