A global variable can be accessed from multiple functions or locations, but that convenience creates hidden coupling: any function in the package can alter it, making dependent unit tests harder to isolate. section 2.3.2
var db *sql.DB
func init() {
dataSourceName :=
os.Getenv("MYSQL_DATA_SOURCE_NAME") #1
d, err := sql.Open("mysql", dataSourceName)
if err != nil {
log.Panic(err)
}
err = d.Ping()
if err != nil {
log.Panic(err)
}
db = d #2
}
This database example stores a connection pool in the package-level variable db after init performs connection setup and panics on failure. section 2.3.2
Using a global database connection from init is often a mistake. init cannot return an error, so it must panic; it also runs before tests, even when a test does not need the connection. A plain createClient function instead returns the error to its caller, which can choose retries, fallbacks, or termination. section 2.3.2
func createClient(dsn string) (*sql.DB, error) { #1
db, err := sql.Open("mysql", dsn)
if err != nil {
return nil, err #2
}
if err = db.Ping(); err != nil {
return nil, err
}
return db, nil
}
This replacement encapsulates database creation in a callable function and returns failures instead of assigning the connection to global state. section 2.3.2
Preventing a benchmark from disappearing
A global variable has a narrow, deliberate use in benchmarks. Store each function result in a local variable during the loop, then assign the final value to a global variable after the loop. The local assignment limits per-iteration overhead, while the global assignment gives the compiler an observable result and prevents inlining or dead-code elimination from making the benchmark effectively empty. section 11.8.3











