「バニラDIについて」への回答


https://qiita.com/yyu/items/f1f0fa21ddfc23c4bf18 に対する回答です。

twitter 上でも返信しましたが、元記事の文脈から外れてこの記事だけをみた方に誤解を与えかねないので、こちらにも会話を掲示しておきます(Qiita で Vanilla DI を検索するとこの記事が引っかかるので)。

(追記: 2020/12/29)
Minimal Cake Pattern 再考 の記事を受けて、私の理解が間違っていた部分を訂正しました。

TL;DR

Vanilla DI は、「DIコンテナの濫用」に対するカウンターを目指した宣言です。この宣言の目的は、以下の 2 つに集約されます:

  • 目的1: DI の仕組みを単純かつ簡潔に保つこと
  • 目的2: 設計破綻への感度を上げることで「設計のカナリア」とすること
    • 言い換えると、やりづらさを感じたら設計を疑うこと

そして、Vanilla DI ではその手段として Constructor Injection を選んでいます。これは他の手段を比較検討した上での結論です:

  • DI コンテナ
    • ❌ 目的1と2の両方を満たさない
  • デフォルト引数
    • ❌ 目的2を満たさない(責務過多/抽象の不足を見逃しやすいうえに、暗黙の前提を埋め込むので保守性が悪い)
  • Cake Pattern
    • ❌ 目的2を満たさない(デメテルの法則違反や責務過多/抽象の不足を見逃しやすい) (訂正: 2020/12/29)
    • ⭕️ どちらも満たしうるが、目的1が言語間ポータビリティが目当てなら適さない
  • Setter Injection
    • ❌ 目的2を満たさない(デメテルの法則違反や責務過多/抽象の不足を見逃しやすい)
  • Constructor Injection
    • ⭕️ どちらも満たす (訂正: 2020/12/29)
    • ⭕️ どちらも満たすが、言語間ポータビリティが必要なければ各言語にさらに最適な方法が存在しうる

まとめると、Vanilla DI は以下の要望をもつ方に向けたものです:

  • DI でテスト容易に保ちたい
  • 設計をよくしたい
  • 言語間ポータビリティを保ちたい (追記: 2020/12/29)

このような要望のもとならば、Vanilla DI はうまく機能することでしょう。

詳細

(訂正: 2020/12/29): Minimal Cake Pattern でも protected を使えばデメテルの法則違反を防げます。

(訂正: 2020/12/29): テストを書いていれば Minimal Cake Pattern でも設計の不味さの感度は保たてます(ただし運用状況に依存しますがこの点は Vanilla DI も同じ)。なお、テストを書かない上で悪い設計を無視する状況を正当化しうるのはごく短命なソフトウェアのみだと思います。