loading...

Creating Taboo Error Handler For Go

clavinjune profile image Clavin June Originally published at clavinjune.dev on ・3 min read

Photo by @hhh13 on Unsplash

I created this module for Golang to help me with error handling. This idea showed when a colleague of mine was thinking to pass context from handler to service, to repository to trace the error log more verbose. I disagreed with him because I thought that’s not what context is for. Perhaps I was wrong or he was wrong, or maybe both of us wrong because this is our first Golang project that deployed on production.

Despite our opinion about context, we both agreed that Golang’s error handling is too verbose and bulky. It makes us read more error handling more than read the system flow itself. Then I remember when I was coding using Java/Kotlin that I always use throws, throw, and try-catch block to handle any errors.

Hmm…

Why don’t I create it for Golang?

Then I create this try-catch block module for Golang called taboo. Because I know this thing creates polemic among Golang developer but, then I thought why don’t I give it a try?

For the design itself, I was inspired by this article but the whole implementation is all adjusted with my current needs. Instead of error, this module is based on panic and recover so it is quite dangerous whenever used in the wrong condition.

Let’s take an example:

package main

func div(a, b int) int {
  return a / b
}

func main() {
  div(10, 0)
}

Enter fullscreen mode Exit fullscreen mode

When b is filled with zero, it causes panic

panic: runtime error: integer divide by zero

goroutine 1 [running]:
main.div(...)
        /tmp/anon-org/taboo/cmd/example.go:4
main.main()
        /tmp/anon-org/taboo/cmd/example.go:8 +0x12

Process finished with exit code 2

Enter fullscreen mode Exit fullscreen mode

So, we can handle it using taboo like this:

taboo.Try(func() {
  div(10, 0)  
}).Catch(func(e *taboo.Exception) {
  fmt.Println(e.Error())
}).Do()

Enter fullscreen mode Exit fullscreen mode

taboo will catch the panic and try to recover it and make a stack of error called taboo.Exception to trace error more verbose. So the program ends like this:

main.div:9 runtime error: integer divide by zero

Process finished with exit code 0

Enter fullscreen mode Exit fullscreen mode

Quite handy right?

Then, what if I want to throw or rethrow the error to the first caller?

package main

import (
  "errors"
  "fmt"
  "github.com/anon-org/taboo/pkg/taboo"
)

func div(a, b int) int {
  if b == 0 {
    taboo.Throw(errors.New("division by zero detected"))
  }
  return a / b
}

func callDiv() int {
  var result int

  taboo.Try(func() {
    result = div(10, 0)
  }).Catch(func(e *taboo.Exception) {
    e.Throw("callDiv rethrow this error")
  }).Do()

  return result
}

func callCallDiv() int {
  var result int

  taboo.Try(func() {
    result = callDiv()
  }).Catch(func(e *taboo.Exception) {
    e.Throw("callCallDiv rethrow this error")
  }).Do()

  return result
}

func main() {
  taboo.Try(func() {
    callCallDiv()
  }).Catch(func(e *taboo.Exception) {
    fmt.Println(e.Error())
  }).Do()
}

Enter fullscreen mode Exit fullscreen mode

e.Throw(message) Will wrap the previous exception, and throw it again to the previous caller. So the printed error will be like this:

main.callCallDiv:34 callCallDiv rethrow this error caused by:
  main.callDiv:22 callDiv rethrow this error caused by:
    main.div:11 division by zero detected

Process finished with exit code 0

Enter fullscreen mode Exit fullscreen mode

It just like try-catch block in Java/Kotlin I think but with many flaws lol. This module is still an experiment that I myself is not going to using this module in production. Or perhaps should I?

Discussion

pic
Editor guide