Introduction : pourquoi le code review en Go n'est pas une simple formalité
\nLe code review n'est pas une procédure bureaucratique, mais un élément clé de la culture de développement. En Go, avec sa syntaxe concise et ses règles strictes, la revue devient souvent le premier filtre qui élimine les problèmes à un stade précoce. De nombreuses équipes qui passent à Golang constatent que les anciennes habitudes (par exemple, de Python ou PHP) ne fonctionnent pas : Go pardonne moins les erreurs liées aux types, mais exige une attention aux détails.
\nEn pratique, le code review en Go résout trois problèmes : la formation de l'équipe (les nouveaux s'intègrent plus rapidement au style de code), l'amélioration de la qualité (recherche de bugs et d'anti-patrons) et la cohérence du code (pour que le projet ne devienne pas un "patchwork"). Analysons ce qu'il faut regarder précisément et comment formuler les remarques.
\n\n1. Que vérifier en priorité : de la syntaxe aux erreurs
\nToute revue commence par les bases. En Go, il y a plusieurs "points chauds" à vérifier automatiquement ou manuellement.
\n\n1.1. Gestion des erreurs (error handling)
\nGo n'utilise pas d'exceptions — les erreurs sont retournées comme des valeurs. Un problème fréquent : le développeur ignore l'erreur retournée avec _. Cela n'est acceptable que dans de rares cas (par exemple, fmt.Println).
// Mauvais : l'erreur est ignorée\nresp, _ := http.Get("https://api.example.com/data")\n\n// Bon : l'erreur est traitée\nresp, err := http.Get("https://api.example.com/data")\nif err != nil {\n log.Printf("impossible d'obtenir les données : %v", err)\n return err\n}\ndefer resp.Body.Close()\nQue vérifier :
\n- \n
- Toutes les erreurs sont-elles traitées (pas seulement
_) ? \n deferest-il utilisé pour fermer les ressources (fichiers, connexions) ?- Les erreurs dans les goroutines ne sont-elles pas "avalées" ?
1.2. Nommage et style (Go idioms)
\nGo exige de la concision : camelCase pour les éléments privés, PascalCase pour les exportés. Évitez la "notation hongroise" et les noms longs.
// Mauvais\nfunc GetUserDataFromDatabase(userID int) (*UserData, error)\n\n// Bon\nfunc GetUser(id int) (*User, error)\nDrapeaux rouges :
\n- \n
- Noms de variables comme
temp,data,val(trop génériques). \n - Fonctions de plus de 30-40 lignes (à découper). \n
- Absence de commentaires pour les fonctions exportées (exigence de
golint). \n
1.3. Goroutines et synchronisation
\nC'est la partie la plus complexe. Les erreurs dans le code concurrent sont une source fréquente de bugs en production.
\n// Mauvais : course de données (data race)\nvar counter int\nfor i := 0; i < 100; i++ {\n go func() {\n counter++ // non sécurisé\n }()\n}\n\n// Bon : utilisation d'un mutex\nvar mu sync.Mutex\nvar counter int\nfor i := 0; i < 100; i++ {\n go func() {\n mu.Lock()\n counter++\n mu.Unlock()\n }()\n}\nQue vérifier :
\n- \n
- Y a-t-il
sync.Mutexouatomicpour les données partagées ? \n - A-t-on oublié de fermer le canal (
close(ch)) ? \n - Les goroutines ne "fuient-elles" pas (pas de
selectavec timeout) ? \n
2. Vérifications architecturales : des interfaces aux paquets
\nAprès la syntaxe de base, examinons la structure du code. Go favorise la composition plutôt que l'héritage.
\n\n2.1. Interfaces : petites et du côté du consommateur
\nEn Go, les interfaces sont implémentées implicitement. Une bonne interface contient 1 à 3 méthodes. Vérifiez si l'auteur n'essaie pas de créer une interface "globale".
\n// Mauvais : interface énorme\ntype Storage interface {\n Save(data []byte) error\n Load(id string) ([]byte, error)\n Delete(id string) error\n List() ([]string, error)\n Connect() error\