https://recruit-tech.co.jp/blog/2017/12/11/go_dependency_injection/
この記事をみた。ここからは個人的な雑感だけど、結論からいえばGoではここまでのDIは必要ないことがおおいとおもう。
DIがなぜ必要なのかというと、テストをしたいからだ。しかもたいていはユニットテストだとおもう。UserServiceとUserRepositoryみたいなのがあったとして、UserServiceの挙動をテストするために、UserRepositoryがある特定のふるまいをしたときのことをテストしたい、みたいなやつ。
Goのばあい、ユニットテストは元のコードとおなじパッケージに存在していて、テストコードは内部構造もしっているし直接さわれる。だからこんなに頑張ってビルダをそとからわたさなくてもいいことがおおい。
具体的には、たとえば
package user
type Service struct {
repo Repo
}
func NewService(opts... ServiceOptions) *Service {
return &Service{repo: initRepo(opts...)}
}
みたいなservice.goファイルがあるとすると、service_test.goファイルでは、
package user
func TestService(t *testing.T) {
s := &Service{repo: mockRepo}
...
}
などのようにNewServiceをつかわずに初期化していい。
もちろんこのとき、初期化関数(NewServiceなど)じたいのテストができないという難点がある。でもこうした初期化関数はほんとうにインスタンスをつくるだけのような自明なものにすれば、テストする必要性はそれほどない。
もちろん、ほかにいろんなパターンがあるので、DIする必要がまったくないということはない。たとえば、インテグレーションテストの環境のために外部サービスをきりかえる、ということはある。ほんとうは外部のストレージサービスに接続するが、テスト用にはオンメモリな実装をつくって、テストデータでうごかしたいときとか。そういうばあいには、インタフェースをパラメータとしてうけとるような構造をつくってDIすることにはなるとおもう(ただ、ビルダが必要になるかはわからない。インスタンスをつくって渡すのでいいんじゃないかなあ)。ほかにも実際の実装モジュールがいろいろあって設定できりかえたいとか、DIしたいパターンはおおいとはおもう。
とはいえ、そのようにきりわけられるべきレイヤはそこまで大量にはならないので、こういうJavaみたいな壮大なDIフレームワークがほしいことは、あまりないんじゃないか。ふつうにmainでわたすとか、カスタマイズしたいときだけオプショナルなパラメータを指定するとか、そういうのであまりこまらないと、個人的にはおもう。といった雑感です。