8 ms·
Go best practices, six years in (2016)
- jjuel 9y agoThis is great, but I wish it would get updated for 2018 as it is now 2 years old.
- HankB99 9y agoSearch for "update:" in the article. There are three and the most recent references a post from June of 2017. It appears the author has modified it for developments he considers important. It would be helpful if he indicated the revision date near the top of the article.
- indescions_2018 9y agoAuthor of go-kit microservices framework, which has several nice examples with which to get up and running https://gokit.io/examples/ https://gokit.io/examples/ Another interesting recent project is Truss which allows you to autogen go-kit handlers from protobuf definitions https://github.com/TuneLab/truss/blob/master/TUTORIAL.md https://github.com/TuneLab/truss/blob/master/TUTORIAL.md
- wiremine 9y agoI found Gokit's stringsvc tutorial particularly helpful: https://gokit.io/examples/stringsvc.html https://gokit.io/examples/stringsvc.html
- 0xmohit 9y ago50 Shades of Go: Traps, Gotchas, and Common Mistakes for New Golang Devs [0] might serve as a nice supplement to this article. [0] http://devs.cloudimmunity.com/gotchas-and-common-mistakes-in-go-golang/ http://devs.cloudimmunity.com/gotchas-and-common-mistakes-in...
- kylequest 9y agoI have another post that covers a few project structure best practices: https://medium.com/golang-learn/go-project-layout-e5213cdcfaa2 https://medium.com/golang-learn/go-project-layout-e5213cdcfa... It has a little more than Peter's post, but it's still not too opinionated :)
- tuespetre 9y agoI love the way the headings and their 'anchors' are styled on this blog post. I don't know, it just looks so pleasing.
- petercooper 9y ago[2016]
- sctb 9y agoThanks, we've updated the headline.
- zalmoxes 9y agoAt [Kolide](https://kolide.com/ https://kolide.com/) we're heavy users of Go Kit, and as a result have also adopted a lot of the style Peter recommends here. We've been slowly expanding on it with a style guide and company specific set of common libraries [here](https://github.com/kolide/kit#kolide-kit https://github.com/kolide/kit#kolide-kit). My coworker also wrote a [blog post](https://blog.kolide.com/using-go-for-scalable-operating-system-analytics-cb170d85b1c5 https://blog.kolide.com/using-go-for-scalable-operating-syst...) on how Go has been fantastic for us and references the above style guide. The code from go kit and [oklog](https://github.com/oklog/oklog https://github.com/oklog/oklog) are great examples of idiomatic Go. Unfortunately the community at large doesn't really follow the "no init"/"no package global vars", which can sometimes lead to bad experiences importing opensource Go libs.
- junkscience2017 9y agoI feel like go-kit is quite antithetical to the Go mindset...it presents a lossy abstraction as a means of future-proofing against eventualities that will almost certainly never be encountered to be honest it strikes me as the sort of library that excites intermediate developers who tend to over-architect
- sdhgaiojfsa 9y agoPretty good advice, except the preference for interfaces to support mocking. You should avoid mocking when possible in favor of real objects or fakes. Interfaces are still cool, though.
- spraak 9y agoCan you explain this further, or offer a link that does?
- sdhgaiojfsa 9y agoThe general theory is that, although you're focused on the code under test, if the underlying dependency is not behaving as expected, you want to know that. Mocks create an opportunity for your code's expectations about your dependencies' behavior to diverge from reality. So if at all possible, they should be avoided. There are a few general ways to do this. The best way is to use the real underlying dependency. This should be the default. If the dependency is too slow to use in the test (e.g. it has a long startup time, or is hosted remotely), the next best thing is to use a fake -- a local implementation of the dep that has the same behavior, but operates in memory on ephemeral data. The best libraries will provide these, and if they don't, you might be able to implement one and contribute it back. Even if you have to maintain it yourself, it often takes less code than describing mock behavior. The downside of fakes vs. the real implementation is that their behavior too can diverge. But this is not a net downside compared to mocks. If you can't use a fake, the next best thing after that is a stub. See below. Only if none of these options are viable should you use mocks. (The position I'm describing is the one referred to as "classicist" in this post: https://martinfowler.com/articles/mocksArentStubs.html https://martinfowler.com/articles/mocksArentStubs.html. I'm not by any means its originator.)
- sagichmal 9y agoThis is straight-up bad advice. You don't test the http.Client as part of your business logic, even (especially) if your business logic makes HTTP requests. Instead, you trust that package http is already well-tested, mock out http.Client as an abstract HTTP Request Do-er, and you downscope your tests to your business logic exclusively.
- erikb 9y agoHere are also some Go proverbs. Some of them are a lot older than 6 years. https://senseis.xmp.net/?GoProverbs https://senseis.xmp.net/?GoProverbs
- Goopplesoft 9y agoIs anyone else using golang dep[1] as their vendor/dependency tool? I’ve used it and it works great (much better than glide, gb et al) but I don’t see it in the wild too often. [1] https://github.com/golang/dep https://github.com/golang/dep
- pjmlp 9y agoWell, it is on its way out, have you missed the news regarding vgo? https://research.swtch.com/vgo https://research.swtch.com/vgo
- kitd 9y agoEr, thanks. We've just moved to go dep :) Go's dependency management story is starting to resemble JS's modules story :(
- dilap 9y agoYeah... In defense of the Go folks (1) they are working hard to make the transition as smooth as possible (2) dep was always just considered an experiment (though with aspirations by the author to have it become the official solution) (3) vgo almost certainly marks the end of the churn, and looks really nice.
- allover 9y ago> Go's dependency management story is starting to resemble JS's modules story It's worse tbh. npm was actually always usable if you knew what you were doing. Complaints with npm were generally down to misunderstanding, people not being aware of features like 'npm shrinkwrap' (which has now been replaced with a lockfile-by-default strategy) and of course registry issues (allowing unpublishing) that weren't unique to npm, and were only an issue for people relying on public registries at deploy-time, a bad idea.
- chimeracoder 9y ago> Well, it is on its way out, have you missed the news regarding vgo? Dep will have a clean migration path to vgo, and the latter isn't really production-ready yet. For now, I'd recommend using dep for daily use, until you have a compelling reason to switch to vgo, at which point the migration will probably be automatic.
- ctdonath 9y agoRule of thumb: anyone using the term "best practices" doesn't understand them. (Yes, some do. On the whole I find most don't.)
- spraak 9y agoAre you saying that speaks on this article or not? I don't care about a rule of thumb if it doesn't apply here.
- nzoschke 9y agoI simply love the go toolchain. The defacto standards for code formatting, linting and vetting, and the speed of builds and tests save tons of time. Both clock time and overall developer productivity. I have a GitHub CI service that verifies the standard go tools pass on every commit. The bot itself is naturally written in Go and executed in a Lambda function. Everything is just so fast! You get feedback in seconds. Which keeps you in the flow of coding. Maybe some other gophers will find it useful: https://www.mixable.net/products/bios/ https://www.mixable.net/products/bios/
- bbatha 9y agoThis is generally great advice, and aside from the package manager recommendations is still relevant today. I do take issue with a few things though. 1. Don't put your internal libraries in /pkg. /pkg has special GOPATH meaning as "compilation cache". Its not an actual name conflict, but why bother risking it. 2. This is just wrong: > fmt.Printf is self-contained and doesn’t affect or depend on global state; in functional terms, it has something like referential transparency. So it is not a dependency. Obviously, f.Bar is a dependency. And, interestingly, log.Printf acts on a package-global logger object, it’s just obscured behind the free function Printf. So it, too, is a dependency. stdout (and the buffer, and mutex on it) are exactly the same as the global log object. In fact, `log.Printf` is more or less just an alias to `fmt.Printf`[0] 3. I wish it had mentioned the functional options pattern in the part about constructors[1] 0: https://github.com/golang/go/blob/b77aad089176ecab971d3a72f0357ed0abc81f4a/src/log/log.go#L294 https://github.com/golang/go/blob/b77aad089176ecab971d3a72f0... 1: https://dave.cheney.net/2014/10/17/functional-options-for-friendly-apis https://dave.cheney.net/2014/10/17/functional-options-for-fr...
- kylequest 9y ago> 1. Don't put your internal libraries in /pkg. /pkg has special GOPATH meaning as "compilation cache". Its not an actual name conflict, but why bother risking it. It's a little too late for this because it's pretty much an unofficial standard for library code :-) Just look at Kubernetes, Docker or many other major Go-based applications/tools.
- lobster_johnson 9y agoLast I checked, pkg is going away as a compilation cache. As of Go 1.10, the compilation is in fact now stored elsewhere: https://golang.org/doc/go1.10 https://golang.org/doc/go1.10
- atombender 9y ago> the functional options pattern Functional options are controversial in the Go community. I don't like them personally. The idea of having a bunch of functions that exist only to mutate internal state on init is... an odd choice. Google code is riddled with this sort of style. It's annoying to write client code for another reason: It's hard to discover. For the "term" example in the article, you can't sit in your editor/IDE and type "term." and get a list of setter suggestions, since everything in a single namespace. "term.Speed()" does not sound like an option to me. Function names are generally verbs, and having one called Speed() doesn't read well. And it causes issues if you want to have a type called Speed. Then it has to be term.WithSpeed() or term.SetSpeed() or something. Neither of which is really self-explanatory. The fact that options are functions has other downsides. The moment you pack a option into a function, they've lost their ability to be introspected. You can't dump the options to a debug log before you invoke the constructor function. You can never ask an option function what it contains. I prefer representing options using actual data: type ( Option interface { isOption() } Speed int RawMode bool SomeOtherSetting struct { A, B int } ) Unfortunately, due to how Go interfaces work, you'll have to provide a dummy private method to tie the types together, but it's a small loss. (Go itself uses this pattern in a bunch of places, such as the compiler's AST.)