ビジネスロジックの外でコードのログを完全に記録し続けることは可能ですか?


12

AOPを利用して、ビジネスロジックからロギングコードを削除できます。しかし、それは単純なもの(つまり、メソッドの入り口/出口およびパラメーター値のロギング)をログに記録するためにのみ使用できると思います。

ただし、ビジネスロジックに何かを記録する必要がある場合はどうなりますか?例えば

public void SomeDomainMethod(string id)
{
   //Get user by Id
   User user = Users.Get(id);
   if (user == null)
   {
      Log.Warn("user is not existed");        //<----------------- Log A
      throw new InvalidOperationException("user is not existed");
   }

   //Step 1 
   while(true)
   {
       //do something
   }
   Log.Info("Step 1 is completed");            //<----------------- Log B

   //Step 2
   while(true)
   {
       //do something
   }
   Log.Info("Step 2 is completed");            //<----------------- Log C

}

上記のサンプルメソッドは十分に明確ではない場合があります。ここで説明したいのは、メソッドをドメインの観点から最小単位として扱う必要があることです。小さな部分に分割しないでください。

メソッドから3つ以上のロギングコードを移動することは可能ですか?そのような状況のベストプラクティスは何ですか?


あなたの例の「Step1」と「Step2」のログはビジネスロジック監査証跡の一部であり、最初のログは技術ログであるはずです。最初にこれをソートします...
tofro

回答:


1

承知しました!

しかし、私の経験では、有用なロギングには2つの一般的なタイプがあります。

すべてのログ:プロファイリングAPIを通じて構築されたログ。パフォーマンスの問題を特定し、例外を報告するのに適しています。うるさい。

ビジネスイベントログ:ビジネスロジックで呼び出されたログ。ビジネスが気にかけるかもしれないもの。最小限のノイズ。注目に値する、論理的な「ビジネス」イベント。監査およびKPIに適しています...

したがって、私は2つのことを強くお勧めします。まず、New Relicなどの他の監視ツールと同じようにして、.NETプロファイリングAPI 1使用します。次に、論理的なビジネスイベントをビジネスロジックに記録します。特定のイベントの記録を保持することビジネスロジックです。

また、通常、どちらの種類のロギングについてもAOPを提案することはありません2。私の経験では、プロファイラーを使用していることを意味するすべてのもの、または論理的/ビジネスイベントが必要です。後者の場合、ビジネスロジックでロガー呼び出すだけの方が簡単だと思います


1.しかし、真剣に、何千時間もの労力を節約し、既存のプロファイラーツールを使用してください...

2.もちろん、これは、アスペクトがビジネスルールを隠すのに最適な場所ではないという私の意見を共有することを前提としています。


「ビジネスイベントログ」についてはまったく同意します。他の人の回答と同様に、ログコードをビジネスロジックに保持します。また、「すべてのログ」の部分では、SOPに従い、ビジネスロジックを汚染しないため、AOPソリューションを使用することをお勧めします。とにかく、最初にプロファイリングAPIを見てみましょう。
チャーリー

10

もちろん、これにはAOPを簡単に使用できます。単にパーツをリファクタリングする

  • IDでユーザーを取得
  • ステップ1
  • ステップ2

別の方法(あなたのコードクリーナーを作るためにどちらかのやるべきとして)。これで、選択したメソッド呼び出しをログに記録するようにAOPフレームワークを簡単に構成できます(ここに示すように)。例外は呼び出し元が直接ログに記録でき、これをビジネスロジックから取得するためにAOPを使用する必要はありません。

あなたの編集に:

ここで示したいのは、メソッドはドメインの観点から最小単位として扱われるべきだということです。細かく分割しないでください

なぜそれをすべきではないのですか?「ビジネスロジックコンテキスト」で、ログに値する「何か」をログに記録する場合、この「何か」にわかりやすい名前を付けることができれば、ほとんどの場合、コードをメソッドにリファクタリングすることは意味があります。それ自身。AOPを使用する場合は、ロギングの要件に関係なく、コードを構造化する必要があると思われる方法でコードを構造化する必要があります。これをAOPの欠点として解釈することも、コード構造を改善できるフィードバックを提供するため、これを利点として解釈することもできます。


私の例が十分に明確ではないのは残念です。私が実際に例で示したいのは、メソッドがドメインの観点からは最小の単位であり、小さい部分に分割されるべきではないということです。
チャーリー

@Charlie:例は完全に明確です。ここでのあなたの誤解は、おそらく、ステップよりも大きなメソッドを用意することは良い考えかもしれないとあなたが思っていることでしょう。そして、それは私見間違いです、それは良い考えではありません。ログに記録する価値のあるさまざまなステップがあることは、これらのステップに抽象化、独自の名前、したがって独自のメソッドが必要であることを明確に示しています。
Doc Brown

@Charlieは、ユニットまたはワークから呼び出されている3つのプライベートメソッドを実行することを妨げるものはありません。この方法では、外部からは同じままでしたが、これでロギングに必要な抽象化ができました。
レミ

懸念事項をログに記録してコード構造を推進したい場合は、このアプローチで問題ありません。ただし、別の方法でドライブしたい場合もあります。
John Wu

@JohnWu:ロギング要件に関係なく、コード構造はさまざまな懸念事項/手順を反映する必要があります。それが、ここでコード構造を駆動するものです。この問題が解決されると、AOPによってロギングを実行できるようになります。これは、コードの構造を改善することによる「副作用」です。したがって、コード構造を駆動するのはロギングの問題ではないと思います。ロギングにAOPを使用する必要があるため、コードが何らかの構造を欠いていることがより透過的になります。
Doc Brown、

3

Loggingの要素がビジネス要件の一部でない限り、コードから完全に除外するのが最善です。

つまり、「ステップ1完了」のようなものをログに記録したくないのです。最初はデバッグに役立つかもしれませんが、本番環境では決して見ないギガバイトのゴミを生成するだけです。

Step1Completeが何らかのアクションを必要とするある種のビジネスイベントである場合、ILoggerなどをクラスに挿入することを強制せずに、古き良き昔ながらのイベントを通じて公開できます。


それは私が考えていたものです。ドメイン/ビジネスモデルPOCO内でロギングするための合理的なケースを思いつくことができません。ロギングは、コアビジネスモデルであるIMOの外に自然に収まる傾向があるものです。
jleach

2

いくつかの一般的なパターンを利用して、ビジネスロジックからロギングコードを引き出すことができます。ただし、そうする価値はないかもしれません。

たとえば、リスナーを使用すると(1つを手作りするか、イベントバスを使用するなど)、コードは次のようになります。

public void SomeDomainMethod(string id)
{
   //Get user by Id
   User user = Users.Get(id);
   if (user == null)
   {
      listener.OnUserNotFound(userId);
      throw new InvalidOperationException("user is not existed");
   }

   //Step 1 
   while(true)
   {
       //do something
   }
   listener.OnStep1Finished(......);

   ...

}

リスナーにロギングを実装することにより、ロギングロジックはビジネスロジックに含まれなくなります。

ただし、ロジックの意味のあるイベントを常に定義できるとは限らないため、これが常に現実的であるとは限りません。

別のアプローチは、実行中のプロセスに注入できるようにするSolarisのDtraceのようなメカニズムによるものです(C#で同様のことを行う方法はあると思いますか?)ロギングと統計収集を実行時に定義できます。それでも他の欠点があります。


AOPが解決しようとしている問題の1つは、「ビジネスコード」と織り交ぜられたビジネスログ以外のコード(ログの呼び出しなど)が読み取れなくなるという問題です。「ロガー」を「リスナー」に置き換えてもこれは解決されず、コードの可読性は変更されません
Doc Brown

2

別のアプローチは、ビジネスログと技術ログを区別することです。次に、ビジネスロギングを「監査」と呼び、ストレージ期間などの特定のビジネスルールと、ビジネスアクティビティモニタリングなどの処理ルールを適用できます。

一方、技術的なロギング、または単に「ロギング」は、技術的な問題の痕跡を残す最後の手段です。ログメッセージの永続化の失敗に対して、非同期で高速かつ耐性がある必要があります。また、ログメッセージは、問題の原因に近づくために、可能な限り少ない数のプロキシを通過する必要があります。

ロギングのロジックは非常に可変的であり、実装と密接に結びついているので、本当にそれをコードから分離する必要がありますか?

監査のロジックは、ドメインロジックと見なして、それに応じて処理する必要があります。

たとえば、ヘキサゴナルアーキテクチャでは、クライアント、ストレージ、およびMQ(および場合によってはメトリックとコントロール)ポートとともに監査ポートが存在する場合があります。これはセカンダリポートになります。つまり、このポートでのアクティビティは、外部システムではなくビジネスコアによってトリガーされます。


ロギングには2種類あるということで、あなたにとても同意しました。しかし、私はLogic of the Loggingを取得できません。ロギングはかなり可変的であり、実装と密接に結びついています。ここで技術的なロギングを意味しますか?技術的なロギングでは、メソッドの入り口/出口とパラメーター値をログに記録するために使用されていると思います。
チャーリー

@Charlieはい、「The Logging」とは、技術的なロギングを意味します。純粋な関数の場合は、入り口/出口/パラメーター値のロギングで十分です。次に、またはもちろん、アスペクトまたはロガーモナドを使用できます。しかし、純粋な関数はテスト可能であるという点で優れています。したがって、ロガーがトレースすることになっている問題は、開発/デバッグ中に解決される可能性があります。純粋でない関数では、技術ロギングが最も有用であり、副作用のあるすべての呼び出しパラメーター/結果、すべての例外をログに記録する必要があります。
iTollu 2017年

1

クラスまたはメソッドに直接ログを記録しないようにする方法:

  1. 例外をスローし、呼び出しツリーのさらに上のcatchブロックでログを記録します。ログレベルをキャプチャする必要がある場合は、カスタム例外をスローできます。

  2. ロギング用にすでに装備されているメソッドを呼び出します。


1
ロギングは問題であることが示されている場所であり、「修正」する価値さえありますか?
whatsisname 2017年

1

ロギングをビジネスロジックから分離することが本当に必要ですか?実行されるロギングは、記述されたビジネスロジックに対応しているため、同じクラス/関数内にあることが理にかなっています。さらに重要なのは、コードを読みやすくすることです。

ただし、ロギングをビジネスロジックから分離したい場合は、カスタム例外をスローし、それらの例外をロギングに渡すことを検討する必要があります。


0

いいえ、C#ではありません

OP、あなたの特定の質問への答えはノーです、C#ではありません。他にももっとネイティブなAOP言語があるかもしれませんが、私が見たc#でのAOPへのすべてのアプローチは、結合ポイントのコンテキストでアスペクトされた動作のみを適用できます。つまり、1つのコードブロックと別の。当然ながら別のメソッドを呼び出すことを除いて、アスペクト動作はメソッドの途中で実行されません。

ロギングの特定のビットを「アスペクト化」できます

そうは言っても、ログの書き込みではなく、ログに関連する特定の懸念を抽出できます。たとえば、メソッドの入り口で実行されたカットポイントは、ロギングコンテキストをセットアップしてすべての入力パラメーターを出力し、出口で例外をキャッチしたり、ログを永続的なストレージにコミットしたりすることができます。

とにかく、ログの書き込みはアスペクトではありません

とにかく、ログの書き込みは実際には分野横断的な問題ではないことを付け加えておきます。少なくともロギングをデバッグしないでください。これについての私の証拠は、この側面が何をするかを完全に説明する横断的な要件を書くことができなかったことです-ログを書き込む目的は、何が起こっているかを反映することであるので、すべてのケースに固有ですロジック、および各メソッドのロジックは合理的に一意である必要があります(DRYを参照)。

言い換えれば、ログの書き込みと書き込まれているものとの間に不可解な論理的な依存関係があります。あなたはそれを一般化することはできません。

しかし、監査は

ある種の機能ログ要件(たとえば、否認防止の要件をサポートする監査ログ)がある場合、一部の人々は、メソッドの途中でこれらのログ書き込みを実行する必要があることに気付いた場合、アスペクト指向の考え方と一致する方法でコードを構造化していない。これが発生した場合、必要なレベルの細分性が得​​られるまで、コードを個別のメソッドに抽出する必要があります。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.