24 ms·
Error handling is strictly worse than pretty much any other language out there — you are only making you believe that you are handling your error cases. A pragm
by kaba0 4y ago
Error handling is strictly worse than pretty much any other language out there — you are only making you believe that you are handling your error cases. A pragmatic “handle it here or bubble it up” is a much better approach, as more often than not you can’t actually handle the error at call site.
Goroutines in themselves won’t give you actually correct concurrency.
I really hope that Go doesn’t replace Java.
- smasher164 4y ago> A pragmatic “handle it here or bubble it up” is a much better approach This is exactly the approach used in Go code, so I'm not sure what you're referring to. If you're talking about the fact that you can technically ignore an error result like res, _ := doWork() then that's a fair point. But we still have https://staticcheck.io/docs/checks#SA4006 https://staticcheck.io/docs/checks#SA4006 for that.
- kaba0 4y agoI don’t see any automatic bubble up with Go.
- smasher164 4y agoI don’t think the original commenter said anything about “automatic”. That’s more of a subjective decision—whether or not you manually bubble up an error, or it just floats up because of the exception handler. Empirically, java code has had terrible error handling, because people just stick one catch statement at the root of their program. Go atleast confronts you with the error at every step.
- kaba0 4y agoAnd that is exactly the wrong approach. You really can’t do anything with the error case at most places. If I write a web server, which parts could knowingly handle a db connection error? Either the db driver internally, or going 10 deep higher and the request handler returning an 500 error. In go you would just verbosely (and error pronely!!) have to manually bubble it up, while this is automatically happening in Java with an informative stack trace, with no option to forget about it. Java is the one that handles error cases properly (and that’s why you might see exceptions more there — because they weren’t silenced somewhere wrongly!) here.
- smasher164 4y agoI agree that a stack trace is useful, but I disagree that automatic bubbling is universally good. If you look at well-written Go, context is added to every site where you bubble up an error.
- ilyt 4y ago>Error handling is strictly worse than pretty much any other language out there — you are only making you believe that you are handling your error cases. A pragmatic “handle it here or bubble it up” is a much better approach, as more often than not you can’t actually handle the error at call site. It could've definitely be better (just Rust-like Result<T> type would make it so much clearer to handle) but Go's insistence of dealing with it here and now means you have to think about what is exactly happening when it errors out, and are encouraged to add context to the error message instead of "here is stack trace, fuck you user, you're not worth knowing what is wrong". But it's verboseness in common cases is inexcusable, if I have 3 steps to establish a connection, having 3 lines per error to handle is inexcusably bad. And it will be fucking 3 lines even if you write it in one line, because go fmt will expand it back to 3 lines > Goroutines in themselves won’t give you actually correct concurrency. Main advantage is they are cheap enough that doing goroutine per request won't bite you in most cases so you can have near-perfect parallelization of common apps by just writing essentially serial code. The concurrency primitives are built into language and stdlibs which means when you do need synchronization, everyone does it same way.
- Gwypaas 4y ago> The concurrency primitives are built into language and stdlibs which means when you do need synchronization, everyone does it same way. As long as you after refactor N still are staying in the happy path avoiding the numerous footguns and implicit behavior Go supplies you with. I would say if you stray outside a single thread or shared nothing fire up a Goroutine per response architecture deeply reconsider the choice of using Go. https://eng.uber.com/data-race-patterns-in-go/ https://eng.uber.com/data-race-patterns-in-go/
- Xeoncross 4y ago> are encouraged to add context to the error message instead of "here is stack trace, fuck you user, you're not worth knowing what is wrong" haha, so true. I almost always wrap errors at every level with addition context. If it was worth doing, then it's worth explaining. People that prefer try/catching large sections of functionality or want to skip verbose handling of errors often have not thought through the user or tester experience. Heck, even trying to recreate the issue/state from production. if err != nil { return err } vs if err != nil { return fmt.Errorf("context here: %s: %w", action_type, err) } (or wrapping some custom app error with context for the trace) Of course you don't want to leak private details, but often there is a public component that is worth adding. This also brings up the concept of dual-error chains where what you log and what you report to the client are different.
- flippinburgers 4y agoIt is good to be forced to recognize errors and manually send them up the stack. Too many programmers have a "not my problem" attitude about errors. 1. Immediately when the error occurs, send it to logging with all required data to find the exact point of failure + data to understand the "why". 2. Send the error up the stack. If you do these two things, your systems written in golang will be resilient.
- kaba0 4y agoSo rely on the programmer countering their laziness instead of having these things the default in the language also known as exceptions?
- flippinburgers 4y agoExceptions are a nightmare.
- kaba0 4y agoThat’s your subjective opinion.