Rubyアプリケーションのスケーリングのための効果的な依存性注入





Habréのブログでは、当社の製品の開発について話しているだけでなく、Hydraの通信事業者への請求だけでなく、インフラストラクチャの操作と他社の経験からのテクノロジーの使用に関する資料も公開しています。 プログラマーであり、オーストラリアの開発スタジオであるIcelabのリーダーの1人であるTim Rileyが、企業ブログへのRuby依存関係の実装に関する記事を執筆しまし



前の部分で、 Rileyは、依存関係注入を使用して、 チームパターンを実装する小さな再利用可能な機能オブジェクトを作成するアプローチについて説明しました。 実装は比較的単純で、コードのかさばる部分がなく、3つのオブジェクトのみが連携して動作することが判明しました。 この例では、1つまたは200ではなく、1つまたは2つの依存関係の使用について説明します。



依存関係の注入が大規模なインフラストラクチャーでも機能するために必要なのは、 制御反転備えたコンテナーのみです。



この時点で、Rileyは依存性注入を使用するCreateArticleコマンドのコードを提供します。



class CreateArticle attr_reader :validate_article, :persist_article def initialize(validate_article, persist_article) @validate_article = validate_article @persist_article = persist_article end def call(params) result = validate_article.call(params) if result.success? persist_article.call(params) end end end
      
      





このコマンドは、コンストラクターで依存性注入を使用して、 validate_article



およびpersist_article



persist_article



これは、必要に応じて依存関係を使用できるように、ドライコンテナー(逆制御を使用したコンテナーの半分の実装として使用するように設計された単純なスレッドセーフコンテナー)の使用方法を説明しています



 require "dry-container" #   class MyContainer extend Dry::Container::Mixin end #    MyContainer.register "validate_article" do ValidateArticle.new end MyContainer.register "persist_article" do PersistArticle.new end MyContainer.register "create_article" do CreateArticle.new( MyContainer["validate_article"], MyContainer["persist_article"], ) end #   `CreateArticle`    MyContainer["create_article"].("title" => "Hello world")
      
      





ティムは、類推を使用して制御の反転を説明します-アプリケーション内のオブジェクトへのアクセスを制御する1つの大きな連想配列を想像してください。 前述のコードフラグメントでは、3つのオブジェクトがブロックを使用して登録され、その後の処理時に作成されました。 ブロックの遅延計算は、コンテナ内の他のオブジェクトにアクセスするためにそれらを使用することが引き続き可能であることも意味します。 このようにして、 create_article



作成時に依存関係が渡されます。



MyApp::Container["create_article"]



を呼び出すと、オブジェクトが完全に構成され、使用できる状態になります。 コンテナがあると、オブジェクトを一度登録して、将来それらを再利用できます。



dry-container



は、多数のオブジェクトの処理を容易にするために、名前空間を使用せずにオブジェクトを宣言することをサポートしています。 実際のアプリケーションでは、説明した例にある単純な識別子の代わりに、名前空間「articles.validate_article」と「persistence.commands.persist_article」が最もよく使用されます。



ただし、大規模なアプリケーションではすべてが順調です。多くの定型コードを避けたいと思います。 この問題は2段階で解決できます。 最初の方法は、依存関係をオブジェクトに自動的に注入するシステムの使用です。 dry-auto_inject (必要に応じて依存関係を解決するメカニズム)を使用すると、次のようになります。



 require "dry-container" require "dry-auto_inject" #   class MyContainer extend Dry::Container::Mixin end #         MyContainer.register "validate_article", -> { ValidateArticle.new } MyContainer.register "persist_article", -> { PersistArticle.new } MyContainer.register "create_article", -> { CreateArticle.new } #   AutoInject    AutoInject = Dry::AutoInject(MyContainer) #    CreateArticle class CreateArticle include AutoInject["validate_article", "persist_article"] # AutoInject    `validate_article` and `persist_article` def call(params) result = validate_article.call(params) if result.success? persist_article.call(params) end end end
      
      





自動実装メカニズムを使用すると、コンテナでオブジェクトを宣言する際の定型コードの量を減らすことができます。 宣言時にCreateArticle.new



メソッドに渡すための依存関係のリストを作成する必要はありません。 代わりに、クラスで直接依存関係を定義できます。 AutoInject[*dependencies]



を使用するプラグインは、コンテナから依存関係を「プル」して使用できるようにする.new



#initialize



およびattr_readers



を定義します。



使用される場所で依存関係を宣言することは、コンストラクタ定義を必要とせずに共有オブジェクトを理解できるようにする非常に強力なキャストです。 さらに、依存関係のリストを単純に更新することが可能になります-これは、オブジェクトによって実行されるタスクが時間とともに変化するため便利です。



説明した方法はかなりエレガントで効率的ですが、最後のコード例の冒頭で使用したコンテナの宣言方法について詳しく説明する価値があります。 この宣言は、必要なすべての依存関係管理機能を備え、 dry-container



およびdry-auto_inject



基づいたシステムであるdry-component



で使用できます。 このシステム自体は、アプリケーションのすべての部分で制御反転を使用するために必要なものを制御します。



彼女の記事では、ライリーはこのシステムの1つの側面である自動依存関係宣言に個別に焦点を当てています。



3つのオブジェクトがファイルlib/validate_article.rb



lib/persist_article.rb



、およびlib/create_article.rb



定義されているとします。 これらはすべて、最上位ファイルmy_app.rb



特別な設定を使用して、コンテナーに自動的に含めることができます。



 require "dry-component" require "dry/component/container" class MyApp < Dry::Component::Container configure do |config| config.root = Pathname(__FILE__).realpath.dirname config.auto_register = "lib" end #  "lib/"  $LOAD_PATH load_paths! "lib" end #    MyApp.finalize! #       MyApp["validate_article"].("title" => "Hello world")
      
      





これで、プログラムが同じコード行を含まなくなり、アプリケーションは引き続き機能します。 自動登録は、単純なファイルとクラス名の変換を使用します。 ディレクトリは名前空間に変換されるため、開発者はlib/articles/validate_article.rb



ファイル内のArticles::ValidateArticle



クラスを、追加のアクションなしでarticles.validate_article



コンテナで利用できます。 これにより、Ruby on Railsへの変換に似た便利な変換が提供され、クラスの自動ロードに問題はありません。



dry-container



dry-auto_inject



、およびdry-component



は、依存性注入によって簡単に接続される小さな個々のコンポーネントで作業するために必要なすべてです。 これらのツールを使用すると、アプリケーションの作成が簡素化され、さらに重要なことに、アプリケーションのサポート、拡張、および再設計が容易になります。



ラテラからの他の技術記事:






All Articles