Cómo trabajar con la configuración en Go: del caos al orden
\n\nTodo desarrollador de Go, tarde o temprano, se enfrenta a la pregunta: «¿Cómo almacenar y cargar correctamente los ajustes de la aplicación?» El tema es tan popular que en Stack Overflow la pregunta correspondiente ha acumulado miles de visitas y docenas de respuestas. Y no es casualidad: de cómo organices la configuración depende lo fácil que será desplegar la aplicación, probarla y adaptarla a diferentes entornos.
\n\nEn este artículo analizaremos las preguntas más frecuentes sobre la configuración en Go, veremos ejemplos reales de código y desarrollaremos un enfoque que te salvará de dolores de cabeza en el despliegue.
\n\n¿Por qué la configuración es un dolor?
\n\nImagina: has escrito una aplicación excelente. Funciona localmente, las pruebas pasan, los colegas aplauden. Pero cuando llega el momento de desplegar en staging y producción, comienza el infierno. Diferentes bases de datos, diferentes claves API, diferentes niveles de registro. Y entonces te das cuenta de que hardcodear los ajustes es una mala idea.
\n\nGo ofrece herramientas flexibles para trabajar con la configuración, pero los principiantes suelen cometer los mismos errores: usar variables globales, confundir formatos, olvidar las variables de entorno. Aclaremos cómo hacerlo correctamente.
\n\nPregunta frecuente n.º 1: ¿JSON o YAML?
\n\nLa primera pregunta que surge es: «¿En qué formato almacenar la configuración?» La respuesta depende del contexto, pero hay recomendaciones generales.
\n\nJSON — simple y nativo
\n\nGo puede trabajar con JSON de forma nativa a través del paquete encoding/json. Es una excelente opción para microservicios y puertas de enlace 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("Iniciando servidor en el puerto %d\\n", config.Port)\n fmt.Printf("Conectando a la BD %s:%d/%s\\n", \n config.Database.Host, \n config.Database.Port, \n config.Database.Name)\n}\n\nYAML — la legibilidad ante todo
\n\nPara configuraciones complejas con múltiples campos anidados, YAML es más conveniente. Eso sí, requerirá una biblioteca externa, por ejemplo, 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("Tiempo de espera del servidor: %s\\n", config.Server.Timeout)\n}\n\nConsejo: Usa YAML para configuraciones que leerán personas, y JSON para el intercambio de datos entre máquinas.
\n\nPregunta frecuente n.º 2: ¿Y qué pasa con las variables de entorno?
\n\nEn el desarrollo moderno (especialmente en contenedores y Kubernetes), las variables de entorno se han convertido en el estándar de facto. Permiten cambiar fácilmente los ajustes sin recompilar la aplicación.
\n\nGo admite el trabajo con variables de entorno a través de os.Getenv() y os.LookupEnv(). Pero analizar manualmente cada variable es tedioso y