2016-05-26 11 views
2

私はEric EvansとVaughn Vernonの本を読んで仮想的なビジネスドメインを段階的に習得しています。私はPHPを使って自分のプロジェクトで実装しようとしています。DDDアプローチでアソシエーションをモデル化する方法は?

最近、私は、ドメインによって規定されるべきであるモデルのため集計AggregateRootエンティティの多くパターンを読んでいます。そして、率直に言って、私はすべての定義をよく理解していないので、ここで私の質問をすることにしました。

まずは、私の質問に簡単に答える必要がある従業員の休日管理を担当する(サブ)ドメインを提示したいと思います。

ほとんどの場合、Employeeは多くの場合Teamsにあります。従業員が数日休暇を取ることに決めたとき、休日の種類(休日の休暇、子供の世話をする休暇など)、受け入れ状況、およびコースの時間範囲などのメタデータをHolidaysRequestに送信する必要があります。彼は彼の事務所に出席するつもりはない。 HolidaysRequestEmployeeHolidaysRequestを送信したことに注意する必要があります。 Employeeによって送信されたHolidaysRequestもすべて検索したいと思います。

DateRangeまたはHolidayTypeのようなものは純粋なバリューオブジェクトです。それは私にとっては明らかです。問題は、エンティティの境界を定義する必要があるときに始まります。エンティティのオブジェクトを入れ子にして関連付けを定義するという悪い習慣があるかもしれないので、ここで責任の定義を見つけてください。

  1. ここにエンティティとは何ですか?集計とは何か、集計ルートの場所はどこですか?
  2. エンティティ間の関連付けを定義する方法は?例えば。 Employeeは複数のTeamまたはHolidaysRequestに属し、Employeeによって作成され、それを受け入れる別のEmployeeに割り当てられます。集計として実装する必要がありますか?

なぜ私はこれらの質問をしていますか?数週間前に私はここに質問を掲示しました。答えの1つはEmployeeTeamsの関係について考えることでしたが、それはEmployeeInTeamと呼ばれる単一のAggreateにあるはずですが、私は正しい方法でそれを理解していません。

ありがとうございました。

+1

従業員のチームは休日の要求にどのように関連していますか?ここで保護する不変量は何ですか?たとえば、同じチームの他の従業員が重複する休暇を要求した場合、従業員は休暇を要求できますか?あなたは保護しようとしている不変量を知らなくても、適切なAR境界を定義することはできません。 – plalx

+0

@plalx境界線がないとしましょう。ある日に誰も働いていない日があるとしましょう。別のシナリオ:少なくとも1人のチームのメンバーが働いていなければならず、他のメンバーは甘い休暇を取るとします。私が知る必要があるのは、これらの関係をモデル化する方法だけです。従業員が休息を取ることができない場合は、何らかのイベントの再発可能性がありますか?一方、そのような要求をしている従業員は、その日に従業員が誰も利用できないため、休暇申請を送信できないことを知る必要があります。どう思いますか? –

+0

@plalx私の答えを完成させるために、従業員は送信された休暇申請の作者であるため、それを受け入れる許可を得ようとしている他の「従業員」は誰がそれを送ったかを知っています。ですから、基本的に 'HolidaysRequest'はHolidaysRequestMetadataと' Employee'で構成されています。 –

答えて

0

DDDの主な点は、ドメインに焦点を当てることです。その理由は、ドメインと呼ばれる理由です。ドリブンデザイン。

ドメイン、ドメインを構成するものを詳しく調べることなく、関係、集約、およびエンティティについて尋ねると、実際にはドメインではなくデータベースモデリングが求められます。

私はあなたが間違った質問をしていると言っているわけでもなく、批判しているわけでもありません。勉強中に実際に試してみると間違っていないと思います。

私はDDDの専門家ではありません。私はあなたのように学んでいますが、私は助けようとします。

どのような状況が発生する可能性があると考え始めます。Holydays Management。さまざまなルールがある場合は、の戦略(私は最終的な解決策です)を使用して開始することができます。

素敵で意味のあるドメインを構築することは、少なくとも私にとっては難しいことです。あなたはコードを書く。試して。洞察力を持ち、コードを投げて書き直してください。それをリファクタリングしてください。ソフトウェアのライフサイクルでは、ドメインに焦点を当てる必要があるため、常に改善する必要があります。

(ドメインの下書きのように)コーディングを開始して、どのように見えるかを確認します。それを試してみましょう。まず、なぜこのようなものを管理する必要があるのでしょうか?どんな問題を解決しようとしていますか?ああ、時には従業員が休みを求める時、私たちはそれをコントロールしたい。我々は、彼らが「ホリデイ」を望む理由と、どのようにチームのステータスになっているかによって、承認するかどうかを決めるかもしれない。私たちが辞退し、彼らがまだ家に帰ると、私たちは火事か割引かを決定するでしょう。

ここ
public interface IHolydayStrategy 
{ 
    bool CanTakeDaysOff(HolydayRequest request); 
} 

public class TakeCareOfChildren : IHolydayStrategy 
{ 
    public bool CanTakeDaysOff(HolydayRequest request) 
    { 
     return IsTotalDaysRequestedUnderLimit(request.Range.TotalDays()); 
    } 

    public bool IsTotalDaysRequestedUnderLimit(int totalDays) 
    { 
     return totalDays < 3; 
    } 
} 

public class InjuredEmployee : IHolydayStrategy 
{ 
    public bool CanTakeDaysOff(HolydayRequest request) 
    { 
     return true; 
    } 
} 

public class NeedsToRelax : IHolydayStrategy 
{ 
    public bool CanTakeDaysOff(HolydayRequest request) 
    { 
     return IsCurrentPercentageOfWorkingEmployeesAcceptable(request.TeamRealSize, request.WorkingEmployees) 
      || AreProjectsWithinDeadline(request.Projects); 
    } 

    private bool AreProjectsWithinDeadline(IEnumerable<Project> projects) 
    { 
     return !projects.Any(p => p.IsDeadlineExceeded()); 
    } 

    private bool IsCurrentPercentageOfWorkingEmployeesAcceptable(int teamRealSize, int workingEmployees) 
    { 
     return workingEmployees/teamRealSize > 0.7d; 
    } 
} 

public class Project 
{ 
    public bool IsDeadlineExceeded() 
    { 
     throw new NotImplementedException(); 
    } 
} 

public class DateRange 
{ 
    public DateTime Start { get; set; } 
    public DateTime End { get; set; } 

    public int TotalDays() 
    { 
     return End.Subtract(Start).Days; 
    } 

    public bool IsBetween(DateTime date) 
    { 
     return date > Start && date < End; 
    } 
} 

public enum HolydayTypes 
{ 
    TakeCareOfChildren, 
    NeedToRelax, 
    BankOfHours, 
    Injured, 
    NeedToVisitDoctor, 
    WannaVisitDisney 
} 

public class HolydayRequest 
{ 
    public IEnumerable<Project> Projects { get; internal set; } 
    public DateRange Range { get; set; } 
    public HolydayTypes Reason { get; set; } 
    public int TeamRealSize { get; internal set; } 
    public int WorkingEmployees { get; internal set; } 
} 

が、私はすぐにこれを書いた方法です:ユビキタス言語を強制することは、のコードでこの問題を表現してみましょう

  • Holydaysが付与されたかどうか、状況や 理由に応じて、のは作成してみましょうすることができますIHolydayStrategy
  • 空白(プロパティなしHolydayRequestクラスが作成されました。
  • 考えられる理由ごとに、異なる戦略を作成しましょう。
  • 子供の世話をする理由がある場合は、 の合計リクエストが制限を下回っていると、休みになることがあります。
  • 理由は、従業員が負傷したためです。要求を許可する以外に、 という選択肢がありません。
  • リラックスしなければならない理由がある場合は、 の従業員の受け入れ可能なパーセンテージか、プロジェクトが 期限内にあるかどうかを確認します。
  • 戦略のデータが必要になるとすぐに、私はCTRL + .から までをHolydayRequestに自動的に作成しました。

これらのものがどのように格納/マップされるのかわからないのを見てください。私はちょうど問題を解決するコードを書いて、それを解決するために必要な情報を得ました。

明らかに、これは最終的なドメインではなく、単なる草稿です。私はこのコードを取り除き、必要であれば、まだそれのための気持ちを書き直すことはできません。

人々はそれだけで常にtrueを返すためにInjuredEmployeeクラスを作成するために役に立たないと思うかもしれませんが、ここでのポイントは、可能な限り明示ようなものを作るために、ユビキタス言語を利用することで、誰もが同じことを読み、理解するであろう: "怪我をした従業員がいる場合、チームの状況や必要な日数に関係なく、いつでも休暇を取ることができます。"。 DDDのこのコンセプトの問題の1つは、開発者、プロダクトオーナー、ドメインエキスパート、その他の参加者の間での用語やルールの誤解です。

この後、モックデータでいくつかのテストを書くことになります。私はコードをリファクタリングするかもしれない。

この "3":

public bool IsTotalDaysRequestedUnderLimit(int totalDays) 
    { 
     return totalDays < 3; 
    } 

と、この "0.7D":

private bool IsCurrentPercentageOfWorkingEmployeesAcceptable(int teamRealSize, int workingEmployees) 
    { 
     return workingEmployees/teamRealSize > 0.7d; 
    } 

は戦略に存在すべきでない、私の視点では、仕様です。物事を切り離すために、仕様書を適用することがあります。

合格したテストで合理的な初期の解決策を得たら、それをどのように保存すべきか考えてみましょう。ここでは、最終的に定義されたクラス(Team、Project、Employeeなど)をORMによってマップすることがあります。

あなたのエンティティの間にはの関係が生じるので、私は通常、ORMが自分のドメインをどのように保持するのか、この時点で集計は何か気にしません。

非常に重要だとはいえ、私はEmployeeクラスをまだ作成していないことを見てください。そのため、エンティティとそのプロパティを作成することで開始するべきではありません。なぜなら、テーブルとフィールドを作成することとまったく同じですからです。

あなたのDDDはになります。Database Driven Designそうですね、私たちはこれを望ましくありません。もちろん、最終的には従業員を作るつもりですが、必要なときに作成してみましょう。一度にすべてのモデリングを開始しないで、必要なすべてのエンティティを予測してください。あなたの問題に焦点を当て、それを解決する方法。

あなたの質問については、エンティティとは何ですか、私はあなたがそれらの定義を要求していないと思うが、従業員はあなたのドメインを考慮して、ドメインがコードによって明らかにされるとすぐに、あなたは最終的に自分自身に答えるでしょう。 Application Laye rの開発を開始したときには、データを読み込んで自分のドメインに委任する必要があります。私のドメインロジックが期待するデータ、どこからクエリを開始するのか。

私は誰かを助けたと思います。

+0

すばらしい答えをありがとう!その間に、これをインターネットで、特にイベントソーシングのコンテキストで、集約について読んでください。私があなたが協会について書いたことを理解している限り、私はイベント間の一貫性について考える方法を考え始めました。 12月31日(そして今日は6月21日)に休暇を要求する従業員がいるとします。これは長生きの出来事です。従業員のチーム名が変更された場合や従業員の職位が変更された場合、どうなりますか?オンデマンドで最新の値を取得するために、チームアイデンティティへの参照を保持する必要がありますか? –

+0

@KubaT完璧な例です。これは私がドメイン専門家に聞きたいと思う種類の質問です。アソシエーションをどのように作成するのか、集約は、この種の状況の理解に依存します。私が知っている限り、イベントソーシングについて話しても、決して*事柄を削除することはありません。彼らはそこにいたので、あなたのブランドの新しい従業員(新しいチームに所属しているか、自分のポジションを変更した)はもうHolydayを持っていないかもしれません。私はこのコンセプトについても学んでいます。それは私にとってはまったく新しいものです。あなたが結論に至ったかどうか私に教えてください、私は何とか助けることができたらうれしいです。 – Alisson

+0

ESの「削除しない」ことは明らかですが、むしろ関連するエンティティの変更に関する問題を考えました。私の例を見ると、HolidaysRequestが配置され、Employeeデータが含まれている場合、従業員が変更されたときの対処方法は?この具体的なEmployeeが発生したEventStoreのすべてのイベントが検索できません。 HolidaysWithEmployeeのような集計であっても、従業員データが変更されたためだけ更新できません。右? –

関連する問題