2.3 定義型を作成してアプリケーションドメインに対応する

型の定義や拡張の方法について説明してきたので、ここでは実務に即した定義型の利用方法について、ポイントごとにまとめます。

定義型のレシーバーにアプリケーション固有のドメインロジックを宣言することで、関心事を分離したり、凝集度を高めたりできるようになります。これにはコード全体の見通しが良くなることに加えて、ユニットテストが書きやすくなる効果もあり、品質や生産性の向上にも寄与するでしょう。

2.3.1 スライスへの型定義

構造体や列挙型を丁寧に宣言しているプロジェクトでも見過ごしがちなのは、この集合型の定義型宣言です。

スライスなどのコレクションを受け取った後に、取得側でforループを回して処理するのは一般的な方法ですが、Goではスライスに対しても定義型を作成できます。

type Consumers []Consumer

func (c Consumers) ActiveConsumer() Consumers {
    resp := make([]Consumer, 0, len(c))
    for _, v := range c {
        if v.ActiveFlg {
            resp = append(resp, v)
        }
    }
    return resp
}

これにより、従来スライスで取得していたデータベースなどへの問い合わせ結果を、レシーバー側に移譲できます。

gets, err := GetConsumers(ctx, key)
activeConsumers := gets.ActiveConsumer()

今回の例では処理がシンプルなため、どちらで実装しても良さそうだと思うかもしれません。 しかし、コレクション操作が増えれば増えるほど呼び出し元の見通しが悪くなるのに比べ、レシーバーで実装すると実装箇所を極小化できますし、テストも書きやすくなるため、型を定義してロジックをレシーバーとして実装する方法がおすすめです。 ...