I find myself on a team where where small tiny little mistakes are being made when writing Go. I'd like to collect a reference of how to write better Go. I am putting it here.
- https://go.dev/doc/effective_go
- https://go.dev/doc/faq
- https://github.com/golang/go/wiki/CodeReviewComments
- https://go-proverbs.github.io
- https://github.com/golang-standards/project-layout/issues/10 (pkg directory should not be recommended for us)
- https://github.com/golang-standards/project-layout/issues/117
- If the last 2 don't convince you, then: https://github.com/go-standard/project-layout
- Consider: https://github.com/uber-go/guide/blob/master/style.md
- More: https://rakyll.org/style-packages/
Things I see newer Go programers do which should be avoided:
Too many packages
Circular packages are not allowed in Go, unlike Java, C#, Javascript, Ruby, or Python. This means that you can structure yourself into a corner which requires great feats of moving things around.
When should you create a new package? Only when you must!
You'll know when you must.
Common musts:
- Another executable and you want it smaller so you avoid including some larger packages.
- You are building libraries (packages) consumed by 3rd-parties and you want those 3rd parties to have a choice regarding sizing their resulting executables. Let YAGNI and KISS guide you.
Remember, Go is a derivative of C more than any other language, not Python, Ruby, JavaScript, C#, or Java. The compilation artifact of those languages are different than C or Go. If you aren't very familiar with C, then your instinct in Go is probably misguiding.
Defining an unused interface
https://github.com/golang/go/wiki/CodeReviewComments#interfaces says it best.
Go's implicit interfaces allow consumers to create the interface they need far better than you can.
Common or util packages
NEVER.
https://dave.cheney.net/2019/01/08/avoid-package-names-like-base-util-or-common
Don't store context
You'll notice the RFC for "relax recommendation against storing context" https://github.com/golang/go/issues/22602 is still open. Never expect this to be closed.
In fact, if you read that open issue, you'll learn that it is not requesting to relax the recommendation, but to clarify it and the clarification is, "don't store context"
No unused parameters (unless you are implementing an interface)
This really applies to ALL programming languages, but us Go programmers like it because we have so many "no unused..." rules already.
Clear is better than clever
https://go-proverbs.github.io https://www.youtube.com/watch?v=PAAkCSZUG1c&t=14m35s
Beware of reading too much
This is basic defensive programming which is often ignored which Go stdlib helps make trivial.
You've made your net/http Request and have a response:
Do:
body, err := io.ReadAll(io.LimitReader(resp.Body, 32768))
Don't:
body, err := io.ReadAll(resp.Body)
Vary the 32768 to as large as you expect the response to be, but do limit it. Don't do unlimited reads from the network.
Overuse of init()
init() almost always implies globals. See next item.
Overuse of globals
This really applies to all programming languages, but when you have a global, it is probably a sign that you've designed the structure of your application poorly.
Early on in a project is the best time to spend time to avoid this.
Top comments (1)
More food for thought: fosstodon.org/@filippo@abyssdomain...