新マイクロサービスのアーキテクチャーにNode.jsとTypeScriptを導入したのですが、そちらの基盤技術としてInversifyを導入したらめちゃくちゃ良かったので、使い方含めて紹介します。Injection)を達成するためのコンテナのことです。}}とあったときに、Hoge::get()はFugaがnewされないと処理を実行できないため、例えばこの関数をユニットテストしたいときに、Fugaのコンストラクタの実装に依存してしまいます。コンストラクタ上でデータストアに接続するような処理がある場合、テスト環境にもデータストアの環境を整備しなければならず、本来やりたかったこと以上のことをする必要があり、面倒でありメンテコストも上がってしまいます。}}って外部から注入してあげれば、例えばfugaをモックしたオブジェクトを外から注入してあげるだけで上記の問題が解決します。これがいわゆるDIと呼ばれるものです。呼び出し元でnewすれば注入できるわけですが、そうすると呼び出し元がFugaに依存するようになってしまい、処理がより複雑になってしまいます。CleanArchitectureなどに代表される、多層化されたアーキテクチャーを採用する場合、この問題はより顕著になり、下記のようになってしまいます。{}また、どのクラスをnewすればいいかという観点において、基本的にはアプリケーションごとに唯一のクラスが指定できればいい(通常はモックなしのもの、テスト時はモックありのもの)はずなので、どこかで定義できてしまえば解決します。これを解決するために、newする処理を一つのコンテナ(オブジェクト、グローバル変数のようなもの)に集約することによって、依存性解決をわかりやすくしようというのが、DIコンテナの役割となります。Inversifyを使った方法DIコンテナは各言語、フレームワークごとに独自で実装されていたりするのですが、TypeScriptではInversifyというライブラリがあります。これは、TypeScriptのアノテーションを使うことによって、DIコンテナを実現してくれます。TypeScriptベースで作られているため、型安全に実装できるのがポイント。JavaScriptでも使用できるため、TSユーザじゃなくても使うことができるのが魅力的です。--saverefrect-metadataというものも必要なので、注意。refrect-metadataはグローバルのシングルトンなので、一度だけimportするようにしましょうtsconfig.jsonには下記のように入れていきましょう。}}使用方法まず先に実装クラスと、対応するinterfaceを実装します。今回はDB接続を想定した設計でやってみます。User;}次にDIで用いる識別子を登録していきます。Symbolで実装することを推奨しているようです。TYPES;最後に実装していきます。DIされるクラスには@injectableデコレータを、DIするインスタンスは@injectデコレータをつけていきます。}}こちらを見てもらえれば分かる通り、UserControllerはどのDBの実装クラスが使われているかも、どのUserRepositroyのインスタンスを使うかも気にすることなく、直下のUserRepositoryInterfaceを継承する何かを使うという処理を書くだけで終了します。シングルトンで登録container.bind<UserRepositoryInterface>(TYPES.UserRepo).to(UserRepository);container.bind<UserController>(TYPES.UserCntl).to(UserController);最後にコンポジションルート(最上位のmain処理)に依存性解決の処理を記載します。AWSにはDocumentDBというMongoDB互換のDBがあります。こちらのDBはほとんどMongoDBと同等なのですが、TLS接続が標準であり安全性のために必須にしているかと思います。ローカルではTLS接続はしたくないといったパターンの場合、上記でいうconnect()の関数だけ変更したくなります。いった場合は、下記のように専用のクラスを作り、inversify.config.tsを変更するだけです。Mongo());たったこれだけで本番環境と開発環境でデータストアを切り替えることができます。テストで使いたいテスト環境で使いたい場合も非常にシンプルです。下記のように注入したいモックオブジェクトを作成し、それを注入するだけです。});});また、この他containerにはrebindという関数もあるため、テスト全体で用いるinversify.config.tsを予め用意しておき、テスト専用のモックをrebindで新たにbindした上でテストを行うことによって、多層的な依存関係のクラスのテストも容易になります。まとめ今回はTypeScriptでinversifyを使ったDIコンテナの紹介をさせていただきました。軽量なアプリケーションではこのようなアーキテクチャは不要かもしれませんが、変化が激しい、レイヤーが複数あるアプリケーションや、外部との接続が多いBFFのようなものを実装する際は、処理の実行確認が非常に難しくなるため、使える技術かなと思っています。