My VS Code Setup For Go Development


I’ve been using VS Code for Go development for over a year now. Here’s my current configuration for working on large projects.

The default settings for the Go extension for VSCode are fine for small projects, but I had performance issues when working with large projects or projects that vendor a large amount of code. When saving a project that uses the Kubernetes Go client, for example, VSCode and its helpers would lag, I’d see increased CPU usage, the laptop fans would run at full speed, and the battery would drain.

I have been using gometalinter as my linter in VSCode. When running my normal configuration (more on that in a bit), I noticed that it was fairly slow. Here’s the time on a fairly simple project of mine:

[bakins@tigh:~/go/src/github.com/bakins/stoker-monitor]$ time gometalinter

real	0m16.530s
user	0m44.852s
sys	0m13.151s

(Note: these times are from my older 13" MacBook Pro. My daily work laptop is a bit faster, but the timings ratios are about the same.)

At $DAYJOB, we have a standard gometalinter configuration and my local configuration checks a bit more than it does. However, I don’t necessarily need to run the full lint every time I save. I normally just want to see the obvious things. Then, I discovered megacheck which has a subset of lint checks, but is enough for my “edit code, save, repeat” cycle. It’s also a bit faster than the full gometalinter run:

[bakins@tigh:~/go/src/github.com/bakins/stoker-monitor]$ time megacheck

real	0m5.583s
user	0m14.166s
sys	0m1.641s

So, now, I changed VSCode to run megacheck as my linter. Then I created a VSCode task to run gometaliner:

{
    // See https://go.microsoft.com/fwlink/?LinkId=733558
    // for the documentation about the tasks.json format
    "version": "2.0.0",
    "tasks": [
        {
            "label": "gometalinter",
            "type": "shell",
            "command": "gometalinter",
            "args": [ "${workspaceFolder}" ],
            "presentation": {
                "reveal": "always",
                "panel": "new"
            },
            "problemMatcher": {
                "owner": "go",
                "fileLocation": ["relative", "${workspaceFolder}"],
                "pattern": {
                    //main.go:124:22:warning: error return value not checked (defer res.Body.Close()) (errcheck)
                    "regexp": "^(.*):(\\d+):(\\d+):(warning|error):(.*)$",
                    "file": 1,
                    "line": 2,
                    "column": 3,
                    "severity": 4,
                    "message": 5
                }
            }
        }
    ]
}

I run this task before I commit my code. This works for me as I tend to iterate quickly and megacheck catches the obvious issues. I run gometalinter before committing the code.

VSCode does not currently have a way to share tasks between projects, so I symlink this into each Go project.

Other VSCode Go Settings

I usually write a few lines of code or maybe a full function, then save. I do this without even realizing it. So, having a bunch of potentially slow or resource intensive things happening on every save breaks my work flow. So, I’ve tuned VSCode just a bit to match my style.

"go.vetOnSave": "off" - megacheck includes staticheck which is a super set of go vet.

"go.testOnSave": false - on even medium size projects, tests can take just long enough to interrupt my flow and usually they will fail while I’m actively writing code. I run tests manually often.

"go.buildOnSave": "false" - on large projects, my CPU would stay busy as I unconsciously saved every 30 seconds or so. The build speed should be much better now that Go 1.10 is out, so I’ll see if I keep this setting.

gometalinter Configuration

Here’s my current $HOME/.gometalinter.json:

{
    "Aggregate": true,
    "Disable": [
        "all"
    ],
    "Vendor": true,
    "EnableGC": true,
    "Enable": [
        "megacheck",
        "deadcode",
        "errcheck",
        "gas",
        "goconst",
        "gocyclo",
        "gofmt",
        "goimports",
        "gotype",
        "gotypex",
        "ineffassign",
        "misspell",
        "nakedret",
        "safesql",
        "structcheck",
        "unconvert",
        "unparam",
        "unused",
        "varcheck",
        "vet",
        "vetshadow",
        "golint"
    ],
    "Exclude": [
        "declaration of \"err\" shadows declaration at .* \\(vetshadow\\)"
    ]
}
go  vscode