Conteneur d'injection de dépendances pour Go (Golang) : Wire, Dig et Uber FX
\n\nL'injection de dépendances (DI) est un modèle de conception dans lequel un objet reçoit ses dépendances de l'extérieur, plutôt que de les créer lui-même. En Go (Golang), la DI est particulièrement utile pour créer un code modulaire, testable et évolutif. Les outils de DI les plus populaires pour Go sont Google Wire, Uber Dig et Uber FX. Dans cet article, nous examinerons chacun d'eux, leurs caractéristiques et des exemples d'utilisation.
\n\nPourquoi l'injection de dépendances en Go ?
\nGo est un langage typé statiquement avec un passage explicite de paramètres. Sans DI, les développeurs créent souvent des variables globales ou des fabriques, ce qui complique les tests et la maintenance. Les conteneurs DI résolvent ces problèmes :
\n- \n
- Faible couplage — les composants dépendent d'interfaces, et non d'implémentations concrètes. \n
- Testabilité — il est facile de remplacer les dépendances par des mocks. \n
- Simplification de la configuration — le conteneur résout automatiquement le graphe des dépendances. \n
Google Wire — génération de code à la compilation
\nWire de Google n'est pas un conteneur d'exécution, mais un générateur de code. Il analyse les fonctions constructeurs et génère le code pour lier les dépendances à l'étape de compilation. Cela offre une charge nulle pendant l'exécution et une détection précoce des erreurs.
\n\nInstallation de Wire
\ngo install github.com/google/wire/cmd/wire@latest\n\nExemple d'utilisation de Wire
\nSupposons que nous ayons un service qui dépend d'une base de données et d'un journaliseur :
\n// main.go\npackage main\n\nimport "fmt"\n\ntype Logger struct{}\n\nfunc NewLogger() Logger { return Logger{} }\n\nfunc (l Logger) Log(msg string) { fmt.Println(msg) }\n\ntype Database struct {\n logger Logger\n}\n\nfunc NewDatabase(logger Logger) Database {\n return Database{logger: logger}\n}\n\ntype Service struct {\n db Database\n log Logger\n}\n\nfunc NewService(db Database, log Logger) Service {\n return Service{db: db, log: log}\n}\nCréons maintenant un fichier wire.go avec les instructions pour Wire :
// wire.go\n//go:build wireinject\n// +build wireinject\n\npackage main\n\nimport "github.com/google/wire"\n\nfunc InitializeService() Service {\n wire.Build(NewLogger, NewDatabase, NewService)\n return Service{}\n}\nLançons la génération :
\nwire\nWire créera un fichier wire_gen.go avec le code d'initialisation prêt :
// wire_gen.go\n// Code generated by Wire. DO NOT EDIT.\n\npackage main\n\nfunc InitializeService() Service {\n logger := NewLogger()\n database := NewDatabase(logger)\n service := NewService(database, logger)\n return service\n}\nAvantages de Wire :
\n- \n
- Erreurs à l'étape de compilation. \n
- Pas de reflection, haute performance. \n
- Code simple et prévisible. \n
Inconvénients de Wire :
\n- \n
- Nécessite une étape de génération séparée. \n
- Difficile à utiliser avec des dépendances dynamiques. \n
Uber Dig — conteneur d'exécution avec reflection
\nDig d'Uber est un conteneur fonctionnant pendant l'exécution. Il utilise la reflection pour analyser les types et résoudre automatiquement les dépendances. Dig fournit une API simple pour enregistrer des constructeurs et extraire des objets.
\n\nInstallation de Dig
\ngo get go.uber.org/dig\n\nExemple d'utilisation de Dig
\npackage main\n\nimport (\n "fmt"\n "go.uber.org/dig"\n)\n\ntype Config struct {\n Port int\n}\n\nfunc NewConfig() *Config {\n return &Config{Port: 8080}\n}\n\ntype Server struct {\n config *Config\n}\n\nfunc NewServer(c *Config) *Server {\n return &Server{config: c}\n}\n\nfunc (s *Server) Start() {\n fmt.Print Aussi dans la bibliothèque
log — Journalisation pour Rust
Limitation de débit en Rust : bibliothèques governor, leaky-bucket et middleware pour serveurs web
Travailler avec XML en Go (Golang) : la bibliothèque standard encoding/xml
Travailler avec CSV en Kotlin : bibliothèques, analyse et écriture de données
golangci-lint pour Go : guide complet avec exemples