Reduced error handling noice

229 views
Skip to first unread message

Johan Martinsson

unread,
Oct 7, 2020, 2:36:07 PM10/7/20
to golang-nuts
Hi, I'm looking for thoughts from some experienced go programmers on a technique to reduce error handling verbosity. 

The basic idea is to be optimistic over a few instructions, and then combine many errors in to one. This gist and explains the idea (note the absence of if err != nil {} )

        tenantID, err1 := store.GetParameter("TENANT_ID")
clientID, err2 := store.GetParameter("CLIENT_ID")
clientSecret, err3 := store.GetParameter("CLIENT_SECRET")

globalErr := multierr.Combine(err1, err2, err3)
return connection{
tenantID,
clientID,
clientSecret,
}, globalErr

There's some more detail in a post http://martinsson-johan.blogspot.com/2020/10/less-error-handling-noice-in-go.html. I'm sure someone else has already proposed this, but I wasn't able to find it. Grateful for pointers
 
While it seems sound to me I'm a very interested in what people from the community thinks.

Cheers
Johan Martinsson

David Skinner

unread,
Oct 7, 2020, 11:18:11 PM10/7/20
to golang-nuts
This looks like something I might have done. However, my preference would be to write a wrapper MustGetParameter receives string field, calls store.GetParameter(field), returns parameter or panics. 

You may then use
    defer func() { globalErr = recover()} 
    tenantID, err1 := MustGetParameter("TENANT_ID")
    clientID, err2 := MustGetParameter("CLIENT_ID")
    clientSecret, err3 := MustGetParameter("CLIENT_SECRET")

    return connection{
        tenantID,
        clientID,
        clientSecret,
    }, globalErr

If an error can be handled, it should be handled, but if you are just cascading the reports of errors, use defer recover as a try and let the calling function handle it. Of course some panics really should be a panic so you might want to have your defer func check the panic error to see if it is expected or something that really is a panic.

When I do an API I may have a Doit and a MustDoit, one returns an error and the other panics. My way of keeping the code clean unless I can actually do something about the error.

Johan Martinsson

unread,
Oct 8, 2020, 1:02:59 PM10/8/20
to golang-nuts

Indeed I learned this from https://blog.golang.org/defer-panic-and-recover and they mention this is done in the json module. And I couldn't adhere more. It's basically the same as try-catch from other languages.

Doing this systematically in a Rest server for errors of type 502, 400, 404 (in the sens route exists but not the resource with the given id) etc is still considered a good thing by go programmers?

Misha Gusarov

unread,
Oct 9, 2020, 3:26:17 AM10/9/20
to David Skinner, golang-nuts
On 8 Oct 2020, at 5:18, David Skinner wrote:

> When I do an API I may have a Doit and a MustDoit, one returns an error and
> the other panics. My way of keeping the code clean unless I can actually do
> something about the error.

Have a look at https://github.com/ridge/must — I got tired of writing Must*
functions and also of lack of Must* in various libraries.

It only covers simple cases, but works pretty well in practice.

--
Misha

Markus Heukelom

unread,
Oct 9, 2020, 3:31:39 AM10/9/20
to golang-nuts

In this case, because you call the same function, you could also try a helper function:

// GetParameters retrieves multiple parameters using GetParameter.
func GetParameters(params ...string) ([]string, error) {
var values []string
for _, param := range params {
value, err := GetParameter(param)
if err != nil {
return nil, err // alternatively you could also collect & combine all errors
}
values = append(values, value)
}
return values, err
}


params, err := GetParameters("TENANT_ID", "CLIENT_ID", "CLIENT_SECRET")
if err != nil {
return err
}
tenantID, clientID, clientSecret := params[0], params[1], params[2]
Reply all
Reply to author
Forward
0 new messages