HACKER Q&A
📣 denyial

Modern Go Dev Setup


For anyone who would consider themselves familiar with Go, what's your dev setup? I'm coming from Python 6yoe, am looking to learn Go. What is the 'recommended/idiomatic' professional Go dev setup for a local Nvim/CLI flow?

In Python, it would be something like `pyenv` version control, `poetry` environment, maybe `tox` for automation, `flake8`/`black` etc. Dump all their config in a root `pyproject.toml`, dir structure with `tests`, `src` and modules available and imported from root path. Write code -> run `python X.py` etc.

Basically what I want to know is what is the equivalent 'pretty good' setup for Go? Beyond setting PATH and GOPATH with some helloworld example go.mod it's not apparent from docs/tutorials what the equivalent environments/directories/commands are to the Python example above.

Any advice or opinions welcome! Learning syntax is fine, but without working in a few teams first to get a feeling of dev flows, I want to avoid noob mistakes/patterns early. Even a GH link to a minimal template 'get started' repo with some dummy files would be great!


  👤 sethammons Accepted Answer ✓
For going deeper, check out /r/golang on reddit.

You no longer need to set your GOPATH. Just create your project directory and `go mod init`. I prefer the Goland IDE or VS Code with the Go extension; however, lots of people get all the tooling set up in vim easily enough.

Basically, getting started 101: Create a project dir, run go mod init, write something in main.go at the root, and then `go run main.go`.

You'll want to read Effective Go (https://go.dev/doc/effective_go).

For everything else, it is much more simple than you are used to in Python. Use the latest version of Go. Use Go Modules takes care of your module versioning. A tox-like tool doesn't make sense in Go, just use `go test`. If/when things get more complicated, most people use a simple shell script or makefile. No need for anything like flake8, use `go fmt` which auto-runs every time you save, along with `go imports` if you set your tooling up and also makes it so you don't have to add/remove imports when hacking around. Pro-tip, to avoid unused variables when hacking, just assign them: `_ = myVar`.

The directory structure starts off super simple: a main.go and main_test.go in your root - you can get more clever as your project needs it. There are a few other conventions. You can check out https://www.wolfe.id.au/2020/03/10/how-do-i-structure-my-go-... for general reference. Apparently people are now using a `pkg` directory; I never do that (all the nested dirs there would just be top level in my projects). `cmd` is used for any number of executables you want to create after you outgrow a single main.go in your root.

When you start with integration tests, those make sense in their own directory, otherwise, all unit tests match their counterpart go file (*.go -> *_test.go).

With a single main.go, you just run `go run main.go` or you can run `go run .` if multiple *.go files are needed.

Some other general recommendations: avoid ORMs, avoid global state, avoid web frameworks (just use the stdlib or a request router like Chi), avoid mocks (have 'fakes' that match interface functions), don't go over the top on channels (often a mutex is best), and if you find yourself fighting the language, you are probably doing something non-idiomatic.

Best of luck!


👤 bartmika
The advice in this thread is excellent so far. I'll add to the discussion to say that another option you have is to containerize your Golang application and have a container for every project you work with. If this interests you, I've written a Blog article on it:

https://bartlomiejmika.com/posts/2022/how-to-containerize-a-...

It takes a little bit more time to setup your application in a container, but as time goes on, it saves you work by containing different services you can easily re-create / add / delete / etc versus having to install them manually in your workstation. In addition, having a containerized Golang application is the first step to creating "cloud-native" sort of applications. If this interests you, checkout this tutorial on building cloud-native applications:

https://learning-cloud-native-go.github.io/


👤 stop50
I came from the same direction. I put gopath on a ramdisk, because its an cacge which is polluted fast with old versions. GOBIN is set to ~/.local/bin, so the installed go binaries are static and in the path. fo itself has most tooling integrated: black = go fmt poetry = go.mod sphinx = go doc/godoc

For linting i use revive, which i selected in vscode. since modules are path based the directory structure has everything at the root path. i put the files with the main function usually in cmd or one sublevel below it. if you have multiple binaries in one repo you have to move them into their own directories or building gets messy.