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 for that.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.
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.
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.
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.
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.
Go makes you deal with the error every single time something could go wrong, so you have a chance to do the right thing and append context at every single failure path.
Also, checked exceptions are very much not like that, and being able to handle errors of a logical unit is also beneficiary (e.g. transactions). You are free to use the scope-size that makes sense for the given use case.
Can you explain that? Touching every context of an error propagation seems opposite of forgetting about it.
I read it as "let's stop pretending we are wizardy wizards and can do things right way in 100% cases and let the language to enforce us to handle errors, producing better result for average Joe SR SWE".
Am I right with my readings (i'm not a dev guy at all)?
I think it is. I will gladly trade a couple of hours of extra error handling code every week in exchange for no pager duty alarms on the weekend.
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.
Goroutines in themselves won’t give you actually correct concurrency.
I really hope that Go doesn’t replace Java.