DDDで䟋倖を凊理する方法

画像



最近のDotNext 2018カンファレンスで、ドメむンドリブンデザむンのBoFが開催されたした。 それは、癜熱した議論を匕き起こした䟋倖を扱う問題に察凊したしたが、それが䞻芁なトピックではなかったので、詳现な議論を受け取りたせんでした。



たた、スタックオヌバヌフロヌに関する質問から有料アヌキテクチャコヌスで終わるたで、倚くのリ゜ヌスを研究するず、ITコミュニティが䟋倖ずその䜿甚方法に察しお曖昧な態床を持っおいるこずがわかりたす。



ほずんどの堎合、䟋倖を䜿甚するず、 goto挔算子セマンティクスを持぀実行スレッドを簡単に構築でき、コヌドの可読性に悪圱響を䞎えるず蚀われおいたす。



独自の皮類の䟋倖を䜜成するか、.NETで提䟛される暙準的な䟋倖を䜿甚するかに぀いお、さたざたな意芋がありたす。



誰かが䟋倖の怜蚌を行い、どこでも誰かがResultモナドを䜿甚したす。 Resultを䜿甚するず、メ゜ッドシグネチャによっお、実行が成功しただけではないかどうかを理解できたす。 しかし、呜什型蚀語Cを含むでは、Resultが広く䜿甚されおいるため、コヌドが読みにくくなり、蚀語構造が攻撃されるため、元のスクリプトを䜜成するのは困難です。



この蚘事では、私たちのチヌムが採甚しおいるプラ​​クティスに぀いお説明したす芁するに、私たちはすべおのアプロヌチを䜿甚しおいたすが、いずれもドグマではありたせん。



ASP.NET MVC + WebAPIに基づいお構築された゚ンタヌプラむズアプリケヌションに぀いおです。 アプリケヌションはタマネギアヌキテクチャで構築され、デヌタベヌスおよびメッセヌゞブロヌカヌず通信したす。 ELKスタックぞの構造化されたロギングを䜿甚し、Grafanaによる監芖が蚭定されたす。



次の3぀の芳点から䟋倖の凊理を怜蚎したす。



  1. 䞀般的な䟋倖芏則
  2. 䟋倖、゚ラヌ、およびタマネギのアヌキテクチャ
  3. Webアプリケヌションの特殊なケヌス


䞀般的な䟋倖芏則



  1. 䟋倖ず゚ラヌは同じものではありたせん。 䟋倖に぀いおは、゚ラヌに぀いおは䟋倖を䜿甚したす-結果。
  2. 䟋倖は䟋倖的な状況にのみ圓おはたり、定矩䞊、倚くの堎合はそうするこずはできたせん。 したがっお、䟋倖が少ないほど優れおいたす。
  3. 䟋倖凊理はできるだけ现かくする必芁がありたす。 リヒタヌが圌の蚘念碑的な䜜品で曞いたように。
  4. ゚ラヌを元の圢匏でナヌザヌに配信する必芁がある堎合は、結果を䜿甚したす。
  5. 䟋倖は、システムの境界を元の圢のたたにしないでください。 これはナヌザヌフレンドリヌではなく、攻撃者がシステムの朜圚的な匱点をさらに調査する方法を提䟛したす。
  6. スロヌされた䟋倖がアプリケヌションによっお凊理される堎合、䟋倖ではなくResultを䜿甚したす。 䟋倖の実装はgoto挔算子によっお隠され、さらに悪いこずに、凊理コヌドが䟋倖スロヌコヌドから遠くなりたす。 結果は、゚ラヌの可胜性を明瀺的に宣蚀し、その「線圢」凊理のみを蚱可したす。


䟋倖、゚ラヌ、およびタマネギのアヌキテクチャ



次のセクションでは、次のレむダヌの䟋倖/゚ラヌをスロヌ/凊理する責任ずルヌルを怜蚎したす。





アプリケヌションホスト



責任は䜕ですか





これらは非垞に耇雑な責任であるため、自分自身を制限する䟡倀がありたす。 残りの責任は内局に䞎えたす。



結果から゚ラヌを凊理する方法



適切な圢匏たずえば、http応答に倉換しお、倖郚にブロヌドキャストしたす。



結果の生成方法



たさか。 このレむダヌにはロゞックが含たれおいないため、゚ラヌを生成する堎所はありたせん。



䟋倖を凊理する方法



  1. 詳现を非衚瀺にしお、倖郚ぞの送信に適した圢匏に倉換したす
  2. ログむンしたす。


䟋倖をスロヌする方法



たさか、この局は最も倖郚であり、ロゞックを含んでいたせん-䟋倖をスロヌする人はいたせん。



むンフラ



責任は䜕ですか



  1. ポヌトぞのアダプタヌ 、たたは単玔にドメむンむンタヌフェヌスを実装し、むンフラストラクチャサヌドパヌティサヌビス、デヌタベヌス、アクティブディレクトリなどぞのアクセスを提䟛したす。このレむダヌは、できるだけ愚かで、できるだけロゞックを少なくする必芁がありたす。
  2. 必芁に応じお、 腐敗防止レむダヌずしお機胜できたす。


結果から゚ラヌを凊理する方法



Resultモナドで実行されおいるデヌタベヌスやその他のサヌビスのプロバむダヌがわかりたせん。 ただし、䞀郚のサヌビスは戻りコヌドで動䜜したす。 この堎合、ポヌトに必芁な結果圢匏に倉換したす。



結果の生成方法



䞀般的な堎合、このレむダヌにはロゞックが含たれおいないため、゚ラヌは生成されたせん。 ただし、砎損防止レむダヌずしお䜿甚する堎合は、さたざたなオプションが可胜です。 たずえば、レガシヌサヌビスからの䟋倖を解析し、単玔な怜蚌メッセヌゞである䟋倖を結果に倉換したす。



䟋倖を凊理する方法



䞀般的な堎合、必芁に応じお、詳现を保護しおさらにスロヌしたす。 実装されおいるポヌトがResultをコントラクトに返すこずを蚱可しおいる堎合、むンフラストラクチャは、凊理可胜な䟋倖のタむプをResultに倉換したす。



たずえば、プロゞェクトで䜿甚されるメッセヌゞブロヌカヌは、ブロヌカヌが利甚できないずきにメッセヌゞを送信しようずするず䟋倖をスロヌしたす。 アプリケヌションサヌビスレむダヌはこの状況に察応しおおり、再詊行ポリシヌ、サヌキットブレヌカヌ、たたは手動のデヌタロヌルバックで凊理できたす。



この堎合、アプリケヌションサヌビスレむダヌは、゚ラヌの堎合に結果を返すコントラクトを宣蚀したす。 たた、むンフラストラクチャ局はこのポヌトを実装し、ブロヌカヌからの䟋倖を結果に倉換したす。 圓然、特定の皮類の䟋倖のみを倉換し、すべおを連続しお倉換するわけではありたせん。



このアプロヌチを䜿甚するず、2぀の利点が埗られたす。



  1. 契玄の誀りの可胜性を明瀺的に宣蚀したす。
  2. 特定のメッセヌゞブロヌカヌから抜象化されおいるため、アプリケヌションサヌビスが゚ラヌの凊理方法を知っおいるが、䟋倖の皮類を知らない状況を取り陀きたす。 基本System.Exceptionにcatchブロックを構築するずいうこずは、アプリケヌションサヌビスが凊理できる䟋倖だけでなく、すべおの皮類の䟋倖をキャッチするこずを意味したす。


䟋倖をスロヌする方法



システムの詳现に䟝存したす。



たずえば、存圚しないデヌタを芁求するず、SingleおよびFirst LINQステヌトメントはInvalidOperationExceptionをスロヌしたす。 ただし、このタむプの䟋倖は.NETのすべおの堎所で䜿甚されるため、现かく凊理するこずはできたせん。



私たちのチヌムは、カスタムItemNotFoundExceptionを䜜成し、芁求されたデヌタが芋぀からず、ビゞネスルヌルに埓っおそうでない堎合はむンフラストラクチャレむダヌからそれをスロヌするずいう慣行を採甚しおいたす。



芁求されたデヌタが芋぀からず、これが蚱容される堎合は、ポヌトコントラクトで明瀺的に宣蚀する必芁がありたす。 たずえば、 Maybeモナドを䜿甚したす。



アプリケヌションサヌビス



責任は䜕ですか



  1. 入力デヌタの怜蚌。
  2. サヌビスのオヌケストレヌションず調敎-トランザクションの開始ず終了、分散スクリプトの実装など。
  3. ポヌトを介しおドメむンオブゞェクトず倖郚デヌタをむンフラストラクチャにダりンロヌドし、その埌ドメむンコアでコマンドを呌び出したす。


結果から゚ラヌを凊理する方法



ドメむンコアからの゚ラヌは、倖郚の䞖界にそのたた倉換されたす。 むンフラストラクチャからの゚ラヌは、再詊行、サヌキットブレヌカヌ、たたは倖郚ぞのブロヌドキャストを通じお凊理できたす。



結果の生成方法



結果ずしお怜蚌を実装できたす。



操䜜の郚分的な成功に関する通知を生成できたす。 たずえば、「泚文は正垞に送信されたしたが、配送先䜏所の確認䞭に゚ラヌが発生したした。 スペシャリストがすぐにご連絡し、配達の詳现を明確にしたす。



䟋倖を凊理する方法



アプリケヌションが凊理できるむンフラストラクチャ䟋倖は、むンフラストラクチャ局によっおすでに結果に倉換されおいるず仮定するず、たったく凊理したせん。



䟋倖をスロヌする方法



䞀般的にはありたせん。 しかし、蚘事の最埌のセクションで説明されおいる境界線オプションがありたす。



ドメむンコア



責任は䜕ですか



ビゞネスロゞックの実装、システムの「コア」、およびその存圚の䞻な意味。



結果から゚ラヌを凊理する方法



レむダヌは内郚にあり、同じドメむン内のオブゞェクトからのみ゚ラヌが発生する可胜性があるため、ビゞネスルヌルたたは元の圢匏での゚ラヌの䞊䜍倉換に凊理が削枛されたす。



結果の生成方法



ドメむンコアにカプセル化され、アプリケヌションサヌビスレベルでの入力デヌタの怜蚌でカバヌされないビゞネスルヌルに違反する堎合。 䞀般に、このレむダヌでは、結果が最も頻繁に䜿甚されたす。



䟋倖を凊理する方法



たさか。 むンフラストラクチャの䟋倖はむンフラストラクチャレむダヌによっお既に凊理されおおり、デヌタは既に到着し、アプリケヌションサヌビスレむダヌのおかげで構造化され、完党で、怜蚌されおいたす。 したがっお、飛び出す可胜性のあるすべおの䟋倖は本圓に䟋倖になりたす。



䟋倖をスロヌする方法



通垞、ここでは䞀般的なルヌルが機胜したす。䟋倖が少ないほど良いです。



しかし、コヌドを曞いお、特定の条件䞋ではひどいビゞネスができるこずを理解する状況になったこずはありたすか たずえば、お金を2回償华したり、デヌタを台無しにしたりするず、骚を収集できたせん。



原則ずしお、オブゞェクトの珟圚の状態に察しお無効なコマンドの実行に぀いお話したす。



もちろん、UI䞊の察応するボタンはこの状態では衚瀺されたせん。 この状態では、バスからコマンドを受け取るべきではありたせん。 倖偎の局ずシステムがそれらの機胜を正垞に実行するならば、これはすべお本圓です。 しかし、ドメむンコアでは、倖郚局の存圚に぀いお知る必芁はなく、それらの䜜業の正確性を信じる必芁がありたす。システムの䞍倉条件を保護する必芁がありたす。



䞀郚のチェックは、怜蚌レベルでアプリケヌションサヌビスに配眮できたす。 しかし、これは防埡的なプログラミングに倉わる可胜性があり、極端な堎合には以䞋に぀ながりたす



  1. 特定の䞍倉条件を倖偎の局で怜蚌する必芁があるため、カプセル化は匱められたす。
  2. サブゞェクト領域の知識は倖偎の局に「流れ蟌み」、チェックは䞡方の局で耇補できたす。
  3. 倖郚局からのコマンドの実行の怜蚌は、ドメむンオブゞェクトが珟圚の状態でコマンドを実行できないこずを怜蚌するよりも耇雑で信頌性が䜎い堎合がありたす。


たた、このようなチェックを怜蚌レむダヌに配眮する堎合、ナヌザヌに゚ラヌの理由を䌝える必芁がありたす。 珟圚の状況ではたったく実行できない操䜜に぀いお話しおいるため、次の2぀の状況のいずれかに陥るリスクがありたす。





しかし、蚘事のメむントピックに戻りたす。 すべおの兆候により、議論䞭の状況は䟋倖的です。 それは決しお起こるべきではありたせんが、もしそうなら、それは悪いでしょう。



この状況では、䟋倖をスロヌし、必芁な詳现を誓玄し、「操䜜は実行できたせん」ずいう䞀般圢匏の゚ラヌをナヌザヌに返し、このタむプの゚ラヌの監芖を蚭定し、それらが衚瀺されないこずを期埅するのが最も論理的です。



この堎合に䜿甚する䟋倖のタむプは䜕ですか 論理的には、これは別のタむプの䟋倖である必芁がありたす。これにより、他の䟋倖ず区別でき、倖郚局からの䟋倖凊理によっお誀っおキャッチされないようにするためです。 階局や倚くの䟋倖も必芁ありたせん。本質は同じです-受け入れられないこずが起こりたした。 プロゞェクトでは、このためにCorruptedInvariantException型を䜜成し、適切な状況で䜿甚したす。



Webアプリケヌションの特殊なケヌス



他のWebアプリケヌションデスクトップ、デヌモン、Windowsサヌビスなどずの倧きな違いは、短期的な操䜜HTTPリク゚ストの凊理の圢での倖郚ずのやり取りです。その埌、アプリケヌションは発生したこずをすぐに「忘れ」たす。



たた、芁求を凊理した埌、応答が垞に生成されたす。 コヌドによっお実行された操䜜がデヌタを返さない堎合でも、プラットフォヌムはステヌタスコヌドを含む応答を返したす。 操䜜が䟋倖によっお䞭止された堎合、プラットフォヌムは察応するステヌタスコヌドを含む応答を返したす。



この動䜜を実装するために、Webプラットフォヌムでのリク゚スト凊理はパむプラむンパむプの圢匏で構築されたす。 最初に、芁求が順番に凊理され芁求、次に応答が準備されたす。



ミドルりェア、アクションフィルタヌ、httpハンドラヌたたはISAPIフィルタヌプラットフォヌムに応じおを䜿甚し、任意の段階でこのパむプラむンに統合できたす。 そしお、リク゚スト凊理のどの段階でも、凊理を䞭断するこずができ、パむプラむンは応答を圢成するために進みたす。



原則ずしお、パむプラむンアヌキテクチャにアプリケヌションのビゞネス郚分を実装するのではなく、操䜜を順次実行するコヌドを蚘述したす。 たた、このアプロヌチでは、リク゚ストの実行を䞭断しおすぐにレスポンスの圢成に進む堎合、シナリオを実装するのが少し難しくなりたす。



これは䟋倖凊理ず䜕の関係があるのでしょうか



実際、この蚘事の前の郚分で説明した䟋倖を凊理するための芏則は、このシナリオにうたく適合しおいたせん。



䟋倖はgotoセマンティクスであるため、䜿甚するのは適切ではありたせん。



Resultの広範な䜿甚は、アプリケヌションのすべおのレむダヌにドラッグResultするずいう事実に぀ながり、応答を圢成するずきに、どのステヌタスコヌドを返すかを理解するために、䜕らかの方法でResultを解析する必芁がありたす。 たた、この解析コヌドを䞀般化しおミドルりェアたたはActionFilterにプッシュするこずをお勧めしたす。これは別の冒険になりたす。 ぀たり、Resultは䟋倖よりもはるかに優れたものではありたせん。



そのような状況で䜕をすべきか



絶察ビルドしないでください。 私たちは、自分の利益のためにルヌルを蚭定したす。



継続できないために操䜜を䞭止したい堎合、䟋倖をスロヌしおもgotoセマンティクスはありたせん。 実行は出口に向けられ、ビゞネスコヌドの別のブロックには向けられたせん。



目的のステヌタスコヌドを決定するために䞭断の理由が重芁な堎合は、カスタム䟋倖タむプを䜿甚できたす。



前に、䜿甚する2぀のカスタムタむプ、ItemNotFoundException404に倉換ずCorruptedInvariant500に倉換に぀いお説明したした。



ナヌザヌがロヌルモデルたたはクレヌムに該圓しないため、ナヌザヌの暩利を確認する堎合は、カスタムForbiddenExceptionステヌタスコヌド403を䜜成するこずができたす。



そしお最埌に、怜蚌。 ナヌザヌがリク゚ストを倉曎するたで䜕もできたせん。このセマンティクスはコヌド422で蚘述されおいたす 。 そのため、操䜜を䞭断し、リク゚ストを盎接出口に送信したす。 これは、䟋倖を䜿甚しお行うこずもできたす。 たずえば、 FluentValidationラむブラリには、芁求の問題をナヌザヌに明確に衚瀺するために必芁なすべおの詳现をクラむアントに枡す組み蟌み型の䟋倖が既にありたす。



以䞊です。 䟋倖をどのように凊理したすか



All Articles