Linting Go programs: A guide to improving code quality

by:

Web Development

Using linters improves readability by highlighting problems before they are executed, and it helps with the standardization of your codebase. A good linter has configuration settings that help to lessen warnings for rules you don’t care about, making code easier to comprehend, modify, and maintain.

In this article, we’ll be learning more about linting through these topics:

golint has been the most widely used linter for Go over the years. Unfortunately, it is now officially deprecated and archived. The issue with golint is that it doesn’t offer any configuration options and always applies all the rules, which leads to warnings for rules you don’t care about. In this article, we’ll use the revive package as well as exploring alternative go linting packages.

Conversely, revive is a fast, configurable, extensible, adaptable, and beautiful linter for Go. It serves as golint’s drop-in replacement.

Here’s how revive is different from golint:

  • Allows us to enable or disable rules using a configuration file
  • Allows us to configure the linting rules with a TOML file
  • Is two times faster running the same rules as golint
  • Provides functionality for disabling a specific rule or the entire linter for a file or a range of lines (golint allows this only for generated files)
  • Optional type checking. Most rules in golint do not require type checking. If you disable them in the config file, revive will run over six times faster than golint
  • Provides multiple formatters that let us customize the output
  • Allows us to customize the return code for the entire linter or based on the failure of only some rules
  • Everyone can extend it easily with custom rules or formatters
  • revive provides more rules compared to golint

Setting up a project with revive

Open a terminal and create a project folder. Navigate to the project folder and run the following command to start a new project:

go mod init project

Navigate to your Go project and run the following command to install the revive linter package:

go install github.com/mgechev/[email protected]

Create a main.go file and add the following code snippet to the main.go file:

package main
import (
    "fmt"
)
func main() 
    PrintName("Emmanuel")
    PrintAge(23)

func PrintName(name string) 
    fmt.Println(name)

func PrintAge(age int) 
    fmt.Println(age)

Now, run the revive command on the project terminal and you should get the following report:

main.go:11:1: exported function PrintName should have comment or be unexported
main.go:15:1: exported function PrintAge should have comment or be unexported

In Go, the first letter of an exported function is usually an uppercase. A properly documented codebase requires that exported functions be commented with a brief overview of the function’s purpose, so everyone can understand what it does. Now we can see how the revive package helps us write well-documented code.


More great articles from LogRocket:


Now, let’s add some comments to these functions:

...
// This function uses the fmt.Println function to print a string.
func PrintName(name string) 
    fmt.Println(name)

// This function uses the fmt.Println function to print a number.
func PrintAge(age int) 
    fmt.Println(age)

Execute the revive command and you should have the following report:

main.go:12:1: comment on exported function PrintName should 
be of the form "PrintName ..."
main.go:17:1: comment on exported function PrintAge should be of the form "PrintAge ..." 

Revive tells us that our comment should begin with the name of our exported functions for a properly documented codebase.

Let’s change our comments to the following:

...
// PrintName uses the fmt.Println function to print a string.
func PrintName(name string) 
    fmt.Println(name)

// PrintAge uses the fmt.Println function to print a number.
func PrintAge(age int) 
    fmt.Println(age)

With this, execute the revive command and you should have no report.

Suppressing linting errors with revive

Sometimes, it’s necessary to disable specific linting issues that appear in a file or package. Both comments and exclusion rules in the configuration file can be used to do this. Let’s examine each strategy in turn.

The comments strategy comes in handy when you want to disable warnings for a certain section of code but still want to apply the rule to other parts of the project.

Here is how to disable specific linting issues using comments:

package main
import (
    "fmt"
)
func main() 
    PrintName("Emmanuel")

// revive:disable:exported
func PrintName(name string) 
    fmt.Println(name)

The syntax for this is revive, followed by a colon, then disable. If desired, add another colon followed by the name of a linter rule.

Setting up configurations for linters

This is one amazing feature of the revive linter package that address the major challenge with the popular golint linter package.

Let’s see how to configure the revive linter package to disable some linting rules in order to reduce unnecessary warnings.

Add a file named revive.toml to the project folder with the default revive configuration:

ignoreGeneratedHeader = false
severity = "warning"
confidence = 0.8
errorCode = 0
warningCode = 0

[rule.blank-imports]
[rule.context-as-argument]
[rule.context-keys-type]
[rule.dot-imports]
[rule.error-return]
[rule.error-strings]
[rule.error-naming]
[rule.exported]
[rule.if-return]
[rule.increment-decrement]
[rule.var-naming]
[rule.var-declaration]
[rule.package-comments]
[rule.range]
[rule.receiver-naming]
[rule.time-naming]
[rule.unexported-return]
[rule.indent-error-flow]
[rule.errorf]
[rule.empty-block]
[rule.superfluous-else]
[rule.unused-parameter]
[rule.unreachable-code]
[rule.redefines-builtin-id]

Now, remove all comments and run the following command to use the linter with the configuration file:

revive -config revive.toml

To disable any of these rules, you can either remove them or add # before the specified rule as follows:

#[rule.exported]

Setting up linting in code editors

Some code editors support linting code automatically; Visual Studio Code is one of them.

Let’s see how to set up the revive linter in Visual Studio Code.

Open VS Code and install the go extension for VS Code. Then, select the File tab > Preferences > Settings and add go.lint to the search field and select revive in the Go: Lint Tool section.

Go Lint in Search Field

The default Go linter for Visual Studio Code is staticcheck.

Exploring the go vet command

In contrast to linters, the go vet command identifies code that compiles but probably won’t perform as intended.

Let’s consider a common self assignment bug in our Golang code. Update main.go file as follows:

package main
import (
    "fmt"
)
func main() 
    PrintName("Emmanuel")

// revive:disable:exported
func PrintName(name string) 
    name = name
    fmt.Println(name)

The above code will compile even with this bug. Executing the revive linter command won’t report any issue concerning this bug. This is where the go vet command comes in handy.

Run the go vet command and you should have the following result instead:

$ go vet
# sample
.\main.go:10:2: self-assignment of name to name

Alternative packages for linting in Go

If revive isn’t your preference, here is a list of Go linters that have been built and maintained by the community.

golangci-lint

golangci-lint is a fast Go linters runner. It integrates with every major IDE, employs caching, enables YAML configuration, executes linters in parallel, and comes with a large number of linters.

staticcheck

staticcheck is a cutting-edge Go programming language linter. It employs static analysis to identify bugs and performance problems, provide simplifications, and enforce style guidelines.

Conclusion

Go takes documentation seriously because the easier it is for developers to produce good documentation, the better for everyone.

In this article, we’ve explored linting in Golang, my preferred linting package, and alternative packages for linting in Go. I hope you’ll like working with revive!

LogRocket: Full visibility into your web and mobile apps

LogRocket Dashboard Free Trial Banner

LogRocket is a frontend application monitoring solution that lets you replay problems as if they happened in your own browser. Instead of guessing why errors happen, or asking users for screenshots and log dumps, LogRocket lets you replay the session to quickly understand what went wrong. It works perfectly with any app, regardless of framework, and has plugins to log additional context from Redux, Vuex, and @ngrx/store.

In addition to logging Redux actions and state, LogRocket records console logs, JavaScript errors, stacktraces, network requests/responses with headers + bodies, browser metadata, and custom logs. It also instruments the DOM to record the HTML and CSS on the page, recreating pixel-perfect videos of even the most complex single-page web and mobile apps.

Try it for free.

Leave a Reply

Your email address will not be published.