Structure du Projet Go : Pratiques et Modèles
Structurez vos projets Go pour une évolutivité et une clarté optimales
Structurer un projet Go de manière efficace est fondamental pour la maintenabilité à long terme, la collaboration d’équipe et la scalabilité. Contrairement aux frameworks qui imposent des dispositions de répertoires rigides, Go privilégie la flexibilité – mais cette liberté s’accompagne de la responsabilité de choisir des modèles adaptés aux besoins spécifiques de votre projet.

Comprendre la philosophie de Go sur la structure de projet
La conception minimaliste de Go s’étend à l’organisation des projets. Le langage ne impose pas de structure spécifique, laissant aux développeurs le soin de prendre des décisions éclairées. Cette approche a conduit la communauté à développer plusieurs modèles éprouvés, allant des dispositions plates simples pour les petits projets à des architectures sophistiquées pour les systèmes d’entreprise.
Le principe clé est la simplicité d’abord, la complexité si nécessaire. De nombreux développeurs tombent dans le piège de la sur-ingénierie de leur structure initiale, créant des répertoires profondément imbriqués et des abstractions prématurées. Commencez par ce dont vous avez besoin aujourd’hui, et refactorisez au fur et à mesure que votre projet grandit.
Quand dois-je utiliser le répertoire internal/ par rapport à pkg/ ?
Le répertoire internal/ a un but spécifique dans la conception de Go : il contient des packages qui ne peuvent pas être importés par des projets externes. Le compilateur Go impose cette restriction, rendant internal/ parfait pour la logique d’application privée, les règles métier et les utilitaires non destinés à être réutilisés en dehors de votre projet.
Le répertoire pkg/, en revanche, indique que le code est destiné à une consommation externe. Ne placez du code ici que si vous construisez une bibliothèque ou des composants réutilisables que vous souhaitez que les autres importent. De nombreux projets n’ont pas besoin de pkg/ du tout – si votre code n’est pas consommé en externe, le garder à la racine ou dans internal/ est plus propre. Lors de la construction de bibliothèques réutilisables, envisagez d’utiliser les génériques Go pour créer des composants type-safe et réutilisables.
La structure standard d’un projet Go
Le modèle le plus largement reconnu est le golang-standards/project-layout, bien qu’il soit important de noter qu’il ne s’agit pas d’une norme officielle. Voici à quoi ressemble une structure typique :
monprojet/
├── cmd/
│ ├── api/
│ │ └── main.go
│ └── worker/
│ └── main.go
├── internal/
│ ├── auth/
│ ├── storage/
│ └── transport/
├── pkg/
│ ├── logger/
│ └── crypto/
├── api/
│ └── openapi.yaml
├── config/
│ └── config.yaml
├── scripts/
│ └── deploy.sh
├── go.mod
├── go.sum
└── README.md
Le répertoire cmd/
Le répertoire cmd/ contient les points d’entrée de votre application. Chaque sous-répertoire représente un binaire exécutable séparé. Par exemple, cmd/api/main.go construit votre serveur API, tandis que cmd/worker/main.go pourrait construire un processeur de tâches en arrière-plan.
Bonnes pratiques : Gardez vos fichiers main.go minimalistes – juste assez pour connecter les dépendances, charger la configuration et démarrer l’application. Toute logique substantielle appartient aux packages que main.go importe.
// cmd/api/main.go
package main
import (
"log"
"monprojet/internal/server"
"monprojet/internal/config"
)
func main() {
cfg, err := config.Load()
if err != nil {
log.Fatal(err)
}
srv := server.New(cfg)
if err := srv.Start(); err != nil {
log.Fatal(err)
}
}
Le répertoire internal/
C’est là que se trouve votre code d’application privé. Le compilateur Go empêche tout projet externe d’importer des packages dans internal/, ce qui en fait l’idéal pour :
- La logique métier et les modèles de domaine
- Les services d’application
- Les API et interfaces internes
- Les dépôts de base de données (pour choisir le bon ORM, consultez notre comparaison des ORMs Go pour PostgreSQL)
- La logique d’authentification et d’autorisation
Organisez internal/ par fonctionnalité ou domaine, et non par couche technique. Au lieu de internal/handlers/, internal/services/, internal/repositories/, préférez internal/user/, internal/order/, internal/payment/ où chaque package contient ses handlers, services et dépôts.
Dois-je commencer avec une structure de répertoire complexe ?
Absolument pas. Si vous construisez un petit outil ou un prototype, commencez par :
monprojet/
├── main.go
├── go.mod
└── go.sum
Au fur et à mesure que votre projet grandit et que vous identifiez des regroupements logiques, introduisez des répertoires. Vous pourriez ajouter un package db/ lorsque la logique de base de données devient substantielle, ou un package api/ lorsque les handlers HTTP se multiplient. Laissez la structure émerger naturellement plutôt que de l’imposer dès le départ.
Structures plates vs imbriquées : trouver l’équilibre
L’une des erreurs les plus courantes dans la structure des projets Go est le sur-imbrication. Go favorise les hiérarchies peu profondes – généralement un ou deux niveaux de profondeur. Un imbrication excessive augmente la charge cognitive et rend les imports fastidieux.
Quelles sont les erreurs les plus courantes ?
Sur-imbrication des répertoires : Évitez les structures comme internal/services/user/handlers/http/v1/. Cela crée une complexité de navigation inutile. Utilisez plutôt internal/user/handler.go.
Noms de packages génériques : Des noms comme utils, helpers, common ou base sont des indicateurs de code. Ils ne transmettent pas de fonctionnalité spécifique et deviennent souvent des dépôts pour du code non lié. Utilisez des noms descriptifs : validator, auth, storage, cache.
Dépendances circulaires : Lorsque le package A importe le package B, et B importe A, vous avez une dépendance circulaire – une erreur de compilation dans Go. Cela signale généralement une mauvaise séparation des préoccupations. Introduisez des interfaces ou extrayez les types partagés dans un package séparé.
Mélange des préoccupations : Gardez les handlers HTTP concentrés sur les préoccupations HTTP, les dépôts de base de données sur l’accès aux données, et la logique métier dans les packages de service. Placer les règles métier dans les handlers rend les tests difficiles et couple votre logique de domaine à HTTP.
Conception pilotée par le domaine et architecture hexagonale
Pour les applications plus grandes, en particulier les microservices, la conception pilotée par le domaine (DDD) avec l’architecture hexagonale offre une séparation claire des préoccupations.
Comment structurer un microservice suivant la conception pilotée par le domaine ?
L’architecture hexagonale organise le code en couches concentriques avec des dépendances s’écoulant vers l’intérieur :
internal/
├── domain/
│ └── user/
│ ├── entity.go # Modèles de domaine et objets de valeur
│ ├── repository.go # Interface de dépôt (port)
│ └── service.go # Services de domaine
├── application/
│ └── user/
│ ├── create_user.go # Cas d'utilisation : créer un utilisateur
│ ├── get_user.go # Cas d'utilisation : récupérer un utilisateur
│ └── service.go # Orchestration du service d'application
├── adapter/
│ ├── http/
│ │ └── user_handler.go # Adaptateur HTTP (points de terminaison REST)
│ ├── postgres/
│ │ └── user_repo.go # Adaptateur de base de données (implémente le port de dépôt)
│ └── redis/
│ └── cache.go # Adaptateur de cache
└── api/
└── http/
└── router.go # Configuration des routes et middleware
Couche de domaine (domain/): Logique métier centrale, entités, objets de valeur et interfaces de service de domaine. Cette couche n’a aucune dépendance envers les systèmes externes – pas d’importations HTTP, pas de base de données. Elle définit les interfaces de dépôt (ports) que les adaptateurs implémentent.
Couche d’application (application/): Cas d’utilisation qui orchestrent les objets de domaine. Chaque cas d’utilisation (par exemple, “créer un utilisateur”, “traiter un paiement”) est un fichier ou un package séparé. Cette couche coordonne les objets de domaine mais ne contient pas de règles métier elle-même.
Couche d’adaptation (adapter/): Implémente les interfaces définies par les couches internes. Les handlers HTTP convertissent les requêtes en objets de domaine, les dépôts de base de données implémentent la persistance, les files d’attente de messages gèrent la communication asynchrone. Cette couche contient tout le code spécifique au framework et à l’infrastructure.
Couche API (api/): Routes, middleware, DTOs (Data Transfer Objects), versioning d’API et spécifications OpenAPI.
Cette structure garantit que votre logique métier centrale reste testable et indépendante des frameworks, des bases de données ou des services externes. Vous pouvez remplacer PostgreSQL par MongoDB, ou REST par gRPC, sans toucher au code de domaine.
Modèles pratiques pour différents types de projets
Petit outil CLI
Pour les applications en ligne de commande, vous voudrez une structure qui prend en charge plusieurs commandes et sous-commandes. Envisagez d’utiliser des frameworks comme Cobra pour la structure de commande et Viper pour la gestion de la configuration. Notre guide sur la construction d’applications CLI en Go avec Cobra & Viper couvre ce modèle en détail.
monoutil/
├── main.go
├── command/
│ ├── root.go
│ └── version.go
├── go.mod
└── README.md
Service API REST
Lors de la construction d’APIs REST en Go, cette structure sépare clairement les préoccupations : les handlers gèrent les préoccupations HTTP, les services contiennent la logique métier et les dépôts gèrent l’accès aux données. Pour un guide complet couvrant les approches de la bibliothèque standard, les frameworks, l’authentification, les modèles de test et les meilleures pratiques prêtes pour la production, consultez notre guide complet pour la construction d’APIs REST en Go.
monapi/
├── cmd/
│ └── api/
│ └── main.go
├── internal/
│ ├── config/
│ ├── middleware/
│ ├── user/
│ │ ├── handler.go
│ │ ├── service.go
│ │ └── repository.go
│ └── product/
│ ├── handler.go
│ ├── service.go
│ └── repository.go
├── pkg/
│ └── httputil/
├── go.mod
└── README.md
Monorepo avec plusieurs services
monprojet/
├── cmd/
│ ├── api/
│ ├── worker/
│ └── scheduler/
├── internal/
│ ├── shared/ # Packages internes partagés
│ ├── api/ # Code spécifique à l'API
│ ├── worker/ # Code spécifique au worker
│ └── scheduler/ # Code spécifique au planificateur
├── pkg/ # Bibliothèques partagées
├── go.work # Fichier de l'espace de travail Go
└── README.md
Tests et Documentation
Placez les fichiers de test à côté du code qu’ils testent en utilisant le suffixe _test.go :
internal/
└── user/
├── service.go
├── service_test.go
├── repository.go
└── repository_test.go
Cette convention permet de garder les tests proches de l’implémentation, ce qui les rend faciles à trouver et à maintenir. Pour les tests d’intégration qui touchent plusieurs packages, créez un répertoire test/ séparé à la racine du projet. Pour des conseils complets sur la rédaction de tests unitaires efficaces, y compris les tests pilotés par table, les mocks, l’analyse de couverture et les bonnes pratiques, consultez notre guide sur la structure et les bonnes pratiques des tests unitaires en Go.
La documentation doit être placée dans :
README.md: Vue d’ensemble du projet, instructions d’installation, utilisation de basedocs/: Documentation détaillée, décisions architecturales, références APIapi/: Spécifications OpenAPI/Swagger, définitions protobuf
Pour les API REST, la génération et la fourniture de documentation OpenAPI avec Swagger sont essentielles pour la découvrabilité de l’API et l’expérience développeur. Notre guide sur l’ajout de Swagger à votre API Go couvre l’intégration avec les frameworks populaires et les bonnes pratiques.
Gestion des Dépendances avec les Modules Go
Chaque projet Go doit utiliser les Modules Go pour la gestion des dépendances. Pour une référence complète sur les commandes Go et la gestion des modules, consultez notre Cheat Sheet Go. Initialisez avec :
go mod init github.com/yourusername/myproject
Cela crée go.mod (dépendances et versions) et go.sum (sommets de contrôle pour la vérification). Conservez ces fichiers dans le contrôle de version pour des builds reproductibles.
Mettez à jour les dépendances régulièrement :
go get -u ./... # Mettre à jour toutes les dépendances
go mod tidy # Supprimer les dépendances inutilisées
go mod verify # Vérifier les sommets de contrôle
Principaux Points à Retenir
-
Commencez simplement, évoluez naturellement : Ne sur-ingénieriez pas votre structure initiale. Ajoutez des répertoires et des packages lorsque la complexité le demande.
-
Privilégiez les hiérarchies plates : Limitez l’imbrication à un ou deux niveaux. La structure de package plate de Go améliore la lisibilité.
-
Utilisez des noms de packages descriptifs : Évitez les noms génériques comme
utils. Nommez les packages en fonction de ce qu’ils font :auth,storage,validator. -
Séparez clairement les préoccupations : Gardez les gestionnaires concentrés sur HTTP, les dépôts sur l’accès aux données, et la logique métier dans les packages de service.
-
Utilisez
internal/pour la confidentialité : Utilisez-le pour le code qui ne doit pas être importé extérieurement. La plupart du code d’application appartient ici. -
Appliquez les modèles d’architecture lorsque nécessaire : Pour les systèmes complexes, l’Architecture Hexagonale et le DDD fournissent des limites claires et une testabilité.
-
Laissez-vous guider par Go : Suivez les idiomes de Go plutôt que d’importer des modèles d’autres langages. Go a sa propre philosophie sur la simplicité et l’organisation.
Liens Utiles
- Cheat Sheet Go
- Construction d’API REST en Go : Guide Complet
- Construction d’Applications CLI en Go avec Cobra & Viper
- Tests Unitaires en Go : Structure & Bonnes Pratiques
- Ajout de Swagger à Votre API Go
- Génériques en Go : Cas d’Utilisation et Modèles
- Comparaison des ORMs Go pour PostgreSQL : GORM vs Ent vs Bun vs sqlc
Autres Articles Associés
- Standard Go Project Layout - Directives de structure de projet communautaires
- Go Modules Reference - Documentation officielle des modules Go
- Hexagonal Architecture in Go - Framework d’architecture hexagonale de niveau entreprise
- Domain-Driven Design in Go - Implémentation DDD prête pour la production
- Go Project Structure Conventions - Modèles et exemples supplémentaires
- Effective Go - Guide officiel des bonnes pratiques Go