2024.11.15
FirestoreクライアントをDIする必要性について考える
「FirestoreのクライアントをDI(Dependency Injection)する必要があるのか」というテーマについて考えてみると、いくつかの具体的なパターンが見えてきます。今回は、DIが効果的に機能する可能性のある4つのシチュエーションについて整理してみました。
DI(依存性注入)とは?
DI(Dependency Injection)とは、クラスやモジュールが必要とする依存オブジェクトを外部から注入するデザインパターンのことです。この手法を用いることで、コードの依存関係を明示的に管理し、再利用性やテスト性の向上を図ることができます。DIを使うことにより、コードは疎結合となり、変更や置き換えが容易になります。
DIには次のような利点があります。
- テストのしやすさ: 依存オブジェクトを容易にモックに置き換えることができるため、ユニットテストが簡単に行えます。
- 柔軟性の向上: 依存関係を外部から注入することで、必要に応じて異なる実装を簡単に切り替えることができます。
- コードの保守性向上: 依存が明示的になるため、コードの理解が容易になり、保守性が向上します。
FirestoreクライアントをDIしたくなるパターン
FirestoreクライアントにDIを適用することで、これらの利点がどのように発揮されるかについて、以下で具体的に見ていきます。
1. 複数のFirebase Configを使い分け、複数のDBにアクセスするとき
まず考えられるケースとして、複数のFirebaseプロジェクトやデータベースにアクセスする必要がある場合が挙げられます。 この場合、各環境の設定に応じてFirestoreクライアントを切り替える必要があり、DIを用いると柔軟に対応可能です。
例えばNext.js App Routerで考えてみると、ページによってアクセスするDBを切り替えたいときに、app/layout.tsx
などの中でクライアントを生成し、Context経由で子孫コンポーネントに渡すみたいなことが考えられます。
2. サービスロジックの単体テストを簡便にするため
次に、サービスロジックのテストにおける利便性です。エンドツーエンド(E2E)テストではFirebaseエミュレータを使えば十分なケースが多いですが、関数の単体テストとなるとエミュレータを使うのはやりすぎ感があります。Firestoreクライアントを直接利用すると、テストコードでエミュレータ環境をセットアップする手間がかかり、単体テストが複雑になります。DIを使ってFirestoreをモックに差し替えることで、この手間を省き、より簡潔に素早く単体テストを実装できそうです。
3. 将来的にインフラを置き換える可能性があるとき
次に、Firestoreから別のデータベース、例えばNoSQLからRDBに乗り換えたい場合も考えられます。しかし、実際にはこのシナリオではDIだけで対処できるほど単純ではない可能性が高いです。NoSQLとRDBの設計の違いは大きく、データモデルやクエリの方法も大幅に変わるため、全体的な設計から考え直すことになりそうです。おそらくインフラ層のDIどころではなさそうな気がします。
4. 永続化層をリポジトリパターンで設計したいとき
最後に、永続化層をリポジトリパターンのように設計し、Firestoreへの依存をカプセル化したいケースが考えられます。しかし、このように堅牢で疎結合なソフトウェアを求めるシナリオでは、そもそもFirestoreのようなNoSQLではなく、より構造化されたデータを扱うRDBを選択することが多くなりそうです。Firestoreをリポジトリパターンに組み込む利点は少なく、そのようなプロジェクトではそもそもFirestoreを採用したくなることがあまりないかもしれません。
まとめ
FirestoreクライアントをDIしたいシチュエーションはいくつかありましたが、それぞれには具体的な条件や制約があります。複数の設定を使い分ける必要がある場合や、効率的な単体テストを行いたい場合にはDIが非常に有効です。しかし、インフラ全体を置き換えるような大規模な変更にはDIだけでは対処しきれないこと、また高い堅牢性が求められるプロジェクトではFirestore自体が選択肢から外れる可能性があることを考慮する必要があります。
FirestoreとDIの適用は状況次第ですが、プロジェクトの目的と要件に応じて、最適な選択をすることが重要です。