web-dev-qa-db-ja.com

クリーンアーキテクチャ-エンティティが自動生成されるときに、ビジネス計算をどこに置くか

私は、従来のレイヤードアーキテクチャアプローチからクリーンアーキテクチャに切り替えて、ビジネスロジックを配置する場所を見つけようとしています。以下のシナリオを検討してください-

従業員クラス(Efcore dbに最初にコアに足場を組んで存在します)-

class Employee {
    public int Id {get; set;}
    public int TimeWorked {get; set;}
    public int ZoneCode {get; set;}
    public datetime JoiningDate {get; set;}
    public decimal Reimbursement {get; set;}
}
class SomeMasterData { //Could be a value object
    public int ZoneCode {get; set;}
    public decimal OvertimeAllowedForZoneCode {get; set;}
}
class SomeOtherMasterData {  //Could be a value object
    public int OvertimeMultiplier {get; set;} //and whatever other props
}

従業員に関連するビジネスロジック-

int CalculateReimbursement(Employee emp, SomeMasterData masterData, , SomeOtherMasterData masterData2) {
    // Use data from Employee (fields like zone code, joining date etc) and
    // data from SomeMasterData to calculate the reimbursement amount for the employee
    // The below business logic is random, created for this question
    if(emp.ZoneCode == masterData.ZoneCode && emp.JoiningDate > 'some date') {
        return masterData.OvertimeAllowedForZoneCode * masterData2.OvertimeMultiplier * emp.TimeWorked;
    }
    else //More business logic based on many entities and value objects
    ...
}

私の質問は-クリーンアーキテクチャを考慮して、CalculateReimbursementメソッドをどこに置くか?以下はいくつかのオプションです-

  1. コアのドメインサービス-しかし、これはドメインサービスの目的ですか?
  2. Employeeクラス内-ただし、そのクラスはEfcore dbの最初のスキャフォールディングによって自動生成されるため、変更できません。このメソッドで別のEmployee部分クラスを作成する必要がありますか?
  3. コア内のある種の「ヘルパー」クラス-ある場合、それを何と呼びますか?
  4. クリーンアーキテクチャを念頭に置いて、より理にかなった他の場所はどこですか
3
Achilles

マイクの回答に加えて、上記のコメントに沿って。

CalculateReimbursementにカプセル化されたビジネス知識は、コアに収まるようにします。より具体的には、Entitiesレイヤー。

エンティティ企業全体のビジネスルールをカプセル化します。 エンティティは、メソッドを含むオブジェクトにすることも、データ構造と関数のセットにすることもできます。エンティティがさまざまなアプリケーションで使用できる限り、問題はありません

クリーンコードブログ:クリーンアーキテクチャ -R.C.マーティン

私の強調。

これらの関数がサービス、ヘルパー、ユーティリティのどれであるかは、実装の詳細ではなく境界にあるため、著者は述べていません:business固有のルールはコアに属します

以前との関連で、著者は、フレームワークやインフラストラクチャなどの実装の詳細からコアを分離するという考えを強調しています。

また、このレイヤーが、データベース、UI、または任意の一般的なフレームワークなどの外部性への変更の影響を受けることはないと考えています。この層はそのような懸念から隔離されています。

クリーンコードブログ:クリーンアーキテクチャ -R.C.マーティン

Q:しかし、ここでは、エンティティごとに重複するクラスを作成することについて話しています。自動生成されたエンティティがすでに存在している場合は、それほど多くの作業ではありませんか?

番号。

そもそも、エンティティを1:1でマッピングすることを強制するものはありません。ドメインと永続性データモデルは異なる抽象化です。ドメインの1つのエンティティが永続層のN個のエンティティを必要とする場合、またはその逆の場合があります。各モデルは、それぞれのストア(メモリやファイル)で効率的に読み書きできるように設計されていることを覚えておくことが重要です。その結果、どちらも異なるルールと制約を扱います。

2番目に、追加の作業は自動生成プログラムによって実行されます。だよね?それがそのようなツールを使用する唯一のポイントです。私たちの取り組みは、永続性ではなく、コアをモデル化および進化させるために取り組む必要があります。私たちは永続性を私たちのために機能させ、反対ではありません。1

最後に、分離と分離はクリーンアーキテクチャの基本概念です。 -less LoCsのような前提は、コードを維持するのをより簡単で安価にする-のような前提は誤りです。優れた抽象化と十分に分離された懸念事項により、コードの保守が容易かつ安価になります。

Q:また、エンティティのドメインバージョンを手動で維持してDBテーブルの変更と同期を保つための余分な作業はありませんか?

これは間違った仮定に基づく間違った結論です:ビジネスは永続性に依存しますクリーンなアーキテクチャの動作方法ではありません。

クリーンアーキテクチャでは、ビジネスは永続性に依存しないため、永続性はビジネスのモデル化方法を指示できません。それは正反対です。この時点で、安定した依存関係という概念に慣れることをお勧めします。これは、この建築スタイルの基盤であるためです。

Q:モデルのドメインバージョンを持つことが理想的であると理解していますが、自動生成されたエンティティを再利用して手動の作業を削減できるソリューションがあるかどうか疑問に思っていますまた、可能な限りクリーンなアーキテクチャに従っていますか?

利便性の問題。

私の経験では、明確に定義されたアーキテクチャスタイルを実装することは、部分的に努力する価値がありません。全体として、引数が-の場合、自動生成されたコードは、永続性とビジネスロジックのニーズを満たすことができ、一握りの節約になりますLoCs-。2

どうして?実装の途中から、誰の土地にも行かないからです。アーキテクチャの利点が真実の半分であり、同時に嘘の半分である場所。この問題では、アーキテクチャーの利点を実現するための適切なサポートを見つけることができないため、私たちが訴えたLoCの節約は反対になります。


1:データ中心ドメインモデル自体は悪くありません。一部のアプリケーションには、ビジネスロジックがほとんどありません(またはまったくありません)。最も適切なアプローチは、ビジネス要件の複雑さに依存します。たとえば、クエリとレポートのプロセスにドメインモデルを使用することは、不必要に複雑です。このような場合は、それが何であるかを簡単に認識し、ドメイン層を取り除き、インフラストラクチャ層に直接アクセスするのに役立ちます。

2:万能なソリューションは存在しません

4
Laiv

EFによって作成されたモデルを、データを永続化するために作成された純粋なモデルとして使用できます。これらを、すべてのビジネスロジックを保持できる実際のEmployeeドメインモデルクラスにマップする必要があります。これは、本当にドメインモデルになります。

6
Mike

ビジネスロジックたぶん常には複数のエンティティを処理するため、生成されたエンティティのレイヤーには含めないでください。

理想的には、コア内の独自のレイヤーである必要があります。ビジネスルールを説明する正式なバージョン管理されたWordドキュメントがあり、コード内のbusinesコードのすべての部分がドキュメントを参照しているケースが1つあります。バージョン番号は、変更リクエストチケット。

ビジネスロジックのクラスであるBO(ビジネスオブジェクト)は、コアの独自のレイヤーにあり、モジュール化されています。

フロントエンド、GUI&コントローラー、決定何が必要で、何が最良のフォームかを決定します。したがって、開発者がレイヤーの深さに飛び込み、概要を把握できるようにする必要があります。 。

つまり、すべてのレベル/レイヤーのすべてのユースケースについて、パッケージパスが短く、規定されたサブ階層が複雑すぎず、他の用途が明確に分離されている必要があります。ケース(標準的な手段としてのコードのコピーなし)。

追加のアーティファクト、コードの中間の「パスオン」層(インターフェースと同様)は、可能な限り薄くする必要があります。ボイラープレートコードなし。個人的にはインターフェースが好きです。関心事を分離すると、インターフェースに対してコンポーネントが実装される可能性がありますが、効果的なクラスはそれ以上の実装を行います。

1
Joop Eggen