Injection de Dépendances en Go : guide pratique

Formateur Python en ligne pour débutants

Apprenez Python facilement sans surcharge théorique. Résolvez des tâches pratiques avec vérification automatique et écrivez du code directement dans le navigateur.

Start Course

Injection de Dépendances en Go : de la théorie au code réel

\n\n

L'Injection de Dépendances (DI) est l'un des modèles de conception clés qui aide à créer un code faiblement couplé, testable et maintenable. En Go, avec sa philosophie de simplicité et de clarté, l'injection de dépendances peut être implémentée manuellement ou à l'aide de bibliothèques. Dans cet article, nous allons voir comment appliquer correctement la DI en Golang en pratique, examiner l'approche manuelle ainsi que la bibliothèque populaire google/wire.

\n\n

1. Pourquoi l'Injection de Dépendances en Go est-elle nécessaire ?

\n\n

Imaginez que vous écrivez un service HTTP pour gérer les utilisateurs. Sans DI, votre code pourrait ressembler à ceci :

\n\n
package main\n\nimport "database/sql"\n\ntype UserHandler struct {\n    db *sql.DB\n}\n\nfunc NewUserHandler() *UserHandler {\n    db, _ := sql.Open("postgres", "conn_string")\n    return &UserHandler{db: db}\n}\n\nfunc (h *UserHandler) GetUser(id int) (*User, error) {\n    // travail avec h.db\n}\n
\n\n

Les problèmes sont évidents :

\n
    \n
  • Couplage fort — le handler crée lui-même la base de données.
  • \n
  • Difficulté de test — impossible de remplacer db par un mock.
  • \n
  • Violation du principe de Responsabilité Unique — le handler est responsable à la fois de la création des dépendances et de la logique métier.
  • \n
\n\n

La DI résout ces problèmes en transmettant les dépendances de l'extérieur :

\n\n
type UserHandler struct {\n    db Database\n}\n\nfunc NewUserHandler(db Database) *UserHandler {\n    return &UserHandler{db: db}\n}\n\n// Maintenant, on peut facilement remplacer par un mock\ntype Database interface {\n    GetUser(id int) (*User, error)\n}\n
\n\n

2. Injection manuelle de dépendances : simplicité et contrôle

\n\n

Go ne nécessite pas de frameworks pour la DI. La manière la plus simple et transparente est de passer les dépendances via les constructeurs. Prenons l'exemple d'une application à trois niveaux : handler → service → repository.

\n\n
// repository/user.go\ntype UserRepository interface {\n    FindByID(id int) (*User, error)\n}\n\ntype postgresUserRepo struct {\n    db *sql.DB\n}\n\nfunc NewPostgresUserRepo(db *sql.DB) *postgresUserRepo {\n    return &postgresUserRepo{db: db}\n}\n\nfunc (r *postgresUserRepo) FindByID(id int) (*User, error) {\n    // implémentation\n}\n
\n\n
// service/user.go\ntype UserService struct {\n    repo UserRepository\n}\n\nfunc NewUserService(repo UserRepository) *UserService {\n    return &UserService{repo: repo}\n}\n\nfunc (s *UserService) GetUser(id int) (*User, error) {\n    return s.repo.FindByID(id)\n}\n
\n\n
// handler/user.go\ntype UserHandler struct {\n    svc *UserService\n}\n\nfunc NewUserHandler(svc *UserService) *UserHandler {\n    return &UserHandler{svc: svc}\n}\n\nfunc (h *UserHandler) HandleGetUser(w http.ResponseWriter, r *http.Request) {\n    // travail avec h.svc\n}\n
\n\n

Maintenant, l'assemblage de l'application se fait dans main.go :

\n\n
func main() {\n    db, _ := sql.Open("postgres", os.Getenv("DB_URL"))\n    \n    repo := NewPostgresUserRepo(db)\n    svc := NewUserService(repo)\n    handler := NewUserHandler(svc)\n    \n    http.HandleFunc("/user", handler.HandleGetUser)\n    log.Fatal(http.ListenAndServe(":8080", nil))\n}\n
\n\n

Avantages de la DI manuelle :

\n
    \n
  • Transparence totale — vous voyez toutes les dépendances explicitement.
  • \n
  • Pas de magie ni de dépendances superflues dans le projet.
  • \n
  • Idéal pour les petits et moyens projets.
  • \n
\n\n

Inconvénients : lorsque l'application grandit (50+ composants), l'assemblage manuel devient lourd et sujet aux erreurs.

\n\n

3. Automatisation avec google/wire

\n\n

La bibliothèque github.com/google/wire génère du code pour l'assemblage des dépendances. Ce n'est pas un conteneur d'exécution — c'est un générateur de code, ce qui correspond parfaitement à la philosophie de Go.

\n\n

Installation :

\n
go get github.com/google/wir                

Blogs

Book Recommendations