« Back to Index

[Golang Design Patterns]

View original Gist on GitHub

Tags: #go #golang #design

Golang Design Patterns.md

types as abstraction layers

type Source string

func (src Source) CopyTo(dest string) error {
    return CopyFile(dest, string(src))
}

func main() {
    var from Source = "presentation.md"
    from.CopyTo("/tmp/backup")
}

dependency handling

There are three approaches…

  1. Pass dependencies as arguments to all functions requiring them.
  2. Package exported Init functions for configuring internal package level variables.
  3. Pass dependencies stored within a struct to all functions requiring them.

1.

func init() {
	// configure logger and other stuff
}
 
func main() {
	myOtherPackage.foo("x", configuredLoggerInstance)
    myOtherPackage.bar("y", configuredLoggerInstance)
    myOtherPackage.baz("z", configuredLoggerInstance)
}

2.

func init() {
	// configure logger and other stuff
}
 
func main() {
	myOtherPackage.Init(configuredLoggerInstance)
}

3.

type Deps struct{
    Dep *fooDep
    OtherDep *barDep
}

func Thing(deps *Deps) {
    // extract and use dependencies
}

Note: if you find you have functions that accept lots of arguments then you could also use variadic args to pass the logger and other generic dependencies, then loop over and type assert for them (but that’s a lot of extra code for not a lot of gain). if you do have lots of function args, then try to reduce them by splitting up the code into separate functions and also reduce generic args into a struct so it’s just one arg rather than multiple (e.g. a instrumentation struct).