This gets into a topic that is kinda controversial in go: dependency injection.
Unlike some other languages, we don't usually believe in complicated IOC containers, xml config, and reflection based tools for this kind of thing. I merely follow a few simple principles:
- Application packages and components should have all of their dependencies passed to them explicitly. Preferably as an interface type. If my
web
package needs a database connection, and an elastic client, it may have a function like Serve(addr string, db database.DB, client *elastic.Client)
where DB
is an interface type for my application's db.
-
The job of main
is essentially to read configuration, create all shared components, and pass them to the various components:
func main(){
var config = readConfig() //flags, json, whatever
var elastic = elastic.NewClient(config.whatever)
var db = database.New(config.Connectionstring)
//now start app components
web.Serve(config.Addr, db, elastic)
}
I find this pattern helps keep my packages separate yet inter-operable. I try to avoid package level variables for anything that needs to change from run to run.