Clean Code en Go : principes et exemples pratiques
\n\nGo est un langage qui a été conçu dès le départ avec un accent sur la simplicité et la lisibilité. Cependant, même dans un langage aussi concis, on peut écrire un code confus et difficile à maintenir. Le concept de Clean Code (code propre) aide les développeurs à créer des programmes faciles à lire, tester et modifier. Dans cet article, nous allons analyser les principes clés du Clean Code appliqués à Go et examiner des exemples concrets.
\n\nPourquoi le code propre est-il important en Go ?
\n\nGo est souvent utilisé pour créer des microservices, des API et des systèmes à forte charge. Dans de tels projets, une équipe de développeurs travaille sur le code. Le code propre réduit la charge cognitive, accélère les revues de code et diminue le nombre de bogues. L'objectif principal est d'écrire du code compréhensible non seulement par l'auteur, mais aussi par tout autre développeur qui le verrait pour la première fois.
\n\n1. Nommage des variables et des fonctions
\n\nUn bon nommage est la base d'un code propre. En Go, on utilise des noms courts pour les variables locales et des noms plus longs pour les entités globales.
\n\nMauvais exemple
\npackage main\n\nfunc f(x int, y string) int {\n z, _ := strconv.Atoi(y)\n return x + z\n}\n\n\nBon exemple
\npackage main\n\nfunc addPriceToCount(count int, priceStr string) int {\n price, _ := strconv.Atoi(priceStr)\n return count + price\n}\n\n\nRègles de nommage en Go :
\n- \n
- Utilisez le
camelCasepour les variables non exportées (privées). \n - Utilisez le
PascalCasepour les fonctions et types exportés (publics). \n - Évitez les noms à une seule lettre, sauf pour les indices dans les boucles (
i,j). \n - N'incluez pas le type de la variable dans son nom (par exemple,
priceIntest mauvais,priceest bon). \n
2. Structure des paquets et des fichiers
\n\nEn Go, chaque paquet doit résoudre une seule tâche. Séparez le code par responsabilité. La structure standard d'un projet ressemble à ceci :
\n\nmyproject/\n├── cmd/\n│ └── server/\n│ └── main.go\n├── internal/\n│ ├── handler/\n│ ├── service/\n│ └── repository/\n├── pkg/\n│ └── utils/\n└── go.mod\n\n\nPrincipe : Le paquet internal protège le code des importations externes. Le paquet pkg contient des utilitaires réutilisables. Dans cmd se trouvent les points d'entrée (fichiers main.go).
Mauvais exemple
\n// Le paquet "utils" contient tout et n'importe quoi\npackage utils\n\nfunc Calculate(x, y int) int { ... }\nfunc SendEmail(to string) { ... }\nfunc ParseJSON(data []byte) { ... }\n\n\nBon exemple
\n// Le paquet "calculator" ne s'occupe que des calculs\npackage calculator\n\nfunc Add(a, b int) int { return a + b }\n\n\n3. Gestion des erreurs en Go
\n\nEn Go, il n'y a pas d'exceptions — les erreurs sont retournées comme des valeurs. Un code propre exige une gestion explicite et significative de chaque erreur.
\n\nMauvais exemple
\nfunc readFile(path string) string {\n data, _ := os.ReadFile(path) // on ignore l'erreur\n return string(data)\n}\n\n\nBon exemple
\nfunc readFile(path string) (string, error) {\n data, err := os.ReadFile(path)\n if err != nil {\n return "", fmt.Errorf("read file %s: %w", path, err)\n }\n return string(data), nil\n}\n\n\nConseils pour la gestion des erreurs :
\n- \n
- N'ignorez jamais les erreurs avec
_. \n - Ajoutez toujours du contexte :
fmt.Errorf("operation: %w", err). \n - Utilisez des types d'erreurs personnalisés pour différentes situations. \n
- N'utilisez pas
panicpour les erreurs courantes — uniquement pour des situations truly exceptional. \n
4. Fonctions : longueur et responsabilité
\n\nUne fonction