I found a very complete post about the tooling of the go cli here https://www.alexedwards.net/blog/an-overview-of-go-tooling. If you want to have more details I advise you to check it out. I am going to make a reminder of the comands that I use and recommend the most.
I wrote this post at the version: 1.18.5
Update from the blog I quoted above, go get is now deprecated to install packages locally, https://go.dev/doc/go-get-install-deprecation.
Prefer to use go install :
go install github.com/golangci/golangci-lint/cmd/golangci-lint
golangci-lint -v
In this part, I will show you how to optimize the size of your binary easily.
In this case, I will use a simple example:
package main
import "fmt"
func main() {
fmt.Println("optimize binary")
}
I get these 2 results when I compile my application:
-rwxr-xr-x 1 ... ... 1762620 août 5 15:08 app1
-rwxr-xr-x 1 ... ... 1183744 août 5 15:09 app2
As you can see app2 is ~30% lighter!
app1 is built using:
go build -o app1 .
app2 is built using optimizations:
CGO_ENABLED=0 go build -a -ldflags "-s -w" -o app2 .
CGO_ENABLED=0, you got a staticaly-linked binary that will work without any external dependencies (you can use lighter docker images like scratch).
-ldflags “-s -w”, you can use the -s and -w linker flags to strip the debugging information:
$ go tool link
...
-s disable symbol table
...
-w disable DWARF generation
...
When handling goroutines quite a bit, feel free to run the tests with the Go race detector enabled, which can help detect some of the data races that can occur in real life. For example:
go test -race ./...
Another interesting point is code coverage. You can enable coverage analysis when running tests by using the -coverprofile option. This will generate a coverage report that can be used by Sonarqube or others, like this:
go test -coverprofile=profile.out ./...
You can also view it in your web browser to see the coverage per file in detail, using the go tool cover -html command as follows:
go tool cover -html=profile.out
Before making any changes to your code, I recommend that you run the following commands to update your dependencies and get them in a tidy state:
go get -u ./...
go mod tidy
The go get -u ./… command will update all dependencies at once for a given module, just run the following from the root directory of your module.
The go mod tidy command will remove all unused dependencies from your go.mod and go.sum files, and update the files to include dependencies for all possible combinations of build/OS/architecture tags (note: go run, go test, go build etc. are ‘lazy’ and will only fetch the packages needed for the current build/OS/architecture tags). By doing this before each commit, it will be easier to determine which changes to your code are responsible for adding or removing which dependencies when you look at the version control history.
Golangci-lint is a linting aggregator for Go that runs linters in parallel, reuses Go’s build cache, and caches analysis results to greatly improve performance on subsequent runs.
This is the best way to implement linting in Go projects.
Golangci-lint is configurable via yaml which can allow you to version your rules. Try to use as many linters as possible, especially if you are starting in Go. This will help you to understand the good practices of this language.
Golangci-lint website: https://golangci-lint.run/
An Overview of Go’s Tooling: https://www.alexedwards.net/blog/an-overview-of-go-tooling
A go tooling cheat sheet: https://github.com/fedir/go-tooling-cheat-sheet/blob/master/go-tooling-cheat-sheet.pdf