Go n’impose aucune structure de dossiers via un framework, ce qui est à la fois libérateur et déroutant. Ce guide présente un agencement pratique et idiomatique qui passe à l’échelle, du petit outil au vrai service, et explique les compromis derrière chaque choix.
Commencez par un module
Tout projet Go moderne est un module. Initialisez-en un avec un chemin de module, généralement l’URL de votre dépôt :
go mod init github.com/votrenom/greet
Cela crée un fichier go.mod qui enregistre le chemin du module, la version de
Go et la liste des dépendances. Quand vous ajoutez une dépendance, Go écrit aussi
un fichier go.sum avec des sommes de contrôle cryptographiques pour des builds
reproductibles. Versionnez les deux fichiers ; ne les éditez jamais à la main.
Restez à plat tant que possible
L’erreur la plus fréquente est de trop organiser trop tôt. Un petit programme tient très bien en quelques fichiers dans un seul package, à la racine du dépôt :
greet/
├── go.mod
├── go.sum
├── main.go
└── greeting.go
N’ajoutez des dossiers que lorsqu’un vrai besoin apparaît : un second binaire, ou du code à masquer aux importateurs. Une hiérarchie prématurée ne fait qu’allonger les chemins d’import à écrire.
Le package main et le point d’entrée
L’exécutable vit dans package main avec un point d’entrée func main. Gardez
main mince : lire la configuration, câbler les dépendances, puis déléguer la
vraie logique à un autre package.
// Package main est le point d’entrée de la commande greet.
package main
import (
"fmt"
"github.com/votrenom/greet/internal/greeting"
)
func main() {
fmt.Println(greeting.Message("Go"))
}
internal/ pour le code privé
Go applique une règle de structure via le compilateur : le code sous un dossier
internal/ ne peut être importé que par des packages situés sous le parent de
internal/. C’est la façon idiomatique de garder des détails d’implémentation
privés à votre module.
greet/
├── go.mod
├── main.go
├── internal/
│ └── greeting/
│ └── greeting.go
└── cmd/
└── greet/
└── main.go
cmd/ et pkg/ : le débat
Deux dossiers conventionnels sont très répandus, mais souvent mal employés.
cmd/contient un sous-dossier par binaire, chacun avec son propremain.go. Il se justifie dès que vous avez plus d’un exécutable. Avec un seul binaire, unmain.goà la racine est plus simple.pkg/est censé regrouper du code destiné à être importé par d’autres projets. Il est contesté : beaucoup de mainteneurs estiment qu’il ajoute un niveau de dossier sans signification pour le compilateur, contrairement àinternal/. Préférezinternal/pour le code privé, et ne recourez àpkg/que si vous publiez délibérément une bibliothèque réutilisable.
Le nommage
- Les noms de packages sont courts, en minuscules et en un seul mot :
greeting, pasgreetingUtils. Le nom du dossier doit correspondre à celui du package. - Évitez le bégaiement : une fonction du package
greetingdoit s’appelergreeting.Message, pasgreeting.GreetingMessage. - En Go idiomatique, pas de package fourre-tout
utilsouhelpers. Nommez les packages d’après ce qu’ils fournissent.
Pour la référence officielle sur les modules et la conception des packages, consultez la documentation sur go.dev, qui fait foi à mesure que la chaîne d’outils évolue.
Résumé
- Tout projet est un module : versionnez
go.modetgo.sum, sans les éditer à la main. - Restez à plat au début ; ajoutez
internal/etcmd/seulement en cas de besoin réel. - Préférez
internal/àpkg/pour la confidentialité, et nommez les packages d’après leur rôle.
Ensuite, affinez votre style avec le guide des conventions Go, ou suivez la roadmap développeur Go pour la vue d’ensemble.