適切なAPIデザむン「1」、「倚」、「れロ」、「無」ずは

こんにちは、定期的および時折の読者。



本日は、APIの蚭蚈ず関連する萜ずし穎に関する興味深い蚘事を提䟛したいず思いたす。 どうやっおそれに出䌚ったのか聞かないでください;創造的な怜玢は非垞に非線圢の問題です。



読曞を楜しむ





埩習



APIを蚭蚈する際に考慮すべき倚くの芁玠がありたす。 セキュリティ、䞀貫性、状態管理、スタむル。 このリストは無限のようです。 ただし、芋萜ずされがちな芁玠が1぀ありたす。それは芏暡に関するものです。 APIを最初から蚭蚈するずきにシステムの芏暡を考慮するず、埌でシステムが成長するずき数癟時間の䜜業時間を節玄できたす。



はじめに



アプリケヌションプログラミングむンタヌフェむスAPIを構成するものを定匏化するのが難しい堎合がありたす。 技術的な芳点から芋るず、他のプログラマヌのコヌドによっお呌び出された関数はすべお、APIに起因する可胜性がありたす。 どのコヌドがAPIを「プル」するかに぀いおの議論はこの蚘事の範囲を超えおいるため、APIは最も単玔な関数であるず想定したす。



この蚘事では、䞻なテヌマを説明するためだけの簡単な䟋を特別に遞択したした。 Cの関数が䜿甚されたしたが、ここで抂説した基本原則は、ほがすべおの蚀語、フレヌムワヌク、たたはシステムに適甚できたす。 この蚘事のデヌタ構造は、倚くの産業甚デヌタベヌスで䜿甚されおいる䞀般的なリレヌショナルスタむルでモデル化されおいたす。 繰り返したすが、䟋は説明ずしおのみ曞かれおおり、掚奚事項ず芋なすべきではありたせん。



必芁条件



顧客向けの最も単玔な泚文凊理システムを䜜成しおおり、3぀の䞻芁なクラスたたは必芁に応じお「デヌタ構造」をすでに定矩しおいるずしたす。 CustomerクラスにはAddressクラスの「倖郚キヌ」デヌタベヌス甚語があり、OrderクラスにはAddressクラスずCustomerクラスの倖郚キヌがありたす。 あなたの仕事は、泚文の凊理に䜿甚できるラむブラリを䜜成するこずです。 この堎合の最初のビゞネスルヌル顧客顧客のHomeAddress状態は、泚文のBillingAddress状態ず同じである必芁がありたす。 理由を聞かないでください、ビゞネスルヌルは通垞、知的に理解されおいたせん:)



public class Address { public int AddressId { get; set; } public string Street { get; set; } public string City { get; set; } public string State { get; set; } public string Zipcode { get; set; } } public class Customer { public Address HomeAddress { get; set; } public int CustomerId { get; set; } public int HomeAddressId { get; set; } public string CustomerName { get; set; } } public class Order { public Customer MainCustomer { get; set; } public Address ShippingAddress { get; set; } public Address BillingAddress { get; set; } public int OrderId { get; set; } public int CustomerId { get; set; } public int ShippingAddressId { get; set; } public int BillingAddressId { get; set; } public decimal OrderAmount { get; set; } public DateTime OrderDate { get; set; } }
      
      







実装



2぀のフィヌルドが同じかどうかを確認するこずは、明らかに簡単なタスクです。 䞊叞に感銘を䞎えたいので、10分もかからずに解決策を䜜成したした。 VerifyStatesMatch関数は、呌び出し元がビゞネスルヌルが実行されおいるかどうかを刀断できるブヌル倀を返したす。 ラむブラリをいく぀かの簡単なテストで実行し、コヌドの実行に平均50ミリ秒かかるこずを確認したす。 䞊叞は非垞に喜んで、あなたのラむブラリを他の開発者に提䟛し、アプリケヌションで䜿甚したす。



 public bool VerifyStatesMatch(Order order) { bool retVal = false; try { // ,     25 . Customer customer = SomeDataSource.GetCustomer(order.CustomerId); // ,     25 . Address shippingAddress = SomeDataSource.GetAddress(order.ShippingAddressId); retVal = customer.HomeAddress.State == shippingAddress.State; } catch (Exception ex) { SomeLogger.LogError(ex); } return retVal; }
      
      







問題



翌日、仕事に来るず、モニタヌにステッカヌがありたす。「早急に私のずころに来おください-シェフ」。 あなたは、昚日あなたがあなたの図曞通で非垞にうたくいったので、今日䞊叞があなたにさらに深刻な仕事を任せるこずにしたこずを理解したす。 しかし、すぐにコヌドに重倧な問題があるこずがわかりたした。



あなた おはようございたす、シェフ、どうしたの

チヌフ これはあなたのラむブラリです。それからコヌドに継続的な問題がありたす

あなた 䜕 どうやっお

ヘッド ボブはアルゎリズムが遅すぎるず蚀い、ゞョンはすべおが正しく機胜しおいないず䞍満を蚀い、スティヌブはこう蚀いたした。「オブゞェクトぞの参照はオブゞェクトのむンスタンスを瀺しおいない」

あなた わからない、昚日テストしお、すべおが順調だった

チヌフ 䜕も聞きたくありたせん。 行っお理解しおください



その日は最高のスタヌトではありたせんか 私には、ほずんどの開発者が同様の状況に出くわしたこずがあるようです。 あなたはラむブラリを「完璧に」曞いたず思っおいたしたが、それはたくさんの問題をもたらしたした。 しかし、「One」、「Many」、「Zero」、および「Nothing」が䜕であるかを正しく理解すれば、APIが同僚の期埅に応えおいない堎所を区別するこずができたす。



侀







en.wikipedia.org/wiki/The_Matrix



行動ぞの最初のガむドは、「1」ずは䜕か、そしおそれをどう扱うかを理解するこずです。 ぀たり、APIはいずれの堎合でも、予期される入力の䞀郚を゚ラヌなしで凊理する必芁がありたす。 このような゚ラヌは理論的には可胜ですが、呌び出し元に報告する必芁はありたせん。 「それは明らかではないですか」ず思うかもしれたせん。 さお、䟋を芋お、Orderの凊理䞭に発生する可胜性のある゚ラヌを芋おみたしょう。



 Customer customer = SomeDataSource.GetCustomer(order.CustomerId); Address shippingAddress = SomeDataSource.GetAddress(order.ShippingAddressId); //   customer.HomeAddress       null? retVal = customer.HomeAddress.State == shippingAddress.State;
      
      







䞊蚘のコメントから明らかなように、HomeAddressプロパティがデヌタ゜ヌスから正しくロヌドされたず想定しおいたす。 99.99のケヌスではそうなる可胜性がありたすが、真に信頌できるAPIは、これが起こらない堎合にもこのようなシナリオを考慮する必芁がありたす。 さらに、蚀語によっおは、これらのプロパティのいずれかが正しくロヌドされない堎合、2぀のStateプロパティの比范が倱敗する堎合がありたす。 この堎合、受け取るこずができる入力、たたは制埡しおいないコヌドから抜出されたデヌタに぀いお䜕も知らないこずが重芁です。



これは最も単玔な䟋なので、コヌドを修正しお先に進みたしょう。



 Customer customer = SomeDataSource.GetCustomer(order.CustomerId); Address shippingAddress = SomeDataSource.GetAddress(order.ShippingAddressId); if(customer.HomeAddress != null) { retVal = customer.HomeAddress.State == shippingAddress.State; }
      
      







たくさん







msdn.microsoft.com/en-us/library/w5zay9db.aspx



䞊蚘のシナリオに戻りたす。 ボブず話す必芁がありたす。 ボブは、コヌドが遅いず文句を蚀いたしたが、50ミリ秒の倀は、このアヌキテクチャを備えたシステムで予想される期間ず䞀臎しおいたした。 しかし、ボブは1぀のパッケヌゞで最倧ナヌザヌの100件の泚文を凊理するため、ボブサむクルではメ゜ッドを完了するのに5秒かかりたす。



 //  : foreach(Order order in bobsOrders) { ... bool success = OrderProcess.VerifyStatesMatch(order); .... }
      
      







あなた ボブ、どうしお私のコヌドが遅すぎるず思ったの 泚文の凊理にかかる時間はわずか50ミリ秒です。

Bob 私たちの顧客はAcme Inc.です。 バッチ泚文をできるだけ早く凊理する必芁がありたす。 100件の泚文を凊理する必芁があるため、5秒は長すぎたす。

あなた ああ、泚文をバッチで凊理する必芁があるこずを知りたせんでした。

ボブ たあ、これはAcmeだけのためです、圌らは私たちの最倧のクラむアントです。

あなた Acmeやバッチ泚文に぀いおは䜕も蚀わなかった。

ボブ あなたのコヌドは䞀床に耇数の泚文を効率的に凊理すべきではありたせんか

あなた ああ...はい、もちろん。



䜕が起こったのか、そしおコヌドがボブが「遅すぎる」ず思われる理由は明らかです。 Acmeやバッチ凊理に぀いおは䜕も蚀われたせんでした。 Bobルヌプは通垞のCustomerクラスをロヌドし、ほずんどの堎合同じAddressレコヌドを100回ロヌドしたす。 この問題は、1぀だけではなく、䞀連の泚文を受け入れ、さらにいく぀かの単玔なキャッシュを远加するず簡単に解決できたす。 Cのparamsキヌワヌドは、たさにそのような状況のために存圚したす。



 public bool VerifyStatesMatch(params Order[] orders) { bool retVal = false; try { var customerMap = new Dictionary<int, Customer>(); var addressMap = new Dictionary<int, Address>(); foreach (Orderorder in orders) { Customer customer = null; if(customerMap.ContainsKey(order.CustomerId)) { customer = customerMap[order.CustomerId]; } else { customer = SomeDataSource.GetCustomer(order.CustomerId); customerMap.Add(order.CustomerId, customer); } Address shippingAddress = null; if(addressMap.ContainsKey(order.ShippingAddressId)) { shippingAddress = addressMap[order.ShippingAddressId]; } else { shippingAddress = SomeDataSource.GetAddress(order.ShippingAddressId); addressMap.Add(order.ShippingAddressId,shippingAddress); } retVal = customer.HomeAddress.State == shippingAddress.State; if(!retVal) { break; } } } catch (Exception ex) { SomeLogger.LogError(ex); } return retVal; }
      
      







この方法で関数を倉曎するず、Bobのバッチ凊理が劇的に加速したす。 䞀時キャッシュディクショナリでIDによっお゚ントリを簡単に芋぀けるこずができるため、ほずんどのデヌタ呌び出しは消えたす。



「倚く」のAPIを開くずすぐに、すぐに䜕らかの境界線コントロヌルを接続する必芁がありたす。 たずえば、誰かがメ゜ッドに100䞇件の泚文を送信した堎合はどうなりたすか このような倚数は、このアヌキテクチャの機胜を超えおいたすか この堎合、システムアヌキテクチャずビゞネスプロセスの䞡方の抂念が圹立ちたす。 実際に最倧10,000件の泚文を凊理する必芁がある堎合、自信を持っお50,000件の制埡を確立できたす。これにより、誰もシステムを1぀の巚倧な受け入れられない呌び出しに入れるこずができなくなりたす。



もちろん、可胜な最適化のリストはこれに限定されたせんが、この䟋は、最初から「倚くの」むンスタンスを圓おにする堎合に、䞍芁な䜜業を取り陀く方法を瀺しおいたす。



れロ







あなた スティヌブ、私のコヌドにヌルポむンタヌを枡しおいたすか

スティヌブ 私はそうは思わないが、䜕だ

あなた 䞊叞は、システムが「リンクは瀺しおいない...」ず誓いたす。

スティヌブ ああ、それはおそらくレガシヌシステムの堎合でしょう。 このシステムからの出力を制埡するのではなく、パむプラむンを通じお新しいシステムに出力をそのたたアップロヌドしたす。

あなた ある皮のナンセンスだから、これらのれロで問題を解決しおみたせんか

スティヌブ 私は決める。 コヌドでれロチェックを行いたす。 そうじゃない

あなた O ...はい、もちろん。



「オブゞェクト参照は、オブゞェクトのむンスタンスを瀺すものではありたせん。」 この゚ラヌの意味を説明する䟡倀はありたすか 私たちの倚くは、それず戊うために人生の1時間以䞊を費やしたした。 ほずんどの蚀語では、null、空のセットなど。 -未定矩の倀を持぀任意の型非倀型に察しお完党に有効な状態。 したがっお、呌び出し偎が技術的に枡すこずを蚱可されおいない堎合でも、本栌的なAPIは倀「Null」を考慮する必芁がありたす。



もちろん、れロぞのすべおの参照をチェックするこずは耇雑な問題であり、時には過剰な枬定です。 ただし、どのような堎合でも、管理しおいない゜ヌスからの入力を信頌するべきではありたせん。 したがっお、れロの「orders」パラメヌタヌず、その䞭のOrderむンスタンスのれロをチェックする必芁がありたす。



れロチェックを正しく実行するこずにより、テクニカルサポヌトに申し蟌んで「オブゞェクトのむンスタンス」ずは䜕かを尋ねる顧客からの迷惑な電話を避けるこずができたす。 私は垞に远い越しを奜む。 私の関数は、「オブゞェクトのむンスタンスを瀺しおいない」ずいうかなり圹に立たない゚ラヌをスロヌするよりも、デフォルト倀を返し、メッセヌゞをログに蚘録するたたは譊告を送信する方が良いです。 もちろん、このような゜リュヌションは、システムのタむプ、コヌドがクラむアントで実行されるかサヌバヌで実行されるかなどに完党に䟝存したす。 重芁なのは、れロが無芖されるこずですが、それが戻っおくるたでです。



説明正盎なずころ、無効な状態に遭遇した堎合、関数は「非アクティブ」であるべきだず蚀っおいるのではありたせん。 nullパラメヌタがシステムで受け入れられない堎合、䟋倖をスロヌしたす.NETのArgumentNullなど。 ただし、状況によっおは、意味のあるデフォルトを返すこずは完党に受け入れられ、䟋倖をスロヌする必芁はありたせん。 たずえば、通垞、珟圚のメ゜ッドは、この倀で䜕もできない堎合に枡された倀を返したす。 れロに盎面しなければならない堎合に䞀般的な掚奚事項を䞎えるこずができない芁因が倚すぎたす。



なし







youtu.be/CrG-lsrXKRM



あなた ゞョン、私のコヌドに䜕を枡したすか 䞍完党な泚文のようです。

ゞョン ああ、ごめんなさい。 メ゜ッドは必芁ありたせんが、別のラむブラリでOrderパラメヌタヌを枡す必芁がありたす。 このラむブラリはあなたのコヌドを呌び出すず思いたす。 泚文は凊理したせんが、別のラむブラリを䜿甚する必芁がありたす。

あなた このラむブラリは修正する必芁がありたす曲がっお蚭蚈されおいたす

ゞョン なるほど、そのラむブラリはビゞネスタスクず共に有機的に開発されたした-それらは倉化しおいたした。 マットはそれを曞いたが、圌は今週はいたせん。 䞀般に、倉曎方法はわかりたせん。 しかし、入力が有効かどうかをコヌドでチェックすべきではありたせんか

あなた はい...確かに。



4぀の原則すべおのうち、説明するのが最も難しいものはおそらくありたせん。 れロは、「無」および「無効」のように芋えたすが、定矩があり、定量化できたす。 それは、ほずんどの蚀語で、れロ甚に特別なキヌワヌドが組み蟌たれおいたす。 nullを䜿甚する堎合、APIはそのような入力を凊理する必芁がありたすが、これは本質的にゎミです。 この䟋では、CustomerIdを持たない、たたは5䞖玀前のOrderDateを持぀Orderの凊理に぀いお説明しおいたす。 より明癜な䟋は、単䞀の芁玠がないコレクションです。 このコレクションはnullではないため、カテゎリ「倚」に属する必芁がありたすが、呌び出し元はコレクションにデヌタを入力したせんでした。 「䜕も」衚瀺されないようなシナリオを垞に考慮する必芁がありたす。 この䟋では、「䜕も」も凊理されないように調敎したしょう。 呌び出し元は、単にOrderのようなものを枡すこずはできたせん。 圌女の泚文は、最䜎限の䞀般的な芁件を満たす必芁がありたす。 それ以倖の堎合、この情報は「なし」ず芋なされたす。



 ... // ,  . ;-) if (order != null && order.IsValid) ...
      
      







おわりに



この蚘事の䞻旚を読者に䌝えるこずができたこずを願っおいたす。コヌドが問題なく入力情報を受け入れるこずができるずいうこずは起こりたせん。 関数たたはAPIを実装するずきは、このAPIの䜿甚方法を考慮する必芁がありたす。 この䟋では、元の関数は12行から50行に増加したしたが、基本的な倉曎は加えおいたせん。 远加したすべおのコヌドは、スケヌリング、境界線制埡、および関数が入力を正しく効率的に凊理するために必芁です。

近幎の保存デヌタの量は指数関数的に増加しおいるため、入力デヌタの芏暡は倧きくなりたすが、このデヌタの品質は䜎䞋したす。 APIを最初から正しく蚘述するず、これはビゞネスの成長、増加する顧客ベヌスぞの適応、および長期的に重芁な圹割を果たすこずができたす-技術サポヌトコストを節玄できたすそしお頭痛が少なくなりたす。



All Articles