それでも同じこずはできたせん -長期蚭蚈のためのむンタヌフェヌスず䟝存性泚入の䜿甚

みなさんこんにちは

最終的に、Mark Simanの本「 .NETでの䟝存性泚入 」を曎新する契玄を結んでいたす 。䞻なこずは、圌ができるだけ早くそれを完成させるこずです。 線集郚には、尊敬されるDinesh RajputによるSpring 5のデザむンパタヌンに関する本もありたす。この章では、䟝存関係の実装に関する章もありたす。

私たちは、DIパラダむムの長所を思い起こさせ、それに察する関心を明確にする興味深い資料を長い間探しおいたしたが、今では発芋されおいたす。 確かに、著者はGoで䟋を提䟛するこずを奜みたした。 このトピックがあなたに近い堎合、これがあなたの圌の考えに埓うこずを劚げず、コントロヌルの反転ずむンタヌフェヌスの操䜜の䞀般原則を理解するのに圹立぀こずを願っおいたす。

オリゞナルの感情的な色付けは少し静かで、翻蚳䞭の感嘆笊の数が枛りたす。 玠敵な読曞を

むンタヌフェむスの䜿甚は理解しやすい手法であり、テストでテストしやすく拡匵しやすいコヌドを䜜成できたす。 これが最も匷力なアヌキテクチャ蚭蚈ツヌルであるず繰り返し確信しおいたす。

この蚘事の目的は、むンタヌフェヌスずは䜕か、それらがどのように䜿甚されるか、そしおそれらがどのようにコヌドの拡匵性ずテスト容易性を提䟛するかを説明するこずです。 最埌に、この蚘事では、むンタヌフェむスが゜フトりェア配信管理を最適化し、蚈画を簡玠化する方法を瀺す必芁がありたす

むンタヌフェヌス

むンタヌフェむスは契玄を蚘述したす。 蚀語たたはフレヌムワヌクに応じお、むンタヌフェヌスの䜿甚は明瀺的たたは暗黙的に指瀺される堎合がありたす。 したがっお、Go蚀語では、 むンタヌフェむスは明瀺的に指瀺されたす 。 ゚ンティティをむンタヌフェむスずしお䜿甚しようずしたが、このむンタヌフェむスのルヌルず完党に䞀臎しない堎合、コンパむル時゚ラヌが発生したす。 たずえば、䞊蚘の䟋に続いお、次の゚ラヌが衚瀺されたす。

prog.go:22:85: cannot use BadPricer literal (type BadPricer) as type StockPricer in argument to isPricerHigherThan100: BadPricer does not implement StockPricer (missing CurrentPrice method) Program exited. 

むンタヌフェむスは、呌び出し元を呌び出し先から切り離すのに圹立぀ツヌルです。これは、コントラクトを䜿甚しお行われたす。

自動亀換取匕のプログラムの䟋を䜿甚しお、この問題を特定したしょう。 トレヌダヌプログラムは、蚭定された賌入䟡栌ずティッカヌシンボルで呌び出されたす。 その埌、プログラムは取匕所に行き、このティッカヌの珟圚の盞堎を芋぀けたす。 さらに、このティッカヌの賌入䟡栌が蚭定䟡栌を超えない堎合、プログラムは賌入を行いたす。



簡略化した圢匏では、このプログラムのアヌキテクチャは次のように衚すこずができたす。 䞊蚘の䟋から、珟圚の䟡栌を取埗する操䜜は、プログラムが亀換サヌビスに接続するためのHTTPプロトコルに盎接䟝存するこずが明らかです。

Actionの状態もHTTPに盎接䟝存しおいたす。 したがっお、䞡方の状態は、HTTPを䜿甚しお亀換デヌタを抜出する方法やトランザクションを完了する方法を完党に理解する必芁がありたす。

実装は次のようになりたす。

 func analyze(ticker string, maxTradePrice float64) (bool, err) { resp, err := http.Get( "http://stock-service.com/currentprice/" + ticker ) if err != nil { //   } defer resp.Body.Close() body, err := ioutil.ReadAll(resp.Body) // ... currentPrice := parsePriceFromBody(body) var hasTraded bool var err error if currentPrice <= maximumTradePrice { err = doTrade(ticker, currentPrice) if err == nil { hasTraded = true } } return hasTraded, err } 

ここでは、呌び出し元 analyze はHTTPに盎接䟝存しおいたす。 圌女は、HTTP芁求がどのように定匏化されるかを知る必芁がありたす。 解析はどのように行われたすか。 再詊行、タむムアりト、認蚌などの凊理方法 圌女はhttpよく理解しおいhttp 。 analyzeを呌び出すたびに、 httpラむブラリも呌び出す必芁がありたす 。

ここでむンタヌフェむスはどのように圹立ちたすか むンタヌフェむスによっお提䟛されるコントラクトでは、特定の実装ではなく、 動䜜を説明できたす。

 type StockExchange interface { CurrentPrice(ticker string) float64 } 

䞊蚘は、 StockExchangeの抂念を定矩しおいたす。 ここでは、 StockExchangeが唯䞀のCurrentPrice関数の呌び出しをサポヌトしおいるず述べおいたす。 これらの3行は、私にずっお最も匷力な建築技術のようです。 アプリケヌションの䟝存関係をより自信を持っお制埡するのに圹立ちたす。 テストを提䟛したす。 拡匵性を提䟛したす。

䟝存性泚入

むンタヌフェむスの䟡倀を完党に理解するには、「䟝存性泚入」ず呌ばれる手法を習埗する必芁がありたす。

䟝存性泚入ずは、呌び出し偎が呌び出し偎が必芁ずするものを提䟛するこずを意味したす。 通垞、これは次のようになりたす。呌び出し元はオブゞェクトを構成し、呌び出し先に枡したす。 次に、着信偎が構成ず実装から抜象化したす。 この堎合、既知の調停がありたす。 HTTP Restサヌビスぞのリク゚ストを怜蚎しおください。 クラむアントを実装するには、HTTP芁求を䜜成、送信、受信できるHTTPラむブラリを䜿甚する必芁がありたす。

HTTP芁求をむンタヌフェむスの背埌に配眮した堎合、呌び出し元は切り離される可胜性があり、HTTP芁求が実際に行われたこずを「知らない」こずになりたす。

呌び出し元は、䞀般的な関数呌び出しのみを行う必芁がありたす。 これは、ロヌカルコヌル、リモヌトコヌル、HTTPコヌル、RPCコヌルなどです。 発信者は、䜕が起こっおいるのかを知らず、通垞、期埅される結果が埗られるたで完璧に圌女に合っおいたす。 以䞋は、 analyzeメ゜ッドで䟝存性泚入がどのように芋えるかを瀺しおいたす。

 func analyze(se StockExchange, ticker string, maxTradePrice float64) (bool, error) { currentPrice := se.CurrentPrice(ticker) var hasTraded bool var err error if currentPrice <= maximumTradePrice { err = doTrade(ticker, currentPrice) if err == nil { hasTraded = true } } return hasTraded, err } 

ここで起こっおいるこずに驚かされるこずはありたせん。 䟝存関係ツリヌを完党に反転し、プログラム党䜓をより適切に制埡し始めたした。 さらに、芖芚的にも実装党䜓がよりクリヌンで理解しやすくなりたした。 分析方法が珟圚の䟡栌を遞択し、この䟡栌が私たちに適しおいるかどうかを確認し、そうである堎合は取匕を行う必芁があるこずを明確に確認したす。

最も重芁なこずは、この堎合、呌び出し元から呌び出し元を切り離したす。 呌び出し元ず実装党䜓は、むンタヌフェむスを䜿甚しお呌び出されたものから分離されおいるため、さたざたな実装を䜜成しおむンタヌフェむスを拡匵できたす。 むンタヌフェむスを䜿甚するず、着信偎のコヌドを倉曎するこずなく、さたざたな特定の実装を䜜成できたす。



このプログラムの「珟圚の䟡栌を取埗」ステヌタスは、 StockExchangeむンタヌフェヌスのみに䟝存したす。 この実装は、亀換サヌビスぞの連絡方法、䟡栌の保存方法、たたはリク゚ストの䜜成方法に぀いお䜕も知りたせん。 本圓に至犏の無知。 さらに、二囜間。 HTTPStockExchange実装も分析に぀いお䜕も知りたせん。 課題が間接的であるため、分析が実行されるずきに、分析が実行されるコンテキストに぀いお。

特定の実装を倉曎/远加/削陀する堎合、プログラムフラグメントむンタヌフェむスに䟝存するものを倉曎する必芁がないため、 このような蚭蚈は耐久性がありたす。 StockService非垞に頻繁に利甚できないこずがStockServiceたす。

䞊蚘の䟋は関数の呌び出しずどのように違いたすか 関数呌び出しを䜿甚するず、実装もよりクリヌンになりたす。 違いは、関数を呌び出すずきに、HTTPに頌らなければならないこずです。 analyzeメ゜ッドは、 http自䜓を盎接呌び出すのではなく、単にhttpを呌び出す必芁がある関数のタスクを委任したす。 この手法の匷みは、「泚入」、぀たり呌び出し元が呌び出し先にむンタヌフェむスを提䟛するこずにありたす。 これは、䟝存関係の反転が発生する方法ずたったく同じです。この堎合、取埗䟡栌は実装に䟝存せず、むンタヌフェむスにのみ䟝存したす。

すぐに䜿える耇数の実装

この段階では、 analyze関数ずStockExchangeむンタヌフェむスがありたすが、実際には䟿利なこずは䜕もできたせん。 プログラムを発衚したした。 珟時点では、むンタヌフェむスの芁件を満たす単䞀の特定の実装がないため、これを呌び出すこずはできたせん。

次の図の䞻な匷調点は、「珟圚の䟡栌の取埗」状態ずStockExchangeむンタヌフェヌスぞの䟝存です。 以䞋は、2぀の完党に異なる実装が共存し、珟圚の䟡栌を取埗する方法が䞍明であるこずを瀺しおいたす。 さらに、䞡方の実装は盞互に関連しおおらず、それぞれはStockExchangeむンタヌフェヌスのみに䟝存しおStockExchangeたす。



生産

元のHTTP実装は、プラむマリanalyze実装にすでに存圚したす。 それを抜出しお、むンタヌフェヌスの特定の実装の背埌にカプセル化するだけです。

 type HTTPStockExchange struct {} func (se HTTPStockExchange) CurrentPrice(ticker string) float64 { resp, err := http.Get( "http://stock-service.com/currentprice/" + ticker ) if err != nil { //   } defer resp.Body.Close() body, err := ioutil.ReadAll(resp.Body) // ... return parsePriceFromBody(body) } 

以前に関数analyzeにリンクしおいたコヌドは自埋型になり、 StockExchangeむンタヌフェむスを満たしたす。぀たり、 analyze枡すこずができるようになりたした。 䞊蚘の図から芚えおいるように、analyzeはHTTP䟝存関係に関連付けられなくなりたした。 むンタヌフェヌスを䜿甚しお、 analyzeは舞台裏で䜕が起こるかを「想像」したせん。 圌は、 CurrentPriceを呌び出すこずができるオブゞェクトが䞎えられるこずが保蚌されるこずだけを知っおいたす。

たた、ここではカプセル化の兞型的な長所を利甚しおいたす。 以前は、httpリク゚ストが分析に結び付けられおいた堎合、httpを介しお取匕所ず通信する唯䞀の方法は、 analyzeメ゜ッドを介しお間接的でした。 はい、これらの呌び出しを関数にカプセル化し、関数を独立しお実行できたすが、むンタヌフェむスにより、呌び出し元から呌び出し元を切り離す必芁がありたす。 これで、呌び出し元に関係なくHTTPStockExchangeをテストできたす。 これは、テストの範囲ず、テストの倱敗を理解しお察応する方法に根本的に圱響したす。

テスト䞭

既存のコヌドには、 HTTPStockService構造がありたす。これにより、Exchangeサヌビスず通信し、 HTTPStockService受信した応答を解析できるこずを個別に確認できたす。 しかし、今床は、analyzeがStockExchangeむンタヌフェヌスからの応答を正しく凊理できるこず、さらに、この操䜜が信頌でき、再珟可胜であるこずを確認したしょう。

 currentPrice := se.CurrentPrice(ticker) if currentPrice <= maxTradePrice { err := doTrade(ticker, currentPrice) } 

HTTPを䜿甚した実装を䜿甚できたすが、倚くの欠点がありたす。 ナニットテストでネットワヌク呌び出しを行うず、特に倖郚サヌビスの堎合は遅くなる堎合がありたす。 遅延ず䞍安定なネットワヌク接続のために、テストは信頌できないこずが刀明する可胜性がありたす。 さらに、トランザクションを完了できるステヌトメントを䜿甚したテスト、およびトランザクションを終了すべきでないケヌスを陀倖できるステヌトメントを䜿甚したテストが必芁な堎合、これらの䞡方を確実に満たす実際の本番デヌタを芋぀けるこずは困難です条件。 maxTradePrice遞択するこずもできたす。たずえば、 maxTradePrice := -100堎合、この条件で各条件を人為的に暡倣したす。トランザクションは完了せず、 maxTradePrice := 10000000は明らかにトランザクションで終了したす。

しかし、亀換サヌビスで特定のクォヌタを取埗するずどうなりたすか たたは、アクセス料金を支払う必芁がある堎合 単䜓テストに関しおは、クォヌタを実際に支払うか、䜿うべきでしょうか 理想的には、テストはできるだけ頻繁に実行する必芁がありたす。そのため、テストは高速で、安䟡で、信頌できるものでなければなりたせん。 この段萜から、玔粋なHTTPを備えたバヌゞョンを䜿甚するこずがテストの芳点から非合理的である理由は明らかだず思いたす

より良い方法があり、むンタヌフェヌスを䜿甚する必芁がありたす

むンタヌフェヌスがあれば、 StockExchange実装を慎重に補造できたす。これにより、迅速、安党、確実にanalyzeするこずができたす。

 type StubExchange struct { Price float64 } func (se StubExchange) CurrentPrice(ticker string) float64 { return se.Price } func TestAnalyze_MakeTrade(t *testing.T) { se := StubExchange{Price: 10} maxTradePrice := 11 traded, err := analyze(se, "TSLA", maxTradePrice) if err != nil { t.Errorf("expected err == nil received: %s", err) } if !traded { t.Error("expected traded == true") } } func TestAnalyze_DontTrade(t *testing.T) { se := StubExchange{Price: 10} maxTradePrice := 9 traded, err := analyze(se, "TSLA", maxTradePrice) //  } 

亀換サヌビスのスタブが䞊蚘で䜿甚されおいるanalyze 、 analyzeずなるブランチが起動されたす。 次に、分析が必芁なこずを実行するこずを確認するために、各テストでステヌトメントが䜜成されたす。 これはテストプログラムですが、私の経隓では、むンタヌフェむスがほがこのように䜿甚されるコンポヌネント/アヌキテクチャは、バトルコヌドの耐久性に぀いおもこの方法でテストされるこずを瀺唆しおいたす!!! むンタヌフェヌスのおかげで、メモリ制埡のStockExchange䜿甚できたす。これは、信頌性が高く、蚭定が容易で、理解しやすく、再珟性があり、超高速のテストを提䟛したす!!!

固定解陀-発信者蚭定

むンタヌフェむスを䜿甚しお呌び出し元を呌び出し先から切り離す方法、および耇数の実装を行う方法に぀いお説明したので、重芁な点に぀いおはただ觊れおいたせん。 厳密に定矩された時間に特定の実装を構成および提䟛する方法は 分析関数を盎接呌び出すこずができたすが、実皌働構成で䜕をする必芁がありたすか

これは、䟝存関係の実装が圹立぀堎所です。

 func main() { var ticker = flag.String("ticker", "", "stock ticker symbol to trade for") var maxTradePrice = flag.Float64("maxtradeprice", "", "max price to pay for a share of the ticker symbol." se := HTTPStockExchange{} analyze(se, *ticker, *maxTradePrice) } 

テストケヌスず同様に、 analyzeで䜿甚されるStockExchangeの具䜓的な実装は、analyze以倖の呌び出し元によっお構成されたす。 次に、 analyze枡されたす泚入されたす。 これにより、 HTTPStockExchangeどのように構成されおいるかに぀いおNOTHINGが分析されおいるHTTPStockExchangeたす。 おそらく、コマンドラむンフラグずしお䜿甚するhttpドメむンを提䟛したいので、analyzeを倉曎する必芁はありたせん。 たたは、環境から抜出されるHTTPStockExchangeにアクセスするために䜕らかの認蚌たたはトヌクンを提䟛する必芁がある堎合はどうでしょうか 繰り返したすが、分析は倉曎しないでください。

蚭定はanalyze以倖のレベルで行われるanalyze 、analyzeは独自の䟝存関係を蚭定する必芁がありたせん。 したがっお、職務の厳密な分離が達成されたす。



棚の決定

おそらく䞊蚘の䟋で十分ですが、むンタヌフェヌスや䟝存性泚入には他にも倚くの利点がありたす。 むンタヌフェむスにより、特定の実装に関する決定を延期するこずができたす。 決定には、サポヌトする動䜜を決定する必芁がありたすが、特定の実装に぀いおは埌で決定できたす。 自動トランザクションを行いたいず思っおいたが、どの芋積プロバむダを䜿甚するかただわからなかったずしたす。 デヌタりェアハりスを䜿甚する堎合、同様のクラスの゜リュヌションが垞に扱われたす。 私たちのプログラムは䜕を䜿うべきですかmysql、postgres、redis、ファむルシステム、cassandra 最終的に、これはすべお実装の詳现であり、むンタヌフェむスにより、これらの問題に関する最終決定を延期できたす。 これにより、プログラムのビゞネスロゞックを開発し、最埌に特定の技術゜リュヌションに切り替えるこずができたす

この手法だけでも倚くの可胜性が残されおいるずいう事実にもかかわらず、プロゞェクト蚈画のレベルで䜕か䞍思議なこずが起こりたす。 Exchangeむンタヌフェむスに別の䟝存関係を远加するずどうなるか想像しおみおください。



ここでは、非埪環有向グラフの圢匏でアヌキテクチャを再構成したす。これにより、亀換むンタヌフェむスの詳现に同意するずすぐに、 HTTPStockExchangeを䜿甚しお、パむプラむンをHTTPStockExchangeし続けるこずができたす。 私たちは、プロゞェクトに新しい人を远加するこずで、より速く動くこずができる状況を䜜り出したした。 このようにアヌキテクチャを埮調敎するこずで、プロゞェクト党䜓の配信を促進するために、プロゞェクトに远加の人をどこで、い぀、どのくらいの期間埓事させるこずができるかをよりよく把握できたす。 さらに、むンタヌフェむス間の接続が匱いため、通垞、実装むンタヌフェむスから始めお䜜業に参加するのは簡単です。 プログラムずは完党に独立しお、 HTTPStockExchange開発、テスト、テストできたす

アヌキテクチャの䟝存関係を分析し、これらの䟝存関係に基づいお蚈画するこずで、プロゞェクトを倧幅に加速できたす。 この特定の手法を䜿甚しお、数か月間割り圓おられたプロゞェクトを非垞に迅速に完了するこずができたした。

先に

これで、むンタヌフェむスず䟝存関係の泚入により、蚭蚈されたプログラムの耐久性がどのように保蚌されるかがより明確になりたす。 芋積プロバむダヌを倉曎するか、クォヌタのストリヌミングを開始しおリアルタむムで保存するずしたす。 あなたが奜きなだけ他の倚くの可胜性がありたす。 珟圚の圢匏のanalyzeメ゜ッドは、 StockExchangeむンタヌフェむスずの統合に適した実装をサポヌトしたす。

 se.CurrentPrice(ticker) 

したがっお、倚くの堎合、倉曎せずに実行できたす。 すべおではありたせんが、私たちが遭遇する可胜性のある予枬可胜なケヌスでは。 analyzeコヌドを倉曎し、その䞻芁機胜を再確認analyze必芁性から免れるだけでなく、新しい実装を簡単に提䟛したり、サプラむダを切り替えたりするこずができたす。 たた、 analyzeを倉曎したりダブルチェックしたりするこずなく、すでにある特定の実装をスムヌズに拡匵たたは曎新できたす

䞊蚘の䟋が、むンタヌフェむスを䜿甚しおプログラム内の゚ンティティ間の接続を匱めるず、䟝存関係が完党に再構築され、呌び出し元ず呌び出し元が分離されるこずを玍埗できるように瀺しおくれるこずを期埅しおいたす。 この分離のおかげで、プログラムは特定の実装に䟝存したせんが、特定の動䜜に倧きく䟝存したす 。 この動䜜は、さたざたな実装で提䟛できたす。 この重芁な蚭蚈原則は、 カモタむピングずも呌ばれたす 。

むンタヌフェヌスずいう抂念ず、実装ではなく振る舞いぞの䟝存は非垞に匷力なので、むンタヌフェヌスを蚀語プリミティブず芋なしたす-はい、これは非垞に急進的です。 䞊蚘の䟋が非垞に説埗力のあるものになり、プロゞェクトの最初からむンタヌフェヌスず䟝存関係の泚入を䜿甚するこずに同意するこずを願っおいたす。 私が取り組んだほずんどすべおのプロゞェクトでは、1぀ではなく、少なくずも2぀の実装実皌働甚ずテスト甚が必芁でした。

Source: https://habr.com/ru/post/J428075/


All Articles