2016-06-17 17 views
1

私は最近、Mark Seemannの本をDependency Injectionについて読んできましたが、Inversion of Controlについていくつかのアーキテクチャ上の問題が提起されています。 のは、以下の私が持っていると仮定しましょう:IoC Architecture

  • CompositionRoot.exeと呼ばれる合成ルートとして動作する、非常に基本的な実行可能なプロジェクト。 Domain.dllというライブラリにコンパイル
  • ドメインプロジェクト、
  • DAL.dll
  • Logging.dll
  • というライブラリにコンパイルし、ロギングプロジェクト、というライブラリにコンパイルデータ・アクセス・プロジェクト、

Seemanの本のIoCパターンに従って、リポジトリインターフェイスはドメインに定義されます。 DALはDomainを参照し、これらのインターフェイスを実装します。 CompositionRootは、これらのリポジトリをインスタンス化し、それらをドメインに注入する役割を担います。これまでのところ、それほど平穏ではありません。

今質問です。どのようにロギングがこのシナリオに適合していますか?

私はDomainとDALの両方で使用されているロギングライブラリを構想しました。 StackOverflowの一部の読者は、一部の開発者はロギングがドメインにのみ属すると考えていることを示しています。特定のSQLをベンチマークする場合や、Entity Framework固有の例外をドメインに公開することなくEntity Framework例外を記録する場合など、DALのロギングが役に立ちます。

ここで、ドメインとDALの両方にログインしたいとしましょう(他に誰かが私を納得させることができない限り)。リポジトリインタフェースと同様のドメインでロギングインタフェースを定義する必要がありますか?もしそうなら、これはDALのロギングをドメインロギングに結びつけ、間違っていると感じます。あるいは、DALは独自のロギングインターフェイスを定義して、ロギングも実装することができます。しかし、これはロギングにつながり、ロギングを必要とする新しいDLLごとに新しいインターフェイスを実装する必要がありますが、これも間違っています。あるいは、DomainとDALがLoggingを参照すべきか(IoCに反するように思われる)?別の方法がありますか?私はまだSeemannの本を完成させていないが、インターフェースライブラリー、すなわちちょうどインターフェースで構成されたDLLを使用することを暗唱した数点で、私は現在、これがどのように機能するかを描写できません。

答えて

1

すべてがDependency Inversion Principle(DIP)(依存性注入を促進する原則)に行われます。DIPが状態:

抄録は、上部/ポリシー層によって言い換える

を所有している:抽象化は、それを使用する層によって定義されるべきです。したがって、ドメイン層でロギングが必要な場合は、ドメイン層内でロギング抽象化を行うことは明らかです。

これは、ドメインレイヤーがロギングレイヤー/ライブラリに依存することを意味するものではありません。外部ライブラリを使用する(またはログライブラリを再利用可能にする)場合は、明らかに再利用できないため、ドメインレイヤに依存することは不可能です。しかし、DIPは、外部ライブラリに依存しないコアレイヤーを持つアプリケーションに向けて私たちを導きます。その代わりに、外部ライブラリへの依存性は、Composition Rootまでずっと移動する必要があります。 Composition Rootはall the application assembliesに依存します。ドメイン層とロギングライブラリは互いに依存関係を取ることができないため、解決策はコンポジションルート内にアダプタを実装することです。このアダプタはDomain.ILogger抽象化を実装し、LogメソッドはLoggingライブラリのログ機能を呼び出します。

このアドバイスはあいまいではありません。これは実際にあなたのコアレイヤーを他のパーツから切り離す方法です。ロバートC.マーティンやアリスターコックバーンのような人々は何年も説明しています。 Robert C. MartinはこのタイプのアーキテクチャをScreaming Architectureと呼び、Alister Cockburnは用語Hexagonal Architectureを使用しています。 Mark Seemann explained数年前、両方のアーキテクチャがすべて同じであることを示しました。

DALは、ドメインレイヤーからログの抽象化を使用する必要がありますか?

DALはすでにドメインレイヤーに結合されているため(ドメイン内でリポジトリの抽象化が定義されているため)、DALレイヤーもログの抽象化に依存するのは奇妙ではありません。難しいことを考えなければならないのは、これがLiskov Substitution Principleに違反するかどうかだけです。言い換えれば、両方の消費者(DALとドメイン)は、その抽象化と同じ期待を持っていますか?そうでない場合は、DALに独自のログ抽象化機能を持たせ、ロギングライブラリへの呼び出しを転送するコンポジションルートにアダプタを(もう一度)持たせることは理にかなっています。これにより、異なる冗長レベルで、DALログを別のソースに簡単に書き込むことができます。 DALロガーのインターフェースも異なっているかもしれません。なぜなら、パフォーマンス測定が特に必要になるからです。これは、DALからドメインへの依存性であり、逆の依存性ではないため、ドメインにはまったく関係しません。

+1

こんにちはスティーブン、よく考えています。私はあなたが書いたすべてのものにすでに精通しており、実際には、この記事を読む前に、サードパーティーのロガーの使用のために記述した方法とまったく同じテストアプリケーションをコーディングしました。しかし、私はまだ、ドメインとDALの間でロギングが共有されているため、驚きの気持ちを残していました。この不協和音の原因を最終的に理解するためにLSPに言及しました。 投稿が私の考えを明確にするのに役立ちましたので、私はそれを受け入れられた回答としてマークします。ありがとう。 – Tom

1

ロギングはインフラストラクチャに似ており、すべてのコンポーネントで共有されます。ドメインのように現在定義されているプロジェクトの1つに存在する必要があるのはなぜですか?ロギングライブラリを作成していない限り、私はそれがDomainプロジェクトにあるとは思わないでしょう。

ロギングは静的にするのか、いくつかのロギングインターフェイスを注入しますか? ロギングインターフェイスを使いたいと思うので、これが私のやり方です。

ロギングインターフェイスを保持するライブラリを作成し、DomainおよびDAL(およびログインする他のプロジェクト)で参照します。次に、ログ用の実装ライブラリを作成し、これをコンソールアプリケーションで参照します。 DIを使用して、実装するドメイン/ DAL /どんなクラスにもログを記録します。

正直なところ、TraceSourceクラス、またはETWのいずれか、または多くの既存のロギングライブラリのいずれかをすべて静的に使用して、それを使用するだけです。勝利のための実用主義!

+0

明らかに、私は自分のロギングの実装をドメインに入れていません。スタンドアロンのライブラリに入れています。私はロガーを必要とするクラスのコンストラクターに(ドメインとDALの両方で)ロガーを注入しようとしていました。 – Tom

+0

インターフェイスライブラリを作成し、それをドメインとDALから参照する方法については、具体的な実装と密接に結びつかないという利点があります。不利な点はありますか?インターフェイスライブラリへの緊密な結合? – Tom

+0

正しい軌道に乗っているようですね。独立したインタフェースライブラリを持つことの欠点は、複数のロガーの実装を持たない限り、おそらく不要なことですが、正当な理由がない限り、フレームワークに組み込まれているものを使用するだけです。 –

0

依存性注入のパターンと実装の抽象化はどこまで行きたいですか?並べ替え、メモリ割り当て、スレッドの作成などの基本的な機能も注入しますか?

Domain Driven DesignDependency Injectionパターンでは、モデルに適合する1つ以上の実装を提供し、各コンポーネントの責任を分離する柔軟性を実装者に与えることになります。ロギングはどのプログラムでも標準的な動作ですが、1つのロギングメカニズムで標準化しないと、コンポーネント実装者は別のロギングフレームワークを選択する可能性があります。

プロジェクトの標準ロギングメカニズム(stdout + stderrの場合でも)を確立し、この決定をドキュメント化することをおすすめします。ルートREADME。標準のロギングメカニズムが組み込まれていて、それに依存することができるように十分に構成可能な、多くの言語とフレームワークがあります。たとえば、何らかのコンテキスト認識を許可し、そのコンテキスト内のログを無視、情報、エラーなどとして構成できるようにします。現時点では、その言語ではその質問には指定されていないので、私は何か具体的なことを示唆することはできません。