DDD如何建模时间跟踪?

时间:2017-06-28 08:45:19

标签: domain-driven-design

我正在开发一个具有员工时间跟踪模块的应用程序。当员工开始工作时(例如在某个抽象机器上),我们需要保存有关他工作的信息。每天都有很多员工在很多机器上工作,并在他们之间切换。当他们开始工作时,他们会通知系统他们已经开始工作。当他们完成工作时 - 他们也会通知系统。

我有一个汇总Machine和一个汇总Employee。这两个是具有自己行为的聚合根。现在,我需要一种方法,可以在任何给定的时间段内为任何给定的Employee或任何给定的Machine构建报告。例如,我想看看哪些机器确实给了员工在一段时间内使用了多长时间。或者我想知道哪些员工在这个给定的机器中工作了多长时间。

理想情况下(我认为)我的汇总Machine应该有方法startWorking(Employee employee)finishWorking(Employee employee)

我创建了另一个聚合:EmployeeWorkTime,用于存储有关MachineEmployeestart,finish时间戳的信息。现在我需要一种方法来修改一个聚合并同时创建另一个聚合(或者理想情况下是另一种方法,因为这种方式有点困难)。

此外,员工有一个Shift,用于描述他们每天必须工作多少小时。来自Shift的信息应保存在EmployeeWorkTime汇总中,以便在Shift更改为Employee的情况下保持一致。

改述问题

我有Machine,我有Employee。我怎么能保存信息:

EmployeeMachine从1.05.2017 15:00到1.05.1017 18:31工作。

我可以简单地使用CRUD,在一个事务中保存多个聚合,以数据库优先。但我想使用DDD方法来管理复杂性,因为整个域非常复杂。

2 个答案:

答案 0 :(得分:0)

  

我正在开发一个具有员工时间跟踪模块的应用程序。当员工开始工作时(例如在某个抽象机器上),我们需要保存有关他工作的信息。每天都有很多员工在很多机器上工作,并在他们之间切换。当他们开始工作时,他们会通知系统他们已经开始工作。当他们完成工作时 - 他们也会通知系统。

这里要注意的一件重要事情是,您正在跟踪的活动正在现实世界中发生。你的模型不是不是记录簿;世界是。

EmployeeMachine是真实的世界,因此它们可能不是聚合。 TimeSheetServiceLog可能是;这些是您通过观察现实世界中的活动而构建的聚合(文档)。

  

如果事件源在那里适用,我如何有效地存储域事件以更快地构建报告?每个重要的域事件都应该是自己的聚合吗?

从根本上说,是的 - 您的事件流将成为您观察到的活动。从技术上讲,你可以把它称为聚合,但它是一个非常贫血的;更容易将其视为数据库或日志。

在这种情况下,它可能只是充满了像

这样的事件
TaskStarted {badgeId, machineId, time}
TaskFinished {badgeId, machineId, time}

记录这些事件后,您将它们转发到域模型。例如,您可以使用Bob的badgeId获取所有事件并将其发送到他的时间表,该时间表开始尝试计算他在每个工作站的时间。

  

鉴于Machine和Employee是聚合根(它们在复杂的相互关系网络中有自己的不变量和业务逻辑,时移特征只是其中一个模块)

如果您认为您的数字模型控制着一个真实世界的实体,那么您可能会遇到麻烦。 Digital shopping carts and real world shopping carts不是一回事;当我超出预算时,手机上运行的域名模型无法从物理推车中丢弃。它只能表明,基于其拥有的信息,内容不符合我的预算政策。真相和记录簿是现实世界。

Greg Young在his talk at DDDEU 2016.

中对此进行了讨论

您还可以查看货物DDD样本;特别要注意CargoHandlingHistory之间的区别。

汇总是信息资源;它们是具有内部一致性规则的文档。

答案 1 :(得分:0)

根据我对您的域的理解,您必须为在机器上工作的员工的流程建模。您可以使用Process manager / Saga实现此功能。我们将它命名为EmployeeWorkingOnAMachineSaga。它的工作原理是这样的(使用CQRS,您可以适应其他架构):

  • 当员工想要开始在机器上工作时,EmployeeAggregate会收到命令StartWorkingOnAMachine
  • EmployeeAggregate检查员工是否在其他计算机上工作,如果没有,则会提升EmployeeWantsToWorkOnAMachine并将员工状态更改为wantingToWorkOnAMachine
  • 此事件由从存储库加载EmployeeWorkingOnAMachineSaga的{​​{1}}捕获,并发送命令MachineAggregate;如果机器不是空的,那么它拒绝该命令,并且传奇将TryToUseThisMachine命令发送给RejectWorkingOnTheMachine,然后EmployeeAggregate改变它的内部状态(当然是通过举办事件)
  • 如果机器空置,则会将其内部状态更改为occupiedByAnEmployee(通过举办活动)
  • 当工人停止在机器上工作时
  • 和类似情况。
  

现在我需要一种方法来为任何给定的员工或任何给定的机器在任何给定的时间段内构建报​​告。例如,我想看看员工在一段时间内使用了哪些机器以及使用了多长时间。或者我想知道哪些员工在这台机器上工作了多长时间。

这应由read-models实施,只需听取相关事件并构建您需要的报告。

  

此外,员工有一个Shift,用于描述他们每天必须工作多少小时。来自Shift的信息应保存在EmployeeWorkTime聚合中,以便在为给定的员工更改Shift时保持一致

根据您希望系统的行为方式,您可以使用Saga实现它(如果您希望系统在员工工作时或多或少地工作时执行某些操作),或者如果您只是作为读取模型/报告希望看到那些不符合他们日常班次的员工。