Structured Errors in Go (2022)
41–50 of 75 posts
Re: Structured Errors in Go (2022)
#42Earlier quoted context omitted.
I think what you want are not dedicated classes but error codes. If you find yourself needing to branch on error classes it may mean error handling is too high up. ps. personally I always prefer string error codes, ie. "not-found" as opposed to numeric ones ie. 404.
No, I want dedicated classes. Be they thrown or returned as a value. Error codes are limiting and serve a different purpose. Error codes contain only the type of error that occurred and cannot contain any more data. With an error class you can provide context - a 400 happened when making a request, which URL was hit? What did the server say? Which fields in our request were incorrect? From a code perspective, if an e…
Re: Structured Errors in Go (2022)
#43Alright, so this looks pretty comprehensive for error handling. But I gotta ask – for smaller to mid-size projects, is there a point where this level of structure becomes more work than it's worth?
Even for small projects, this is a small thing to introduce but it will pay you dividends in the future. The earlier you start the more you'll thank yourself (it's not very helpful to frantically try and refactor this into a codebase after you've already been bitten!)
Re: Structured Errors in Go (2022)
#44Earlier quoted context omitted.
This is covered by the “ergonomics” section of TFA: > With custom error structs however, it's a lot of writing to create your own error type and thus it becomes more of a burden to encourage your team members to do this. Because you need a type per layer, and that type needs to implement both error and unwrap.
In practice, I have found the benefit of explicit typing to outweigh the downsides of needing to declare the types. As a concrete example, it means you can target types with precision in the API layer: switch e := err.(type) { case UserNotFound: writeJSONResponse(w, 404, "User not found") case interface { Timeout() bool }: if e.Timeout() { writeJSONResponse(w, 503, "Timeout") } } I skimmed the article and didn't see…
Re: Structured Errors in Go (2022)
#45Earlier quoted context omitted.
In practice, I have found the benefit of explicit typing to outweigh the downsides of needing to declare the types. As a concrete example, it means you can target types with precision in the API layer: switch e := err.(type) { case UserNotFound: writeJSONResponse(w, 404, "User not found") case interface { Timeout() bool }: if e.Timeout() { writeJSONResponse(w, 503, "Timeout") } } I skimmed the article and didn't see…
err.(type) fails when errors are wrapped, which is common and needs to be accommodated. To do what you're trying to do, you need to use errors.As.
Re: Structured Errors in Go (2022)
#46We've been storing values on errors using https://github.com/levenlabs/errctx for close to a decade now. We have a separate logging library that stores a KV map but technically you can store anything on errors. I recently just made it unwrap errors to find deeply stored keys.
Re: Structured Errors in Go (2022)
#47Example:
err := oops. Code("iam_missing_permission"). In("authz"). Tags("authz"). Time(time.Now()). With("user_id", 1234). With("permission", "post.create"). Hint("Runbook: https://doc.acme.org/doc/abcd.md"). User("user-123", "firstname", "john", "lastname", "doe"). Errorf("permission denied")
For easier debugging, the error contains the full stacktrace.
Re: Structured Errors in Go (2022)
#48Yeah always thought error handling is a bit wonky in Go. (Un)fortunately, most of my tinkering with Go are just toy level scripts. Thanks for the write up, will check the library!
Go itself is wonky, yet another programming language that is a fine example of worse is better mentality in the industry, whose adoption was helped by having critical infrastructure software written in it.
Concurrency is also something they got more or less right. The most important thing is that they invented their (Google) language that they could exert complete control over. From a business perspective specifically, that was much better than Java.
Re: Structured Errors in Go (2022)
#49Earlier quoted context omitted.
Go itself is wonky, yet another programming language that is a fine example of worse is better mentality in the industry, whose adoption was helped by having critical infrastructure software written in it.
I think it depends a bit on perception. If you're coming from C, Go is a step up in my opinion. Everything surrounding Go's type system and lack luster error handling seems worse to me coming from almost any other language - except C. Concurrency is also something they got more or less right. The most important thing is that they invented their (Google) language that they could exert complete control over. From a bus…
Walking on burning coals is a step up if you're coming from C.
We shouldn't grade languages on that much of a curve by comparing them to garbage.
> Concurrency is also something they got more or less right
Except data-races are an incredibly common bug in Go, and an incredibly rare bug in Rust.
Data-races are way more common in Go than in modern C++ or Java, if only because mutex semantics in Go are awful, with many programmers opting for manual "lock" and "unlock" calls, and mentally reasoning about the correct scope for the critical section with no compiler assistance.
I will give you that they made concurrency very easy.
Re: Structured Errors in Go (2022)
#50Earlier quoted context omitted.
> whose adoption was helped by having critical infrastructure software written in it Doesn't this contradict the first part of your post? Kubernetes for instance was ported from Java to Go (albeit, poorly). Is Java worse than Go?
Java is too advanced for Go folks, it is a PhD level language, when compared with Go minimalism, and their disdain for modern type systems (modern as in, invented in 1976, e.g. CLU and ML). Also it is quite ironic how given the Java bashing on Go community, there was so little learned from Java evolution and design mistakes. They even ended up having to reach for the same folks that helped designing Java generics. As…
To be fair, it was made abundantly clear when it was first released unto the world that it was intended to feel like a dynamically-typed language, but with performance characteristics closer to statically-typed languages. What little type system it has is there merely to support the performance goals. If they had figured out how to deliver on the performance end as a strictly dynamically-typed language, it is likely it would have gone without a static type system entirely.
Call it distain if you will, but it is not like there weren't already a million other languages with modern, advanced type systems. That market was already, and continues to be, flooded with many lovely languages to choose from. Go becoming yet another just like all the rest would have been rather pointless. "Like Python, but faster" was the untapped market at the time – and serving that market is why it is now a household name instead of being added to the long list of obscure languages that, while technically interesting, all do the same thing.