The Go ecosystem provides a lot of tools to help you write cleaner, more predictable code. As a result, it can be a bit tricky to figure out what you should use, especially if you’re new to the language. Some of the more popular tools are go vet
, gofmt
, and golint
.
To be clear, these three tools aren’t competing options. Each one checks for different things, allowing them to be used in conjunction. You could think of them as separate steps in a code-checking ladder.
Detailed description of the image showing popular options for code checking in Go
Popular options for code checking in Go can be thought of using the metaphor of a ladder to describe how opinionated they are. The ladder has four rungs, with the least opinionated at the bottom, and the most opinionated at the top.
The bottom rung is GoCompiler, which finds serious errors that prevent your code from running.
The second rung is go vet, which finds subtle issues where your code may not work as intended.
The third rung is gofmt, which applies standard formatting (whitespace, indentation, etc)
The top rung is golint(and other linters), which make code style recommendations (naming, code conventions, etc).
At the bottom of the ladder, the Go compiler does a baseline check to ensure that your code is valid, catching things like syntax errors and missing imports. Any code checking after that is optional. The higher rungs on the ladder are more focused on code aesthetics.
With that, let’s look a little more closely at each of these tools to see what they do.
go vet
go vet
starts where the compiler ends by identifying subtle issues in your code. It’s good at catching things where your code is technically valid but probably not working as intended. One example of this is when you have unreachable code. go vet
is part of a standard Go installation, making it straightforward to run from the command line.
Running it: go vet main.go
Example:
Before:
package main
import "fmt"
// Prints out "Super Mario 3"
func main() {
game_version :=3
fmt.Printf("Super Mario %s\n",game_version)
}
After:
./main.go:6:2: Printf format %s has arg 3 of wrong type int
This is warning us that we’re trying to interpolate an int into a string using the %s “format verb,” which isn’t usually intended for integers. While it is valid Go, it produces unexpected results, ultimately printing: Super Mario %!s(int=3)
Resources:
gofmt
gofmt
defines code formatting standards for Go and applies them to your code automatically. These formatting changes don’t affect the execution of the code—rather, they improve codebase readability by ensuring that the code is visually consistent. gofmt
focuses on things like indentation, whitespace, comments, and general code succinctness.
gofmt
is included in a standard Go installation and can be run from Go’s command line tools.
Running it: go fmt main.go
or gofmt -w main.go
Example:
Before:
package main
import "fmt"
// Prints out "Super Mario 3"
func main() {
game_version :=3
fmt.Printf("Super Mario %s\n",game_version)
}
After:
package main
+
import "fmt"
+
// Prints out "Super Mario 3"
func main() {
- game_version :=3
- fmt.Printf("Super Mario %s\n",game_version)
+ game_version := 3
+ fmt.Printf("Super Mario %s\n", game_version)
}
This example adds blank lines to separate the package and import declarations. It also adds some spacing into the variable assignment and the function parameters.
Resources:
Alternatives:
gofmt
has a few alternatives. The following tools apply the same formatting as gofmt
along, with some additional formatting rules (which is useful if you want to enforce an even stricter formatting standard):
golint
golint
is a linter maintained by the Go developers. It is intended to enforce the coding conventions described in Effective Go and CodeReviewComments. These same conventions are used in the open-source Go project and at Google. golint
is only concerned with stylistic matters, and its rules are more like opinions than a hard standard. As the project README states:
The suggestions made by golint are exactly that: suggestions. Golint is not perfect… do not treat its output as a gold standard.
golint
is just one of many possible Go linters you can use. These linters can be run together or in parallel to check various aspects of your code, including coding conventions, performance, complexity, and more. For example, golangci-lint is a popular linter runner that comes prepackaged with dozens of linters, including golint
. To run golint
by itself, you can install it with go get -u golang.org/x/lint/golint
and run it in the terminal.
Running it: golint main.go
Example:
Before:
package main
import "fmt"
// Prints out "Super Mario 3"
func main() {
game_version :=3
fmt.Printf("Super Mario %s\n",game_version)
}
After:
main.go:5:2: don't use underscores in Go names; var game_version should be gameVersion
Resources:
Alternatives:
The following alternative linters can be used in place of, or in addition to, golint
:
Integrations and more
The code checking tools we’ve discussed above are mostly just the “official” ones (the ones maintained by Golang developers). One nice benefit of having official tooling is IDE integrations. For example, Goland has built-in support for gofmt, and VSCode has an official Go extension that can check your code whenever you save a file.
Whether you use these official code checkers or other ones provided by the community, there are plenty of great options for keeping your code clean and consistent. Hopefully this article gives you a clearer idea of how you can use go vet
, gofmt
, and golint
to benefit your code.