Domen驱动的架构和用户拼写错误/错误

时间:2015-08-14 05:36:57

标签: domain-driven-design encapsulation setter

DDD教会我们像现实世界的原型一样构建我们的类。

所以不要使用setter

job = new Job
job.person = person
job.since = time.Now()
job.title = title

我们在聚合根

中定义命名良好的方法
job = person.promote(title, /** since=time.Now() **/)

现在是棘手的部分

假设我们有一个人工智能的用户界面,他/她通过HTML表单输入一个新的title并输入错误信息" prgrammer" (当然在实际应用中,它是一个选择列表,但在这里我们有一个文本输入),或选择一个错误的日期(如今默认)

现在我们遇到了问题。现实世界中没有拼写错误。我们的John Doe绝对是一名"程序员"从来没有" prgrammer"

我们如何解决域模型中的错字?

我们的Person只有promotedemotefire等方法,这些方法反映了人力资源领域的模型。

我们可以稍微作弊并直接更改Job记录,但现在我们有一个Job.setTitle方法,它不反映我们的域模型,而且 setter是邪恶,你知道。

这可能看起来有点像学术界#34;但是当我尝试为复杂的应用程序构建一个好的域模型时,这真的让我感到困扰

4 个答案:

答案 0 :(得分:4)

DDD的另一面是不变量 - “always valid”实体。当你试图打破这个不变量(某些规则)时,你必须停止执行并大声说出“抛出异常”。因此,您需要有一个有效标题列表,当您尝试将标题(无关紧要)更改为无效状态时,您必须抛出一些有用的异常。

要“修复”拼写错误情况,您必须将您的域中的操作分开promote是一项操作(它可能会检查某些内容,发送通知邮件:)等等。和edit操作 - 只是编辑一些属性。因此,差异在于操作逻辑。如果没有一些先决条件(例如,所需的工作经验),则无法调用promote,但您可以调用edit并根据类型修复工作人员的姓名。 通常这个操作在不同的用户之间分开:只有HR可以promote但是工人可以edit他的名字,如果它是错的。 对于这样的例子,这个解决方案非常复杂,但它总是使用DDD。 主要概念 - 单独操作。每个人都有自己的条件,权限,规则。

关于不变量(规则)的question

答案 1 :(得分:1)

如果客户端纯粹输入数据,则此(有界)上下文中的基础域不是很深。在这些情况下,可以使用CRUD样式的应用程序并允许更改标题(setTitle())。

只需确保不存在“无效数据”之类的相关BC(例如,结算,休假计划等),就可以适当地对CRUD上下文中的更改做出反应。

答案 2 :(得分:1)

应用程序应该在到达域层之前强制执行输入正确性,没有垃圾输入。如果这意味着使用作业标题的下拉列表那么就是这样。您可以根据现有标题验证标题。

在我的1.8万名员工的公司中,错字一直在发生。你必须务必务实,并接受代码中的setter(以某种方式)

实用主义思维是域驱动设计的核心,也是让事情变得简单的原因。

"纯粹在理论上是好的,但在实践中它可能很难实现,有时你必须选择实用的方法" - 模式,原则和实践领域驱动设计(2015)

答案 3 :(得分:1)

"在现实世界中没有拼写错误",我理解你的意思,但事实并非如此,在现实世界的场景中存在人为错误,并且应该在你的域中加以考虑如果他们经常。

如果数据输入错误不频繁,则可能不值得进行额外的建模工作,而这些可能只是直接在DB中修复。这也取决于企业是否希望了解这些错误。

但是,如果频繁出现数据输入错误,则可能表明系统可能没有提供足够的指导,业务部门可能希望了解有关这些错误的更多信息,以便提高流程效率并减少错误。

您可能希望在专用于数据更正的BC中实施job.correctTitle(...)之类的操作?此外,可能非常罕见的是每一条信息都是错误的,因此可以隔离纠正操作。这意味着您可能不需要job.correctAllInformation(...)种操作。

这整个场景非常虚构,因为职位通常会在不同的BC中进行管理,而且可能会从列表中选出,因此拼写错误会更少,但是你总是要处理数据输入错误。选择合适的解决方案并不总是很容易,并且会因具体情况而异,但要尽量保持务实,不要在您所在领域的每个领域争取完美的模型。