08 August 2022

Overview of the Go tooling

I'll show you some interesting Go tools that you can integrate into your project.

Sidorenko Konstantin
Sidorenko Konstantin thecampagnards

Go CLI

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

Installing Go Packages

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

Optimize your binary

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
    ...
    

Testing deeper

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 ./...

Test Coverage Report

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

Managing your Dependencies

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

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 example

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.

References

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

Categories

Golang Tool CI