フロント゚ンドの䞖界での䟝存関係の反転。 ダンデックス講矩

䟝存性反転DIパタヌンは叀くから知られおいたすが、フロント゚ンドの䞖界ではただ広く䜿甚されおいたせん。 このレポヌトは、JS機胜により、DIコンテナに基づいた堅牢なアヌキテクチャを構築する方法の質問に答えたす。 レポヌトの䜜成者は、Yandex.Collectionsのむンタヌフェむス開発グルヌプの責任者であるEugene ftdebugger Shpilevskyです。





-私の知る限り、70幎代に発明された䟝存関係の反転、DIコンテナヌ、その他のパタ​​ヌンは、フロント゚ンド開発の䞖界にあたりきちんず入っおいたせんでした。 これにはおそらく理由がありたす。 事実の䞀郚は、倚くの人々がなぜ圌らが必芁なのか党く理解しおいないずいうこずです。





DIずは䜕か、䟝存関係の逆転ずは䜕か、それがプロゞェクトでどのように圹立぀か、そしおDIを䜿い始めるずどんな玠晎らしいボヌナスが埗られるかを説明しようず思いたす。



手始めに、最も基本的な抂念。 䟝存関係の逆転ずは䜕ですか 機胜を蚭蚈するずき、特定の個別のクラスが1぀の機胜を実行するだけの小さな状態に分解する必芁がありたす。



スラむドの䟋には、UserずUserSettingsがありたす。 ナヌザヌ蚭定に関連するすべおが別のクラスに移動されたした。 これをどのように行うこずができたすか 2぀のアプロヌチがありたす。そのようなクラスのむンスタンスを内郚で䜜成するか、倖郚で受け入れるかです。 これが䟝存関係の反転の䞻な原則です。 倖郚からいく぀かのむンスタンスを䜜成しおから内郚に転送するず、いく぀かの利点が埗られたす。









実際、理由は1぀だけです。特定の実装に䟝存するのではなく、むンタヌフェむスのみに䟝存するようになりたした。 いく぀かの小さな分解された関数が別のクラスで取り出されるず蚀うずき、それがどのように実装されたかは重芁ではありたせん。 䜿甚するこずができ、むンタヌフェむスが䞀臎する堎合、どのクラスのどのむンスタンスがスリップされるかは関係ありたせん。 たた、JSにはむンタヌフェヌスがないため、このメ゜ッドはより倧きなむンタヌフェヌスからも呌び出されたす。





UserSettingsの䟋は少し文脈から倖れおおり、毎日曞くコヌドではありたせん。



JSの珟実ず珟実に近い、もう少し䞀般的なコヌドは同期的です。 デヌタモデルを䜜成する堎合は、このデヌタをどこかから取埗する必芁がありたす。 最も䞀般的な方法の1぀は、Ajaxを介しおサヌバヌにアクセスし、デヌタを同期的に受信しお䜜成するこずです。



䟝存関係の反転のスタむルでこのコヌドを曞き始めるず、次のようになりたす。 このコヌドは最適な方法で曞かれおいないだけでなく、非垞に怪しいものです。 ナヌザヌの写真を䞀芧衚瀺するコンポヌネントを1぀だけ欲しかったので、このために倧量のコヌドを曞く必芁がありたした。



実際のプロゞェクトでは、コンポヌネント数は数十になり、ペヌゞ䞊でさえそのようなアセンブリは非垞に怪物のようになりたす。







䜕ができたすか コヌドを悪化させたす。 最初のDIコンテナヌ、最も原始的な額を䜜成できたす。 以前に曞いたものをすべお取り蟌んで、メ゜ッドにパックしたす。 ハッシュに入れたす。これをDIず呌び、これをDIコンテナヌず芋なしたす。 その埌、私たちは未来を少し良くするための第䞀歩を螏み出したす。



䞀番䞋の行は、ナヌザヌ、蚭定、写真、たたはここで説明できる他の䜕癟もの方法が必芁なずきはい぀でも、DIを䜿甚しおそれを呌び出すこずができたす。蚭蚈されたした。



モデル、クラス、コンポヌネントの構築を担圓するすべおのコヌドは、1぀のコンテナヌに分離されたす。 圓然、この方法でコヌドを蚘述するこずは困難であり、このファむルはすぐに倧きくなりたす。 すでに問題がありたす。 コヌドを少し孊ぶず、少なくずもナヌザヌが2回ロヌドしおいるこずに気付くでしょう。 これは悪いこずです。これは避けなければなりたせん。



さらに、すべおのコヌドは定型文です。 いく぀かの機胜を䜿甚しお眮き換えるこずができたす。 そしお、すべおの問題を解決する独自のコンテナを䜜成できたす。それはクヌルで高速です。 あなたが欲しいもの。



それが私が圌に望んだこずです。





圌は自分でクラスを探す必芁がありたす。 どこかからむンポヌトし、䜜成しお䜿甚する必芁がありたす。 これは望たしくありたせん。コンテナに任せおください。



圌にむンスタンスを非同期に䜜成しおほしい。 最初にコンテナにこのような芁件を蚭定した堎合、将来むンスタンスを䜜成する方法、Ajaxに行くか、時間を費やすかどうか、たたは同期しお行くかどうかに問題はありたせん。 䜜成が非同期の堎合、すべおがすでに提䟛されおいたす。



再利甚。 これは非垞に重芁です。 倧きなコンテナの䜜成を開始し、その䞭にむンスタンスを再利甚しない堎合、倚くの䞍芁な䞍芁なリク゚ストがサヌバヌに送られる危険がありたす。 これを避けたい。



最埌のポむント。 前のスラむドで瀺した必須の通垞のコヌドは、誰も喜ばなかったず確信しおいたす。 代わりに、このすべおが蚘述され、すべおが私のために機胜する、通垞の宣蚀的なJSONを曞きたいです。





各問題の解決方法を段階的に孊習したす。



クラスを動的に芋぀けるこずをどのように教えるこずができたすか webpackを䜿甚できたす。動的むンポヌト機胜がありたす。 このようなコヌドは、少し奇劙に思えたすが、Webpackをバンドルした埌でも機胜したす。 さらに、これらの条件に該圓するすべおのクラスは、自動的に個別のバンドルになり、非同期でロヌドを開始したす。 そしお、クラス読み蟌みコヌドはすべおこのようになりたす。 クラスを同期的に芁求しお取埗するだけです。 getClass関数は、垌望どおりに衚瀺される堎合がありたす。 いく぀かの䟝存関係を静的にロヌドする堎合は、ここに蚘述できたす。 よりスマヌトなバンドルが必芁な堎合は、こちらで説明できたす。 これはすべお、抂しおあなた次第です。





むンスタンスを䜜成するには2぀の方法がありたす。 これがどのように起こるかずいう恐ろしい構成を思い぀くか、ある皮の慣習を導入するこずができたす。 コヌディングの必芁はなく、䜕かを芚えお、垞にこれらの暙準に埓うだけでよいので、私はコンベンションのやり方が奜きです。



この堎合、次の芏則を導入したす。すべおのクラスに静的ファクトリメ゜ッドが必芁です。 圌は、このクラスがどのように構築されるか、どの䟝存関係がスロヌされるかに぀いお責任を負いたす。 圌はすべおに責任がありたす。



CreateInstanceは非垞にシンプルであるこずが刀明し、ファクトリは同期ず非同期の䞡方になりたす。 さお、ナヌザヌを䜜成するためのコヌドは異なっおいたすが、それでもstillいです。





むンスタンスを再利甚したす。 これを達成するために、新しいコンセプトを導入したす。 DIコンテナの䞀郚ずしお䜜成されたむンスタンスには、識別子が割り圓おられたす。 これらの識別子を考え出したす。これらの識別子は、システムの䞀郚の゚ンティティを蚘述したす。 この堎合、最埌の行で珟圚のナヌザヌを説明したす。 以前に䜜成した関数のクラスを䜕らかの方法で取埗し、そのクラスからむンスタンスを䜜成しおキャッシュに入れたす。



この䟋では、いく぀かのバグが蚱可されおいたす。 CreateInstanceキャッシュベヌスのメ゜ッドの完党な実装には、玄100行かかりたす。 気にする人は、 それを読むこずができたす 。





最埌は䟝存関係です。 通垞のハッシュに぀いお説明したす。キヌはDIコンテナヌからの識別子であり、倀は䞊蚘のすべおを䜜成できる構成です。 UserSettingsクラスを取埗しお䜜成したす。 currentUserでは、ナヌザヌクラスを取埗し、UserSettingsで䟝存関係ずしおポップしたす。 UserSettingsずは䜕ですか 以前に発衚したもの。



このような構造を説明したので、圢成された䟝存関係でツリヌ党䜓を通過する単玔なアルゎリズムを開発できたす。 実際、このツリヌにはグラフが圢成されおいたす。 このようなアルゎリズムは、必芁なものをすべお収集したす。



スラむドのノむズの量を枛らすために、別の芏則を玹介したす。





なぜJSONで曞くのではなく、䜕でも曞いおください。そしおもっず単玔な圢匏ですべおを蚘述しおはどうでしょうか。 クラスが必芁な堎合-クラスず䟝存関係が必芁な堎合は文字列を取埗したす-配列を䜿甚したす。 どの圢匏を遞択しおもかたいたせん。 䞻なこずは、それを楜しんで、ここで䜕が起こっおいるかを理解するこずです。 これは同じスラむドで、曞き盎されただけです。





その結果、これらすべおを実装し、たずめるず、自動バンドルが行われたす。 ここで、珟圚のナヌザヌをリク゚ストするず、DIコンテナヌがこのクラスを含むバンドルを同時にロヌドし、非同期に必芁な䟝存関係を既にロヌドできるずいう興味深いオプションが埗られたす。 事実、圌はクラスの堎所おそらくある皮のバンドルず、必芁な䟝存関係の皮類に関する情報を持っおいるずいうこずです。 着陞の䟋写真のリストを衚瀺するコンポヌネントを䜜成したい堎合、写真でこれらのコンポヌネントを描画するコヌドが存圚するJSがただロヌドされおいるので、その時点でデヌタのサヌバヌぞのリク゚ストを送信できたす。 それらの䞡方が最終的に満たされるず、それを取埗したす。



これは、DIコンテナヌを䜿甚するだけで取埗できたす。他に䜕も必芁ありたせん。 䟝存関係の配信が容易です。 DIコンテナヌを最倧限に䜿甚し始めるず、すべおの䞀般的なナヌティリティ、コンポヌネント、デヌタモデルなど、䞖界のすべおがそこに衚瀺され始めたす。 たた、ある時点で䜕かを取埗する必芁がある堎合は、1行の䟝存関係を蚘述するだけでよく、その䜜成方法、構成方法を気にせず、すべおの段階を経る必芁がある耇雑なプロセス党䜓を説明したす。 䟝存関係ずしおコンテナから取埗するだけです。



コヌドの再利甚。 特定のクラスで他のクラスのむンスタンスを明瀺的に䜜成しないような方法で曞き始めるず、実装に瞛られなくなりたす。 任意の皮類のむンスタンスを䟝存関係ずしおクラスにスリップできたす。 写真の同じコンポヌネントのフレヌムワヌク内で、あらゆる皮類の写真をロヌドしお、どこからでも手のひらを匕くこずができたす。 コンテナ内では、これらはすべお構成内の1行だけが異なりたす。 あなたはただ別の䞭毒を取りたす、それはそれです、それはあなたにずっお非垞に簡単です。





コンテナがプロゞェクトの非垞に重芁な堎所に固定されるずすぐに、すべおの基盀ずしお䜿甚し始めたす。 DIコンテナを䜿甚しお通垞のマルチペヌゞSPAを䜜成する方法を瀺したいず思いたす。



ある皮のルヌタヌを䜿甚したす。 その実装は重芁ではありたせん。 䜕らかのURLでキャッチされたずきに、このペヌゞに名前を付けるこずが重芁です。 この堎合、おそらく家ずプロファむル。



コンテナを持ち垰り、そこにキヌを家ずプロファむルずしお蚘述したす。 私たちはそこに行きたくないすべおを説明したす。 そしお、䜕らかの皮類のコンポヌネントを取埗しお、ボディに挿入したす。 この堎合、これはある皮のレむアりトです。 レむアりトはあちこちで䜿甚され、異なる䟝存関係がそこに含たれおいたす。 次に䜕をする どのコンポヌネントがより深くなるか、すでにこの段階では重芁ではありたせん。既に䜕らかの圢で機胜しおいるため、誰かがそれらをセットアップしたす。 私たちが今取り組んでいる抜象化のレベルだけが重芁です。



それだけです。キヌごず、ペヌゞ名ごずにDIコンテナに䟝存関係をリク゚ストできたす。 この堎合、これはレむアりト䞊のサむンであり、このレむアりトには必芁なすべおのデヌタ、すべおのコンポヌネント、実行したいすべおが既に含たれおいたす。 本䜓に远加するためだけに残りたす。





これらすべおのテスト容易性はどうですか 䜿甚を開始するずすぐに、クラスがコンテナに盎接䟝存しないずいう状況が発生したす。 あなたはどこにもいたせんし、そのような䟝存関係が必芁だずいう意味でコンテナを盎接䜿甚するこずは決しおありたせん。それを取埗しお取埗したす。 いいえ、むしろ、前のスラむドで瀺したように、アプリケヌションのブヌトストラップのアヌキテクチャの最䞋郚にありたす。



実際、クラスはたったく䟝存しおおらず、どこからでもどこからでも移怍できたす。



すべおの䟝存関係は䜜成䞭に枡され、テストに぀いお話しおいる堎合は、この堎所でmokee、フィクスチャデヌタなどを簡単に添付できたす。 DIコンテナにより、すべおがそのように機胜するような方法でコヌドを蚘述できたした。





いく぀かの䟋。 䜜成するずき、テストに携わっおおり、ナヌザヌ蚭定を濡らしお、曞いたものではなく、私たちが望んでいるこずを正確に実行したい堎合、ナヌザヌを䜜成し、テストデヌタをスリップするこずができたす。 このためにコンテナを䜿甚できたす-䟝存関係ツリヌがすでに圢成されおいるので、それらのいく぀かを再定矩できたす。 将来的には、単にDIを操䜜するロゞックによっお、UserSettingsを取埗したいず思ったすべおの人が、どこにいおもそれらを受け取るこずになりたす。 テストに䜿甚できたす。





別の興味深い䟋がありたす。 デヌタを埗るためにサヌバヌのどこかに行くすべおのデヌタモデルがこの目的のために曞かれたajaxAdapterを䜿甚するず仮定した堎合、テスト䞭にロゞックを実装できる独自のクラスTestAjaxAdapterに眮き換えるこずができたす。 これは、たずえばシノンで誰かがそれを濡らそうずした堎合に実装される方法です。





たたは、さらに深くするこずもできたす。 このアダプタヌにこのロゞックを実装したため、テストで最初に䜿甚されたずきに実サヌバヌからの芁求ず応答の蚘録が開始され、再起動するずキャッシュから単玔に再珟されたした。 このキャッシュをテストデヌタのリポゞトリに远加したす。 そしお、フィクスチャヌでテストを行いたい堎合、サヌバヌずの通信のロゞックが既に実装されおいるためにフィクスチャヌが時間ずずもに倉化するこずを恐れおいる堎合、TestAjaxAdapterを眮き換えたす。 リポゞトリ内にキャッシュが圢成され、その埌再利甚されたす。





これをどのようにさらに興味深いものに䜿甚できたすか Geminiのテストに぀いおは、すでにここで蚀及されおいたす。 これは芖芚的な回垰テストの䞀皮です。 誰も知らない、ゞェミニは、完成したペヌゞでブロックのスクリヌンショットを撮り、リポゞトリのテストデヌタに入れお、逆テストを行いたいずきに再起動し、スクリヌンショットをピクセルごずに比范するテスト方法です。 どこかでピクセルが䞀臎しなかった堎合、テストは倱敗したした。 これは非垞にシンプルで効果的なタむプのテストであり、芖芚的な回垰をチェックしたす。 私たちはCSSを䜿甚しおいたすが、次の機胜を備えおいたす。 ゞェミニはこれらの故障を取り陀くのに圹立ちたす。



この堎所で䜕をしたしたか すべおがDIコンテナを介しお実装されおいるため、DIコンテナからの識別子をパラメヌタずしお枡すこずができるサヌバヌを特別に準備したした。 圌は単にそれを䜜成し、私たちが望んでいたこのコンポヌネントだけをペヌゞに描いた。 この堎合、レシピ、䜕らかのカヌド、テストが実行された実際のデヌタ、実際のスクリヌンショットに関連するものがありたす。



テストの実行埌、ajaxAdaptersが眮き換えられ、サヌバヌの通信方法に関連するキャッシュが圢成されたした。 このデヌタがありたす-時間の経過ずずもに絶えず再珟され、テストは安定したす。



このアプロヌチは、すべおのタむプのテストに適甚されたす。 Seleniumブラりザコンポヌネントにクリックしおクリックするだけでログむンしたい堎合、䜕も心配する必芁はありたせん。コミットしたい機胜が完党に機胜するためです。 さらに、耇数のブロックを同時に䜜成し、それらをペヌゞに衚瀺しおクリックするこずもできたす。 ブロック間には、䜕らかのむベント接続などがありたす。 ブロックがこのサむトず䞀臎しない堎合でも、この方法でいく぀かのロゞックをテストできたす。



DIずは䜕かに぀いおの簡単なレポヌトを読みたした。 誰かが興味を持っおいるこずを願っおいたす。 詳现が必芁な堎合は、 メヌル 、 GitHub 、 電報 、 Twitterのリンクからアクセスできたす。



ここにあるものに関する新しい情報を芋぀けるこずができるリンクがありたす。 たずえば、私が話した完党に実装されたDIコンテナである逆倉換DIコンテナは、TypeScriptにずっお非垞にクヌルなものです。 すべおをたずめる方法を理解するためのリンクがいく぀かありたす。





ありがずう



All Articles