0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【体験談】Must系関数との出会いがGoの考え方を変えた話

Posted at

はじめに

Goでテストコードを書いていたときの話だ。
「なんでわざわざ MustNewNode なんて関数を作る必要があるんだ?」
最初は心の底からそう思っていた。

今回は、自分がその疑問にぶつかってから「なるほど!」と腑に落ちるまでの体験を書いていく。
これを読んだ人にもあの感動を味わってほしい。

1. 最初の疑問「NewNodeで良くない?」

テストコードの中でノードを作ろうとしたとき、こんなコードを見つけた。

mockNode: MustNewNode("node-123", "Q", "A", nil, nil)

「いやいや、MustNewNodeって何?普通にNewNode使えば良くない?」

素直にそう思った。そこでこう書いてみた。

mockNode: domain.NewNode("node-123", "Q", "A", nil, nil)

2. コンパイルエラーで気づく

するとビルドが通らない。
エラーメッセージはこれ。

multiple-value domain.NewNode(...) in single-value context

「えっ、何これ?」

少し考えてハッとした。
NewNodeは戻り値が (Node, error) になっている。
Goは明示的にエラーを返す文化。
つまりこう書かないといけない。

node, err := domain.NewNode(...)
if err != nil {
    t.Fatal(err)
}
mockNode: node

3. いや、これテストに毎回書くのめんどくさすぎる問題

確かにこれが正しい書き方だ。
でもテストコードでこんな処理を何回も書くのは明らかに冗長だ。
せっかくテストコードで動作確認したいだけなのに、コード量が無駄に膨れる。
しかも「このパターンでエラーになるわけがない」って前提も多い。

4. なるほどMustNewNodeってそういうことか!

ここでやっとMustNewNodeの意図に気づいた。
「もしこの場面でエラーが出るなら、そもそもテストコードの書き方が間違っている」
だったら panic で即座に気づけた方が良い。
だからこういう実装になっている。

func MustNewNode(...) domain.Node {
    node, err := NewNode(...)
    if err != nil {
        panic(err)
    }
    return node
}

5. Goらしい合理的な割り切りに感動した

この考え方、めちゃくちゃGoっぽい。
「本番コードでは安全に」
「テストコードではスピード優先で」
その切り分けが潔くて合理的。
しかも、標準パッケージでもこの思想が貫かれている。

regexp.MustCompile()
template.Must()
time.MustParse()

まとめ

今回の出来事で、Goの哲学が少し身体に染み込んだ気がした。
最初は「わざわざMustなんていらない」と思った。
でも実際に手を動かして、エラーを起こして、初めて腑に落ちた。

こういう「試行錯誤して初めて見える景色」があるのがプログラミングの面白さだと思う。
この記事が、同じ疑問を持った誰かの助けになれば嬉しい。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?