Please find below an opinionated list of de-facto standard libraries. Needless to say, there are plenty alternatives for logging, HTTP, etc. Please refer to https://github.com/avelino/awesome-go for a comprehensive list of awesome Go projects. However, the projects listed here have been chosen deliberately because they provide more features or are significantly faster than comparable projects.
- AlecAivazis/survey: library for building interactive prompts
- jessevdk/go-flags: command line option parser with support for long flags, environment variables, etc.
- kballard/go-shellquote: shell-like word splitting/joining
- spf13/cobra: a commander for modern Go CLI interactions
- spf13/viper: configuration library; supports environment variables, ini, Java properties, json, toml, yaml, etc.
- google/wire: Google's compile-time dependency injection framework
- spf13/afero: filesystem abstraction; supports different provides: memory, native, readonly, HTTP, SFTP, etc.
- rs/zerolog: zero allocation JSON logger
- abc-inc/browser: opens URLs or files in the most appropriate browser or assigned application
- abc-inc/goava: Google's Guava ported to Go; provides case format, char matcher, stopwatch, escapers, etc.
- dustin/go-humanize: formatters for units to human friendly sizes
- mitchellh/mapstructure: decoding generic map values into native Go structures and vice versa.
- abc-inc/terminus: IP subnet address calculator
- c-robinson/iplib: working with IP addresses and networks
- GeertJohan/go.rice: makes working with resources such as html, js, images, templates, etc very easy
- shurcooL/vfsgen: generates Go code that statically implements a FileSystem; similar to go.rice but less options
- shirou/gopsutil: cross-platform library for process and system monitoring
- google/go-cmp: comparing Go values in tests (deep equality)
- jonboulle/clockwork: a fake clock for simulating time
- stretchr/testify: toolkit with common assertions and mocks that plays nicely with the standard library
- google/uuid: UUIDs based on RFC 4122 and DCE 1.1
- julienschmidt/httprouter: high performance HTTP request router on top of net/http
- Avoid the
elseclause. Reduce the amount of indentation as much as possible. - Comments should be proper sentences, and the first line should start with the name of the struct, function, etc.
New<Something>()should return pointers to avoid re-allocation.- Prefer exporting variables over getters/setter.
If really needed, omit the
Getprefix e.g., useCustomer()for reading andSetCustomer()for writing. - Use short expressive package names - no
util, preferdboverdatabase. - Use short descriptive variable names - prefer
countandcustovercounterandcustomer(cwould be ambiguous). - Variable names should be shorter if they have limited scope and longer if used globally.
- Do not
panic()unless you really have to -log.Fatal()is a good alternative.
- Enums are ordinary integers but can be enriched with additional methods.
The idiomatic way of adding a string representation is the following:
type State int // declare a new type const ( New State = iota // use iota (reverse abbreviation of 'ASCII to int') Progress Done ) // String returns the State string representation. func (s State) String() string { return []string{"New", "Progress", "Done"}[s] }
- Typically, the HTTP server starts in sub milliseconds.
However, if it is necessary to log the exact time when the server become healthy, the following snippet can be used:
url := "https://" + addr.String() + "/health" if _, err = http.Get(url); err == nil { log.Fatal().Msgf("Cannot bind %s", addr) } done := make(chan bool) log.Info().Msg("Starting server...") go func() { log.Err(server.ListenAndServe()).Send() }() log.Debug().Msgf("Checking health on %s", url) for i := 1; i <= 100; i++ { res, err := http.Get(url) if err == nil { if res.StatusCode != http.StatusOK { break } log.Info().Msgf("Server started at %s after %d µs", server.Addr, (time.Now().Sub(start).Microseconds())) <-done } time.Sleep(time.Duration(i) * time.Millisecond) } log.Fatal().Msg("Server failed to start")
- Slices and arrays are reference types and modification of the value of a slice of a slice of a ... modifies the backing array.
go get -t -vshould be used to download required dependencies.go mod downloaddownloads all dependencies listed ingo.mod, regardless whether they are required or not.go mod tidycleans upgo.modandgo.sumafter adding new dependencies.
- Use the
goimportstool, which appliesgofmtstyles and sorts imports.
- Under some circumstances e.g., when using
netor theuserpackage, the linker incorporates libraries from the host. In order to force static linking, the easiest way is to setCGO_ENABLED=0.
- Avoid
init()functions, because they make testing more complicated. - Put test code into the same directory, but use
package <pkg>_test.
go test -coverprofile "${TEMP_DIR}/reports/coverage.out" ./... && \
go tool cover -html "${TEMP_DIR}/reports/coverage.out" -o "${TEMP_DIR}/reports/coverage.html"This is the de-facto standard tool containing 48 Linters. It is available as Docker container as well as binary, which can be launched as follows:
golangci-lint run ./...Check https://golangci-lint.run/ for installation instructions and configuration options.
GitHub provides Super-Linter, which can be downloaded and executed everywhere. It contains dozens of different linters for many programming languages, including Go. If you don't mind pulling a 4 GB Docker image, you can do the following:
docker run --rm \
-e FILTER_REGEX_EXCLUDE="" \ # if required
-e RUN_LOCAL=true \
-v "${PWD}:/tmp/lint" \
github/super-linterFurther information can be found at https://github.com/github/super-linter.
In general, debug information can be stripped from binaries to minimize their size.
Moreover, Go compiles absolute paths into the binary, which can be stripped using -trimpath.
export CGO_ENABLED=0
go build -ldflags "-s -w" -o <binary> -trimpath ./...If you want to introduce a constant such as build version, Git tag or something similar, you can use a linker flag.
The -X flag takes an argument in the form package.ExportedVariable=value (and the flag can be repeated multiple times) e.g.:
go build -ldflags "-X 'main.Version=v1.2'" ./...GUI applications on Windows launch a console. If this is not desirable, it can be suppressed using the following flag:
go build -ldflags "-H=windowsgui" ./...Here is a template Makefile to copy for convenience:
BUILD_DIR=bin
TEMP_DIR=tmp
export CGO_ENABLED=0
all: clean build
build: test
mkdir -p "${BUILD_DIR}"
go build -o "${BUILD_DIR}/" ./...
check:
golangci-lint run ./...
clean:
rm -fr "${BUILD_DIR}" "${TEMP_DIR}"
test:
mkdir -p tmp/reports && \
go test -coverprofile "${TEMP_DIR}/reports/coverage.out" ./...
go tool cover -html "${TEMP_DIR}/reports/coverage.out" -o "${TEMP_DIR}/reports/coverage.html"
.PHONY: all build check clean test