3 ms·
Ask HN: 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!
- stop50 4y agoI 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.
- sethammons 4y agoFor 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 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-project/ 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!
- denyial 4y agoThis is perfect, and exactly all the information I need! Thank you very much for the time :)
- nateb2022 4y agoWell said, over all. I very much disagree, though, about what you said about mutexes and channels. Channels are by far the most idiomatic way to transfer data in a concurrent model. Timeouts, worker patterns, and program architecture are much much more idiomatic and less error-prone when using channels. Mutexes can be used properly, but it's rare that there's a situation where using a mutex would be better than using a channel. When I was first learning Go in 2017, I had to emerge from the shell of using mutexes that I had entered after working in other languages. After switching to predominantly channel-based communication, I found that my architecture became much less error-prone, and that things just worked. Prior to that, I would spend tons of time trying to figure out the exact situation that had put me in a deadlock, where several goroutines were waiting for a mutex to be unlocked that never was, or where a goroutine was trying to unlock an already unlocked mutex.
- sethammons 4y agoChannels are great. In my experience, newcomers can over-do it. I should have qualified it as "don't forget about mutexes."
- kingkongjaffa 4y ago> avoid mocks (have 'fakes' that match interface functions) Can you explain a bit more about this? Any articles I can dig into explaining the difference?
- sethammons 4y agoWent on vacation and missed your question. I'm on a plane so I'll link to an article I wrote some time back. I'd write it differently now to be more clear: https://sendgrid.com/blog/when-writing-unit-tests-dont-use-mocks/ https://sendgrid.com/blog/when-writing-unit-tests-dont-use-m...
- bartmika 4y agoThe 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-golang-app-with-docker-for-development-and-production/ 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/ https://learning-cloud-native-go.github.io/