[TIPS] Avoid Using init() in Go Unless Necessary
By JoeVu, at: Sept. 11, 2024, 11:08 a.m.
Avoid Using init()
in Go Unless Necessary
The init()
function in Go is a special function that gets executed automatically before the main()
function, and even before any other code in the package. While it can be useful, overusing it can make your code harder to follow and maintain. Here’s why you should avoid using init()
unless absolutely necessary.
Why init()
Can Be Problematic
-
Hidden Logic: Since
init()
is executed automatically, it can introduce hidden behavior that isn't obvious from the code's main flow. This can make debugging and understanding the code more challenging, especially for larger projects.
-
Order of Execution: Go doesn't guarantee the order of execution of
init()
functions across different packages. If multiple packages haveinit()
functions, it can lead to unpredictable behavior, making the program harder to reason about.
-
Complicated Testing: If important setup logic is hidden inside
init()
, it can be difficult to mock or bypass during testing. This can lead to tightly coupled tests that are harder to write and maintain.
When to Use init()
Despite the potential downsides, there are legitimate use cases for init()
:
-
Package-Level Configuration: If a package needs to initialize some state or configuration before being used (e.g., setting up a global logger),
init()
can be useful. However, make sure this setup is essential and cannot be handled inmain()
or elsewhere.
-
Registering Components: Some packages, especially those that provide extensible functionality like plugins or middleware, use
init()
to register components. This is acceptable, but try to document this behavior clearly to avoid confusion.
Example of init()
Use
package main
import (
"log"
"os"
)
func init() {
// Set up a global logger
log.SetOutput(os.Stdout)
log.Println("Logger initialized")
}
func main() {
log.Println("This is the main function")
}
In this example, init()
is used to set up a global logger before the main()
function runs. While this is a valid use case, consider whether this setup could be done explicitly in main()
for better clarity.
Further reading: https://www.digitalocean.com/community/tutorials/understanding-init-in-go