« Back to Index

Go: Application Design

View original Gist on GitHub

Tags: #go #guide

README.md

Most information is copied verbatim from https://pace.dev/blog/2020/02/12/why-you-shouldnt-use-func-main-in-golang-by-mat-ryer.html

Also consider:

Call a run function from main to decouple the two and to enable easier testing:

const (
	// exitFail is the exit code if the program
	// fails.
	exitFail = 1
)

func main() {
	if err := run(os.Args, os.Stdout); err != nil {
		fmt.Fprintf(os.Stderr, "%s\n", err)
		os.Exit(exitFail)
	}
}

func run(args []string, stdout io.Writer) error {
	if len(args) < 2 {
		return errors.New("no names")
	}
	for _, name := range args[1:] {
		fmt.Fprintf(stdout, "Hi %s", name)
	}
	return nil
}

We can use flags inside the run function using the flag.NewFlagSet function and avoid using global flags altogether:

flags := flag.NewFlagSet(args[0], flag.ExitOnError)
var (
	verbose    = flags.Bool("v", false, "verbose logging")
	format     = flags.String("f", "Hi %s", "greeting format")
)
if err := flags.Parse(args[1:]); err != nil {
	return err
}

Test code can set any flags they like when calling run by passing in different args:

err := run([]string{"program", "-v", "-debug=true", "-another=2"})

This allows you to write tests covering different flag usage too.