Tips On How To Save Time During A Static Analysis On Go

Tips On How To Save Time During A Static Analysis On Go

For the last two years, our team has been translating various parts of the project into micro services on Go. They are developed by several teams, so we needed to set a strict bar of code quality. To do this, we use several tools, this article will deal with one of them – a static analysis.

Static analysis is the process of automatically checking the source code with the help of special utilities. This article will tell you about its usefulness, briefly describe the popular tools and give instructions on how to implement it. It is worth reading if you have not encountered such tools at all or use them in an unsystematic manner.

In articles on this topic, the term “linter” is often encountered. For us, this is a convenient name for simple tools for static analysis. The task of the linter is to find simple errors and incorrect design.

Why do we need linter?

Working in a team, you most likely perform a code review. Errors missed on the review are potential bugs. Missed the unhandled error – do not get an informative message and look for the problem blindly. The wrong typecasting or turned to nil map – even worse, the binaries will fall from panic.

The above errors can be added to the Code Conventions, but finding them when reading the requester pool is not so easy, because the reviewer will have to read the code. If your head does not have a compiler, some of the problems will still go to battle. In addition, the search for small errors distracts from checking logic and architecture. At a distance, support for this code will become more expensive. We write in a statically typed language, strange not to use it.

Popular Tools

Most utilities for static analysis use go/ast and go/parser packages. They provide functions for parsing the syntax of .go files.

In addition to AST, there is a Single Static Assignment (SSA). This is a more complex way of analyzing code that works with the flow of execution, rather than syntactic constructs. In this article we will not consider it in detail, you can read the documentation and take a look at the example of the stack check utility.

Further, only popular utilities that perform useful checks for us will be considered.

Gofmt

This is a standard utility from the go package, which checks for consistency with the style and can automatically fix it. The matching style is a must for us, so gofmt checking is included in all our projects.

Typecheck

Typecheck checks the type match in the code and supports vendor (unlike gotype). Its launch is mandatory to check the compilation but does not give full guarantees.

Go vet

The go vet utility is part of the standard package and is recommended for use by the Go command. Checks for a number of common errors, for example:

Maligned

In Go, the order of the fields in the structures affects the memory consumption. Maligned finds a sub-optimal sort. In this order of fields:

struct {
a bool
b string
c bool
}

The structure will occupy 32 bits in memory due to the addition of empty bits after fields a and c.

If we change the sorting and put two bool fields together, then the structure will only take 24 bits:

Goconst

The magic variables in the code do not reflect the meaning and complicate the reading. Goconst finds literals and numbers that occur in code 2 times or more. Note, often even a single use can be a mistake.

Gocyclo

We consider the cyclomatic complexity of the code to be an important metric. Gocycle shows the complexity of each function. You can display only functions that exceed the specified value.

We chose the threshold value 7 for ourselves because we did not find the code with a higher complexity, which did not require refactoring.

gocyclo -over 7 package/name

The Dead Code

There are several utilities for finding unused code, their functionality may overlap.

As a result, unused will point directly to both functions, and the deadcode only on unusedFunc. Due to this, the extra code is deleted in one pass. Also unused finds unused variables and field structures.

Varcheck: finds unused variables

Unconvert: finds useless casts

var res int
return int(res) // unconvert error

If there is no task to save on the time of launching checks, it’s best to run them all together. If optimization is necessary, we recommend using unused and unconvert.

How it all works

Running the tools listed above is consistently inconvenient: errors are issued in different formats, execution takes a lot of time. Checking one of our services with the size of ~ 8000 lines of code took more than two minutes. Install utilities, too, will have to separate.

To solve this problem, there are utilities-aggregators, for example, goreporter and gometalinter. Goreporter renders the report in HTML, and the gometalinter writes to the console.

Gometalinter is still used in some large projects (for example, docker). He can install all utilities with one command, run them in parallel, and format errors with the template. The execution time in the service mentioned above was reduced to one and a half minutes.

Aggregation works only on the exact coincidence of the text of an error, therefore on an output, the repeated errors are inevitable.

In May 2018 a golangci-lint project appeared on the GitHub, which greatly exceeds the gometalinter inconvenience:

The execution time on the same project was reduced to 16 seconds (8 times)

There are almost no duplicate errors

Friendly yaml config

The nice output of errors with a code line and a pointer to the problem

Do not need to install additional utilities

Now the speed increase is provided by the re-use of SSA and loader Program, in the future it is also planned to re-use the AST tree, about which we wrote at the beginning of the Tools section.

At the time of writing the article on hub.docker.com there was no image with the documentation, so we made our own, customized according to our notions of convenience. In the future, the configuration will change, so for the production, we recommend that you replace it with your own. To do this, just add the .golangci.yaml file to the root directory of the project (an example is in the golangci-lint repository).

With this command, you can check the entire project. For example, if it is in ~/go/src/project, change the value of the variable to PACKAGE = project. The check works recursively on all internal packages.

Note that this command works correctly only when using a vendor.

Implantation

All of our development services use the docker. Any project runs without the go environment installed.

In other cases, it is better to use CI and to disallow the code in which there is at least one error. We do just that, adding the launch of the linters before the tests.

Conclusion

The introduction of systematic inspections markedly shortened the review period. However, more importantly, another: now we can discuss the big picture and architecture most of the time. This allows you to think about the development of the project instead of plugging holes.

Paul Brook is a professional full stack developer & IT content marketer. Developer by day and a content Marketer by night. He is the lead Developer and content marketer at www.smartspate.com. His passion for helping people in all aspects IT and Marketing flows through in the expert industry coverage he provides. In addition to IT, also provide technical SEO and copywriting services for business of all sizes.

Find Us At:

error: This Content is Protected! All Rights belong to Smart Spate Ltd.

This website uses cookies. By continuing to use this website you are giving consent to cookies being used. For information on a cookie and how it impacts on users, you can visit our Privacy Policy and Cookie Policy.AcceptCloseRead more