Comment travailler avec la configuration en Go : du chaos à l'ordre
\n\nTout développeur Go se retrouve tôt ou tard confronté à la question : « Comment stocker et charger correctement les paramètres de l'application ? » Le sujet est si populaire que sur Stack Overflow, la question correspondante a recueilli des milliers de vues et des dizaines de réponses. Et ce n'est pas un hasard : la façon dont vous organisez la configuration détermine la facilité avec laquelle vous pourrez déployer l'application, la tester et l'adapter à différents environnements.
\n\nDans cet article, nous allons analyser les questions les plus fréquentes sur la configuration en Go, examiner des exemples de code réels et élaborer une approche qui vous évitera des maux de tête lors du déploiement.
\n\nPourquoi la configuration est-elle un problème ?
\n\nImaginez : vous avez écrit une excellente application. Elle fonctionne en local, les tests passent, vos collègues applaudissent. Mais quand il s'agit de déployer sur staging et production, l'enfer commence. Différentes bases de données, différentes clés API, différents niveaux de journalisation. Et là, vous réalisez que coder en dur les paramètres est une mauvaise idée.
\n\nGo propose des outils flexibles pour travailler avec la configuration, mais les débutants commettent souvent les mêmes erreurs : utiliser des variables globales, confondre les formats, oublier les variables d'environnement. Voyons comment bien faire.
\n\nQuestion fréquente n°1 : JSON ou YAML ?
\n\nLa toute première question qui se pose : « Dans quel format stocker la configuration ? » La réponse dépend du contexte, mais il existe des recommandations générales.
\n\nJSON — simple et natif
\n\nGo sait travailler nativement avec JSON via le package encoding/json. C'est un excellent choix pour les microservices et les passerelles API.
// config.json\n{\n "port": 8080,\n "database": {\n "host": "localhost",\n "port": 5432,\n "name": "myapp"\n },\n "log_level": "info"\n}\n\n// main.go\npackage main\n\nimport (\n "encoding/json"\n "fmt"\n "os"\n)\n\ntype Config struct {\n Port int `json:"port"`\n Database Database `json:"database"`\n LogLevel string `json:"log_level"`\n}\n\ntype Database struct {\n Host string `json:"host"`\n Port int `json:"port"`\n Name string `json:"name"`\n}\n\nfunc main() {\n file, _ := os.Open("config.json")\n defer file.Close()\n \n var config Config\n json.NewDecoder(file).Decode(&config)\n \n fmt.Printf("Démarrage du serveur sur le port %d\\n", config.Port)\n fmt.Printf("Connexion à la base de données %s:%d/%s\\n", \n config.Database.Host, \n config.Database.Port, \n config.Database.Name)\n}\n\nYAML — la lisibilité avant tout
\n\nPour les configurations complexes avec de nombreux champs imbriqués, YAML est plus pratique. Cependant, une bibliothèque tierce sera nécessaire — par exemple, gopkg.in/yaml.v3.
// config.yaml\nserver:\n port: 8080\n timeout: 30s\n\ndatabase:\n host: localhost\n port: 5432\n name: myapp\n\nlogging:\n level: info\n format: json\n\npackage main\n\nimport (\n "fmt"\n "gopkg.in/yaml.v3"\n "os"\n)\n\ntype Config struct {\n Server ServerConfig `yaml:"server"`\n Database DatabaseConfig `yaml:"database"`\n Logging LoggingConfig `yaml:"logging"`\n}\n\nfunc main() {\n data, _ := os.ReadFile("config.yaml")\n var config Config\n yaml.Unmarshal(data, &config)\n \n fmt.Printf("Délai d'attente du serveur : %s\\n", config.Server.Timeout)\n}\n\nConseil : Utilisez YAML pour les configurations qui seront lues par des humains, et JSON pour les échanges de données entre machines.
\n\nQuestion fréquente n°2 : Et les variables d'environnement ?
\n\nDans le développement moderne (notamment avec les conteneurs et Kubernetes), les variables d'environnement sont devenues la norme de facto. Elles permettent de modifier facilement les paramètres sans reconstruire l'application.
\n\nGo prend en charge les variables d'environnement via os.Getenv() et os.LookupEnv(). Mais analyser manuellement chaque variable est fastidieux et chronophage.