2011-04-06 59 views
10

我试图使从数据中心设计和开发跳入DDD和已经阅读埃文斯和Nillson但我仍然有麻烦缠绕我的头左右,我应该如何构建我的领域层。我敢肯定,我目前的项目的性质没有帮助!真实世界DDD:构建领域层

一点背景

的应用程序是一个内部解决方案来管理人员评估。人力资源人员将创建评估“模板”,其中包含一系列由团队领导和管理人员为其每个直接报告完成的问题。答案是坚持审计和审查。这些评估可以为各种各样的东西,如对公司的举措,绩效评估反馈等

我的数据中心侧

不影响解决方案,但强调我的数据中心心态,我已经为数据库架构愿景,并包括在这里仅供参考(因为一张图片胜过千言万语):

enter image description here

的模式是,正如所预料的,标准化的和不匹配如何数据在我的应用程序中处理。而且,我忽略了查找表等,试图将问题保持在最低限度。

的用例

第一使用情况是检索和显示,用户需要完成的评估的列表。这将在用户首次登录应用程序时显示,起初它似乎相对容易,但有两个折痕:1 - 评估是基于时间的,因此可能需要每月,每年或每'x'基于员工周年日期的年数;并且,2 - 用户可以保存正在进行的评估并稍后完成评估。因此,清单应包含到期的评估以及任何正在进行的评估。

接下来,当用户选择要执行的评估时,我需要检索该评估的所有问题(当前版本),以便我可以将它们显示给用户。在评估过程中的任何时候,用户都可以保存当前结果。只有在整个评估完成后,才可能实际“提交”或承诺。

第三,人力资源需要一种方法来重新生成评估与监督员提供的回应。

最后,HR能够创建和修改评估 - 他们的版本。因此,无论何时修改某个评估,都会创建一个新版本,并且该版本将成为执行任何NEW评估的模板(任何正在进行的评估都将继续使用其原始模板)。

领域模型

工作无序,这对我来说很有意义,我将有一个是聚合根,以满足第四使用情况的评估实体。它将有一个子实体的子集合,该子实体又将有一个子实体集合。他们都是实体,因为他们有身份(是的?)。评估是消费代码用于持久性,验证等的对象(尽管Section和Question实体自我验证并将状态汇总到根评估)。我的目标是从消费者那里做出版本摘要,并在数据持久层中实现它(好的或坏的想法?)

这意味着我还将有一个AssessmentRepository来处理对我的持久性,可能还有一个AssessmentFactory在需要时创建一个新的评估。

更大的问题出现在其他用例中。我是否也有EmployeeAssessment聚合根?还是仅仅是一个实体?

放眼使用的情况下,我需要使用该信息的几种方法。首先,当我生成要向用户展示的评估列表时,我不仅需要根据评估频率评估直接报告列表,还需要知道我是否已经开始和/或完成评估为该员工。这来自EmployeeAssessments表。另一种情况是,当用户实际执行评估时,我正在与EmployeeAssessments和Responses表进行交互。

从用户界面的角度来看,当用户执行评估时,他们对内部数据结构等一无所知。我需要向用户界面提供该评估的问题列表以显示并接受响应列表坚持下去。这是否会导致带有随附存储库的第二个根目录?

第三个用例相似,在于HR希望能够重新生成在以后的应对办法评估。但是,我认为执行评估时使用的过程可以在此处使用,因为恢复现有评估需要相同的数据,唯一的区别是读/写功能与HR的只读功能不同。

把它包起来了!

好吧,我洋洋洒洒够了,想我已经明白我杂念的头。我很欣赏任何方向,建议,批评等等。正如我所说,我试图跳槽,并认为我理解了这些概念,现在这是应用它们的问题。谢谢!!!

回答

5

几年前,我和你自己一样。我现在正在从简单的香草DDD跳到CQRS(请参阅cqrsinfo.com/)。

我会接近这个CQRS方式即使用事件存储,并在architectuaral水平完全分离读取写入。不过,我认为您提到的问题与普通的香草DDD方式更为直接 - 所以我会在这种情况下回答。

你需要完全摆脱思考“数据驱动”。从主要工作流程开始。第一次和第三次使用基本上只是获取操作。我首先会集中讨论聚合根状态改变的用例。因此,使用案例2即“执行评估”将是一个很好的开始。

  • 正如您正确指出的那样,聚合根将是评估。可以创建“PerformAssessmentService”类(相当于域服务),并且您的执行评估工作流将存在此处。这个工作流将完全处于测试阶段,所有依赖项(如存储库)都被简单地删除。

  • 您可能最终编写整个执行评估工作流程,而无需任何具体的数据库/ UI实现等。所有的业务逻辑都是在这个域服务中编排的,并且所有的逻辑都存在于您的评估实体和其他相关实体中。

  • 进入下一个使用案例 - 也许用例4 - 修改评估(做同上一次)

  • 离开外围的东西,如库/数据库,用户界面等,直到尽可能晚地在你的实现。其重要的在您的域名锁定了所有的业务逻辑首先 - 然后从域驾驶你的周围的关注 - 它的便宜得多/更有效(在我的经验)

注意,有没有正确的方式做到这一点,这只是一般情况下我会如何处理上述项目的概要。这里的关键是,该领域真的是一切实施背后的驱动力...

+0

好的,我和你在一起。我们来关注第一个使用案例,我需要为当前用户生成到期或正在进行的评估列表。我正在努力解决包括评估在内的多少逻辑应该在域层中,而不是在SQL中可以轻松完成的。我真的希望让评估域对象包含一个AssessmentVersion对象列表,并让我的规范类创建一个使用“assessment.Versions”的表达式,以便所有逻辑都在代码中? – SonOfPirate 2011-04-07 18:22:28

+0

另外,我认为我将有一个AssessmentService公开一个ListMyDueAssessments()方法,该方法创建MyDueAssessmentSpecification类的实例并将其传递给AssessmentRepository.Find(spec)方法。 Find()返回满足Spec类提供的Expression的评估对象列表。我在正确的轨道上吗?怎么样返回一个更轻量级,更扁平版本的AssessmentInfo类,这与DDD一致吗? – SonOfPirate 2011-04-07 18:25:03

0

我会与使用内存库一个快速和肮脏的原型开始。如果你走的是正确的道路,那么你会得到一个更好的主意。

+0

这就是,不幸的是,正是我所做的,导致了这些问题。你能解释为什么你键入存储库吗? – SonOfPirate 2011-04-07 10:47:47