Dave Cheney

dave.cheney.net · Personal blog · on HN since 2012

Dave Cheney, a Go programmer and conference speaker, writes about Go language design, error handling, cgo, and API patterns.

What HN saysHN commenters cite his posts as references, especially "Cgo is not Go" on cgo's costs and "Channel Axioms" on Go concurrency behavior.
271HN people shared it
131linked it in comments
233stories submitted
9.4Kstory points
4 months agolast shared
2012people per year2026

Most-shared posts

  1. 1
    Cgo is not Go
    22 people · 16 points · first shared 2016 · discussion on HN
  2. 2
    [dotGo] Functional options for friendly APIs
    17 people · 10 points · first shared 2014 · discussion on HN
  3. 3
    Don't just check errors, handle them gracefully (2016)
    12 people · 50 points · first shared 2016 · 45 comments on HN
  4. 4
  5. 5
    Why Go and Rust are not competitors
    8 people · 142 points · first shared 2015 · 98 comments on HN
  6. 6
    An introduction to cross compilation with Go
    8 people · 72 points · first shared 2012 · 10 comments on HN
  7. 7
    Go Channel Axioms
    7 people · 5 points · first shared 2014 · 1 comments on HN
  8. 8
    Resources for new Go programmers
    6 people · 18 points · first shared 2013 · discussion on HN
  9. 9
    Homepage
    6 people · first shared 2017
  10. 10
    Go 1.7 toolchain improvements
    5 people · 248 points · first shared 2016 · 98 comments on HN
  11. 11
    Why Go Gets Exceptions Right
    5 people · 79 points · first shared 2012 · 81 comments on HN
  12. 12
    Prefer table driven tests (2019)
    5 people · 33 points · first shared 2019 · 64 comments on HN
  13. 13
    Let’s talk about logging
    5 people · 32 points · first shared 2015 · 28 comments on HN
  14. 14
  15. 15
    Dave Cheney's “High Performance Go” Workshop Docs
    5 people · 12 points · first shared 2019 · discussion on HN

What HN people wrote when they linked it

matttproud · 2024-11-26
My opinion on Kubernetes as a yardstick example of Go is this: This was one of the first large systems developed in Go, not too long after the language hit version 1.0 (ca. 12 years ago). What constituted good Go style and package architecture were not well known at that time even. Given that and hindsight being 20:20, I could easily imagine the internal architecture (not even the public surface) for Kubernetes being a lot different and simpler. The package architecture alone makes me cringe. As a hypothetical counterpoint, I wonder what Kubernetes would have looked like had Dave Cheney (https://dave.cheney.net/) and Rob Pike built it in that era. I think that would have been a better yard stick. I have a unique appreciation for this first large systems perspective as I co-designed an adjacent product in the cloud native ecosystem at that time (Prometheus). There was no good example to follow when it came to large program structure and design in Go at that time. We were all figuring that out for ourselves — organically. I think this point about organic evolution of the architecture is important to call out explicitly, because developers often look at an existing structure and essentially mimic it with their additions, changes, and refactors irrespective of whether the structure was correct for the problem it was trying to solve or even good. Given that reality, is it really any wonder that one of the first major pieces of software ended up being this metaphorical…
vips7L · 2025-07-20
Here’s a great read on its quirks, and where it really isn’t “simple”: https://fasterthanli.me/articles/i-want-off-mr-golangs-wild-ride https://dave.cheney.net/2014/03/19/channel-axioms
ncruces · 2025-04-21
I obviously meant "can't" not RFC 2119 "MUST NOT". I could list more sources, but I'll just leave you with these: https://go.dev/blog/package-names https://google.github.io/styleguide/go/best-practices#util-packages https://dave.cheney.net/2019/01/08/avoid-package-names-like-base-util-… The Google style guide is worth a read through, as the subsequent point recognizes the difficulties around package size. It can make sense to have a package with a single function, and it can almost make sense to stuff your entire program/library in a single package. The two rules work that exacerbate this tension are precisely visibility and no cyclic dependencies. The perfect is the enemy of the good. Forbidding cyclic dependencies is one such case, IMO.
IshKebab · 2024-02-29
He said it doesn't integrate well, and he's right. Go works best when you only have Go. (Ok that's true of most languages but it's especially true of Go.) This article has some details: https://dave.cheney.net/2016/01/18/cgo-is-not-go Note that this isn't true of languages like Python (CPython) or Rust which are much more closely tied to C than Go is. Go is a "from scratch as if C never existed" language which is great because it doesn't have any C baggage but it does make integrating with C more awkward.
camdencheek · 2024-01-23
Definitely possible! However, I prefer to avoid cgo wherever possible for more than just the overhead. In my experience: - It complicates builds by requiring a C toolchain - It makes single, static binaries more difficult - It makes portability more difficult (not that assembly is portable though) - It causes difficult-to-debug issues (I recently ran into an issue where MacOS signing changed, causing all my cgo binaries to be killed on startup) - Debuggers don't work across Cgo boundaries (they do with go ASM!) I think Dave Cheney said it best: https://dave.cheney.net/2016/01/18/cgo-is-not-go
kodah · 2022-08-04
Just making a note here, the answer was approved by Dave Cheney. If you're unfamiliar with him: https://dave.cheney.net/ He works for GitHub.
camkego · 2021-11-10
Please share articles/blog posts! I would guess there are newer articles about best practices for Go error handling, other than the great articles by Dave Cheney. https://dave.cheney.net/2016/04/27/dont-just-check-errors-handle-them-…
mappu · 2020-07-15
The go2 proposal (as currently implemented) is a source-to-source translator back to go1, so neither in that case. As for the existing implementation of generic map[K]V, generic []T, chan(T), etc., it's a best-of-both-worlds mix - a kind of erasure (there is only one map implementation in a Go binary) but with a static vtable for accessors without Java's need for boxing - all possible owing to the clever coupling between the runtime and the compiler. See https://dave.cheney.net/2018/05/29/how-the-go-runtime-implements-maps-…
gen220 · 2019-08-01
Not necessarily a collection of beginner tutorials, but for what they're worth, these are some very high quality in-depth articles on pieces of the language: - https://dave.cheney.net/practical-go - https://www.ardanlabs.com/all-posts/ If you're looking for more high-level, "get-things-done" stuff, this has been a great resource for getting off the ground: - https://github.com/astaxie/build-web-application-with-golang
dullgiulio · 2018-09-02
And that has a baggage of problems. The best way is what C# does, which incidentally is also what Go does with maps:https://dave.cheney.net/2018/05/29/how-the-go-runtime-implements-maps-…
mmgutz · 2017-06-01
Standard lib source is good. I gained a lot of insight from Dave Cheney's blog: https://dave.cheney.net.
anonfunction · 2015-10-15
Thanks! Go doesn't have exceptions and it is idiomatic[1] to return the error type. Dave Cheney has a really great blog post[2] which he describes why go does away with exceptions. The Golang wiki on GitHub has a great section[3] on errors as well. 1. https://gobyexample.com/errors 2. http://dave.cheney.net/2012/01/18/why-go-gets-exceptions-right 3. https://github.com/golang/go/wiki/Errors
rcarmo · 2015-08-19
If you use ARM devices, it might be worth pointing out that Dave Cheney has unofficial tarballs of _older_ versions here: http://dave.cheney.net/unofficial-arm-tarballs No 1.5 (yet), but if, like me, you do ARM stuff, you might want to bookmark this. And of course the cross-compiler works, but still. (edit: moved mention of ARM to first line)
conroy · 2014-07-30
The article doesn't mention any of the downsides to this approach, the biggest being style of C code. From Dave Cheney[0] - Using C code is inherently unsafe, not just because it unholsters all the C footguns, but because you can address any symbol in the runtime. With great power comes great responsibility. - The Go 1 compatibility guarantee does not extend to C code. - C functions cannot be inlined. - Escape analysis cannot follow values passed into C functions. - Code coverage does not extend to C functions. - The C compilers (5c, 6c, 8c) are not as optimised as their companion Go compilers, you may find that the code generated is not as efficient as the same code in Go. - You are writing plan 9 style C code, which is a rough analogue of C89. [0]: http://dave.cheney.net/2013/09/07/how-to-include-c-code-in-your-go-pac…
NateDad · 2013-01-29
Cross compiling is easy. Follow the steps here: http://dave.cheney.net/2012/09/08/an-introduction-to-cross-compilation… You can compile from any OS, for any OS. I compile for 32 and 64 bit versions of Windows, OSX, and Linux for my applications. It takes about 5 seconds for all the builds (running serially) to complete. [edit] Bah, beat by shykes. It's still not hard.
rollulus · 2024-12-18
This approach is so bad, I don't even know where to start. But it's all symptoms of their, sorry, incompetence. Take the loadCredentials example on top. If os.ReadFile cannot find the file, it returns an error with string representation: "open cred.json: no such file or directory". This comes straight from the std lib as it is, a great error. What does the errors.Is(err, os.ErrNotExist) do: prepend "file not found" to it, rendering: "file not found: open cred.json: no such file or directory". So this adds exactly nothing. The next if will prepend "failed to read file" to it, again, adding nothing as well. The two errors checks should be replaced by one if statement, optionally wrapping it with a context string but I cannot think of any use. Then the next step, error handling of verifyCredentials. I can only guess what it does, but assume that it returns an "username 'foo bar' cannot contain spaces" error. Does prepending "invalid credentials" help anything? Nope, so the whole if can be removed as well. No surprise your errors get clunky if you make them clunky. I have more pressing things to do than dissect this article line by line, but let me suffice that I feel sorry for newcomers to the language that an article like this is so high on HN. Back in the days there was just Dave Cheney's material to read [1], and it was excellent. It's unfortunately outdated in certain regards (e.g. with new Is/As functionality in the errors package for inspection and the %w formatting…
unscaled · 2023-06-05
I'm pretty sure the designers of Rust knows about CSP. Rust has Channels in the standard library after all: https://doc.rust-lang.org/rust-by-example/std_misc/channels.html Rust Channel have the nice additional that they don't panic, and don't have all the weird Go Channel Axioms[1] that you have to wrap your head around to get things to work correctly[2]. For what it's worth, I don't think Java Virtual Threads (a.k.a. project loom) has implemented an explicit concept of channels, although I guess BlockingQueue could work as a channel. There is a big issue with bringing CSP to languages like Java 21 or Go, that use so-called "colorless concurrency" or "stackful coroutines". CSP losses a lot of its modeling power when you combin shared mutable state and pre-emptive (or invisible) parallelism. And this is exactly what both of these languages do. "Colored" abstractions like async/await are more cumbersome (especially in Rust), but they let you know exactly at which points of execution your stackless coroutine may suspend, and you can handle synchronization accordingly. Those functional concepts are cumbersome, but threads ("green", "kernel", "virtual", "goroutines" or otherwise) are not the panacea their proponents claim them to be. I had to debug way too many data races in my life to consider them perfect. Rust still has a lot to improve on its async front (no async traits, async closures or async iterators and the async runtime confusion), it can at least promise me…
bilinguliar · 2021-01-17
Do not get me wrong, k8s is a revolutionary piece of software, but it is not the best example of a clean Go project. There are a few disturbing things: 1) Usage of `utils` package. Points against it were made in: https://dave.cheney.net/2019/01/08/avoid-package-names-like-base-util-… https://github.com/golang/go/wiki/CodeReviewComments#package-names 2) Check out the number of dependencies. This looks almost like NPM hell. 3) Lack of standardization and consistency. This project is so big, and there are so many contributors with their coding styles that the project looks untidy. 4) A lot of import renaming is a symptom of package name clashing or simply poor package naming. You usually do not need to rename import, and this is simply not required if your package structure was carefully thought about. Again, k8s is great. K8s solves a lot of problems. I love it, but it is not a great example of Go code.
scottlamb · 2021-01-04
Conversely, more sophisticated algorithms, and particularly monomorphization, may bloat the code size, causing icache, L2/L3 cache, and TLB misses. (Also slows compilation.) I think this is under-appreciated because it doesn't show in microbenchmarks. (I wish I knew of an easy way to measure how much cache pressure you're causing from a microbenchmark.) I suspect for this reason it'd be better in Rust to use a Go-like hash map implementation [1] that keeps all the key/value information (size, Hash and Eq implementations) in a vtable-like form rather than be monomorphized, except in really hot inner loops where the specialization is worth it. There was an interesting article and discussion on reddit relating to this [2] where someone made a toy type-erased map (though not as nice as Go's) to measure the difference in compilation times. Maybe some day I'll make a more production-ready attempt... [1] https://dave.cheney.net/2018/05/29/how-the-go-runtime-implements-maps-… [2] https://www.reddit.com/r/rust/comments/g1skz4/an_experiment_with_typee…
benesch · 2019-09-13
What I would give for the developers of the Go toolchain to have spent the last decade improving GCC or LLVM instead of their own bespoke toolchain. In many ways Go seems like an excuse for Google to fund the continued development of Plan 9. Three of the five most influential people on the Go team (Ken Thompson, Rob Pike, and Russ Cox) were heavily involved in Plan 9. And it shows. Go's toolchain is a direct descendant of the Plan 9 toolchain; in fact, the Go language is really just an evolution of the special C dialect that Plan 9 used [1]. Indeed, for a while, the Go compiler was written in this special dialect of C, and so building Go required building a C compiler (!) that could compile this custom dialect of C, and using that to compile the Go compiler [2]. By all rights, Plan 9 was an interesting research project, and seems well loved by those familiar with it. (I'm not personally familiar; it was well before my time.) But it never took off. What we ended up with is Linux, macOS, and Windows. Go very much wants to be Plan 9. Sure, it's not a full-fledged operating system. But it's a linker, assembler, compiler, binutils, and scheduler. All it asks of the host system is memory management, networking, and filesystem support, and it will happily replace your system's DNS resolution with a pure Go version if you ask it to [3]. I wouldn't be surprised if Go ships its own TCP/IP stack someday [4]. This is, in my opinion, craziness. What other language ships its own…
beliu · 2019-02-08
idop · 2018-03-12
My first resources were the Go website, specifically the following pages/articles: How to Write go Code [1], Effective Go [2] and Frequently Asked Questions [3]. I also read Alan Donovan and Brian Kerninghan's book "The Go Programming Language" [4]. So mostly these four, and of course simply writing code (along with the standard library documentation [5]). Since then I've also gained a lot of info and insight from various articles and blogs, such as "Debugging Performance Issues in Go Programs" [6] from an Intel blog, various posts from Peter Bourgon's blog [7] and Dave Cheney's blog [8], both of which I highly recommend. Oh, and "The complete guide to Go net/http timeouts" from the Cloudflare blog [9] is also worth reading. Previously I was mostly a Perl developer, but I also work(ed) a lot with JavaScript, and to a (much) less extent with Haskell, Racket and Nim. [1] https://golang.org/doc/code.html [2] https://golang.org/doc/effective_go.html [3] https://golang.org/doc/faq [4] http://www.gopl.io/ [5] https://golang.org/pkg/ [6] https://software.intel.com/en-us/blogs/2014/05/10/debugging-performanc… [7] https://peter.bourgon.org/articles/ [8] https://dave.cheney.net/ [9] https://blog.cloudflare.com/the-complete-guide-to-golang-net-http-time…
bbatha · 2018-03-02
This 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/b77aad089176ecab971d3a72f0357ed0abc8… 1: https://dave.cheney.net/2014/10/17/functional-options-for-friendly-api…
Groxx · 2018-02-22
Just to briefly jump in: statically compiling dependencies: roughly equivalent to "I want to link against a Go lib"? AFAIK the standard answers are "use cgo" (which has problems[1]) and "maybe plugins?"[2] but I don't know how plugins are working out. static compilation solving transitive dependencies: only if you have no singletons. In that case, yes! But the outside world is a singleton - anything on disk, through network, etc, anything with external state now has to deal with all past and future versions of the code simultaneously. Possible, but difficult and/or wasteful. For pure code though, yeah, this is a great solution, and it's part of why npm's "use all the versions" works out for micro-libs so well - they tend to have their state injected, which allows you-the-user to control how versions interact (if at all). Unfortunately you're left with node_modules[3] (as you mentioned). [1]: https://dave.cheney.net/2016/01/18/cgo-is-not-go + you just inherited a multi-threaded lib, which may cause forking problems later. [2]: https://golang.org/pkg/plugin/ [3]: https://pbs.twimg.com/media/C3SOI-_WAAAM4Js.jpg
fizzbatter · 2016-11-10
So, i was a Go developer for ~4 years, then for the last 4 months or so i've been learning and using Rust. The pure joy of some things with Rust was astounding. Now, i joined a new job and they're in need of a new language for some backend tasks - the choice was mine. Rust or Go? The backend tasks were heavy API servers - nothing amazing, we don't do groundbreaking work. Python was their existing language, but they weren't too happy with it. For weeks (literally) i mulled it over, i really really really wanted to use Rust. Rust gives me a peace of mind that Go never came close to. Unfortunately, Rust does not fit the development speed nor developer experience[1] that this shop has.. and i really felt Go would be the best choice for this place. My point to this post isn't to make a Rust vs Go comparison.. but rather, a wishlist for the hopefully eventual Go 2.0. I have no idea if/when that will ever be made.. but i hope it will, and i hope they adopt some things from Rust. 1. Channels without panics. Channels are awesome, but Go's design of them means that you have to learn special ways to design your usage of channels so that it does not crash your program. This is asinine to me. So much type safety exists in Go, and yet it's so easy for a developer to trip over channels and crash their program. 2. Proper error handling. I love error checking - i love it in Rust especially. It's very explicit, and most importantly, very easy to check the type of things. Recently i was…
zalmoxes · 2016-09-28
I don't think it would be fair to say that the Go community optimizes for productivity over good software development practices. In fact, there's been a good push in the community lately to talk about application design and what it means for code to be good/not good. * https://github.com/marcusolsson/gouk16-slides/blob/master/building-an-… * https://peter.bourgon.org/go-best-practices-2016/ * http://dave.cheney.net/2016/08/20/solid-go-design However, as a Go developer I'm finding that a lot of examples/tutorials and github projects are taking shortcuts when it comes to program design and how dependencies(loggers, config, db handlers) are being passed around. https://peter.bourgon.org/go-best-practices-2016/#program-design IMO it's a sign of Go still being a relatively new language. Despite the language existing for ~6 years now, we're only discovering some best practices today.
zamalek · 2016-09-22
> Go has hordes of green threads "goroutines" To clarify, they do not fall into the the strictest definition of green threads[1]. > [2]: As of Go 1.5, the default value of GOMAXPROCS is the number of CPUs (whatever your operating system considers to be a CPU) visible to the program at startup. Prior to 1.5, the default value was '1' but could be changed. > GUI model [...] Does that mean goroutines will fade into the background in Gallium? The main concern at the moment seems to be wrapping the underlying APIs. However, I see channels being used for great effect further down the line: var ui chan uiFunc = // ... button1Click := make(chan ClickEvent) go func() { for evt := range button1Click { ui <- func() { textBox1.setText("Button clicked!") } } }() button1.onClick(button1Click) I presume this also applies to interacting with the V8 ABI, seeing as JS is inherently single-threaded. [1]: https://golang.org/pkg/runtime/#GOMAXPROCS [2]: http://dave.cheney.net/tag/gomaxprocs
kasey_junk · 2016-03-28
> What‽ It provides channels, which are a really nice abstraction for concurrency. Channels are a concurrent safe queue, nothing more. They are not even particularly well implemented concurrent queues as they are highly contended. What go provides for abstractions around those queues are range and select. Range is a nice way to make simple concurrency cases look like traditional for loops (and is very rarely used in practice as simple concurrency cases are rare, at least for me). Select is a nice addition to the language, yet the edge cases around channels make it very difficult to reason about without keeping http://dave.cheney.net/2013/04/30/curious-channels open. > Have you actually written any Go? Using channels in Go is much nicer than using callbacks. I have, for 2 years, full time. I have not used node. Have you ever used a language that supports concurrency besides Go? Go does not provide, as part of its concurrency abstractions, things that are deemed bare necessities by other languages such as timeouts, cancellation, supervision, lock free structures, etc. The entirety of the Golang concurrency story can be wrapped up with 3 things a) the culture of the language prefers message passing concurrency b) the scheduler is a very good example of when simplicity gets you great performance in the main cases c) select as a language keyword is interesting. By leaving the basics out you push all of that work to the application level, which is why I think the…
Donch · 2015-07-09
People subscribe to Go lists because they want to discuss technical aspects of a programming language. For other topics, there are other venues. Yes, and for highlighting off-topic subjects, there is the simple moderator acronym "OT". A rigid rule book and enforcement policy has nothing to do with free speech. It's all about trying to balance the inequalities in the tech sector. Unfortunately, a rule book is not going to solve that problem. The cynic in me just thinks this a conference "feel-good" announcement planned as a result of Googlers feeling bad about the fact that they are a 83% male workforce. If the real problem is going to be solved, it's got to be about encouraging and educating people from all genders and races to code. That starts much earlier than any engagement in online communities. If the output of schools and colleges of trained coders was balanced, all the horror stories of harassment and abuse would soon become history as the workforce also becomes balanced, in my opinion. I strongly dislike the idea of self-appointed judiciaries. Mistakes happen. The nuances of behaviour of people with mental health issues is likely to get caught up in these rule books. That's why we have courts, to help deal with difficult cases. Vigilantes may well refer to the code of conduct for justification for statements of intent like this: http://dave.cheney.net/2015/06/13/listen-up I'm not comfortable with that.

Keyboard shortcuts

/Search
j kNext / previous blog
EnterOpen selected blog
vVisit the blog site
fFollow / unfollow
lSwitch grid / list view
dSwitch dark mode
g hHome
g pTop posts
g tTopics
g fFollowing
g lLiked
g yHistory
g qFAQ
EscBack / close