#goのwrap結局何が嬉しいのか
先日go1.13から実装されたwrapについての記事を書いたのですが,自分で例とかも書きながら、これって本当にうれしいんか?というか何が嬉しいんやろという疑問がありました。そこで、自分の社内の先輩に嬉しいところを聞いてみたところ、なぁぁぁぁるほどぉぉぉというお答えを頂けたので、自分なりにまとめて書いてみようと思います。
#嬉しいところ
僕が前の記事でエラーをラップすると嬉しいこととして、下位の関数で発生したえらーを上位の関数にシンプルな形でエラーを返せるというような説明をしました。これは本当に嬉しいことでは無かったです。書きながら自分でも疑問だったのですが、結局unwrapするんだしwrapする必要あるのか?ということです。
本当に嬉しかった事としては、もし、下位の関数で定義したエラーを上位の関数に返してしまうと、上位の関数が下位の関数に依存してしまう事になります。ここで、エラーを上位の関数が定義したエラーでwrapする事で依存を防げるのですね。これが本当は嬉しい事だったわけです。
#実装してみる
具体的にどうやって、実装するんや、という話です。
例えば、databaseとの接続部で出たエラーをcontroller層に返す時を考えます。まず、database側でこんなエラーを実装したとします
type DataBaseError struct {
err error
}
func (e dataBaseError)Error() string {
return e.err.Error()
}
これをwrapせずにコントローラー層に返してしまうと、controller層が外側のdatabase層のDataBaseErrorを知ることになり、依存の方向が逆向きになってしまいます。(dao→controllerの依存のみ許します)この DataBaseError
をWrapしてcontroller層に返すことで、 *fmt.WrrapError
型として返るのでcontroller層はDataBaseErrorのことを知らずにdaoからのエラーを扱えるようになります。
。。。。( ^ω^ )
ということを考えながら、自分で言ってて、これUnWrapできんやん、むしろ、AsとかIsとかをcontroller層でやろうとしたら、 errors.Is(err, dao.DataBaseError)
とか書くことになって、結局依存解消できんやんとか自分で突っ込んでしまいました。どうしたもんか
#というわけで、自分なりにもうちょっと考えてみる
色々と調べてみて、考えてみたのですが、確かに、unwrapしない限りは下位の層で定義したエラーを渡さなくて済むのですが、一番嬉しいこととしては自分で定義しエラーを扱う時に、複雑なものなどが必要になったら、wrapしてあげると綺麗なわかりやすい形で渡せることなのかな、という結論に行き着きました。また、そう言った使い方をしている例が多かったように思います。(大半はラップの仕方だけで、嬉しいことはあまり書いてなかった、、)。
もしかしたら、うまく実装できればunwrapしても依存しない形を作れるのかなーとか思ったので、あったらコメントとかしていただけると嬉しいです。