领域驱动设计DDD入门7:加速工具和管理工具

发表于2019-10-25,长度6413, 130个单词, 18分钟读完
Flag Counter

这是本系列最后一课:加速和管理工具。如何加速DDD建模并在项目中应用?如何在敏捷项目中使用DDD?我将在这堂课中讲解。我会先讲事件风暴方法,可以快速建模和获取知识。然后讲敏捷先如何使用DDD,会附带一些额外的工具。后面我会教你如何标识任务和估时。最后说一下时间盒模型。

当使用DDD时是在获取知识,我们在学习业务。我们需要根据业务知识进行高效建模,以便把我们的业务优越性也体现在软件优越上。所以是尝试的问题:通过挑战我们的模型,反复尝试,钻研业务知识,形成更好的模型。而对于我们快速迭代的公司,要求野蛮生长,反而是时间的问题。我们总是“活”在项目deadline的边缘,不断被催促。怎么才能协调高效建模和快速实现的矛盾呢?假如我们设计得很好,实现得很漂亮,但是逾期交付了,那也是项目失败了!我们该怎么办? 这里介绍一些加速工具和管理工具,这些工具有助于在项目中实践DDD并符合项目工期约束。多说一句,有些人尝试了一种称为“无估计”的技术,这种技术轻视任何类型的评估,这些评估可能几天或几周或几个月甚至一天,团队会尽量避免做出估计,因为他们说这些估计不准确。 我认为与我合作的大多数客户都是不可接受无估计方案的,他们大多数仍处于时间约束,非常严格的时间约束之下,他们需要提供估时。这该怎么办?我们被要求必须估时,而估时既耗费时间又不准确。这里也提供一种方法来跟踪您的时间和领域专家的时间,并准确估算实现高效模型各个组件所需的时间。因此,我们必须在时间约束内建模。我们的目标是了解业务和领域并进行有效建模,并不断完善模型。我们需要花费时间去掌握业务知识,但如果我们不快速学习和建模,即使有良好的产出,我们也是失败。我们必须限定建模工作的时间,但绝不能尝试以任何方式消除设计,因为如我们先前所讲的,没有设计就是谬论。那么当我们面对时间挑战,我们该怎么做?我们将使用一些建模加速和管理工具,比如事件风暴和敏捷估算。这里讲的技术将可以与任何敏捷框架一起使用。

事件风暴

事件风暴是一种加速建模和获取知识的技术。使用事件风暴,我们要做的是专注于业务流程,而不是数据、数据库或数据模型。我们的首要重点是业务流程中的操作,我们会将其建模为领域事件。我们还将对域事件的起因(即命令)进行建模。我们还将对聚合或实体建模,如果愿意的话,命令将在其上发生并导致发出域事件。使用事件风暴时,团队中的每个人,领域专家和开发人员,都在一起学习,会互相学到很多东西。这是一种非常快速的建模方法,并且很有效。每个人总是从经验中学习。开事件风暴会议时最重要的事是合适的人员。应该始终拥有整个领域专家团队或至少一个领域专家,以及开发人员,永远不应将专家排除在外。 基本上,事件风暴与询问正确的问题有很大关系,正确的问题只能由正确的人提出,并且由正确的人回答。这也是为什么始终让领域专家参加事件讨论会议。团队中的每个人都能学到东西。

事件风暴会议

首先,我们需要便签纸。这里有一系列便笺,主要用于事件。事件将在橙色贴纸上建模,命令将在蓝色便笺纸上建模,聚合或实体将在淡黄色上建模。可能还有其他种类的便利贴,例如红色记录在建模会议中可能需要注意的警告或错误,绿色用于建模用户接口组件或视图,淡紫色或紫色对模型中发生的策略或过程进行建模,黄色记录用户规则或角色。也可能还需要更多种类的便贴,例如白色等等,但这些可能是您需要的少数。另外建议使用合适的笔,太大的笔在便签上写不了太多东西。

我们还需要一个好的建模平面,比如一张宽大的纸,最小也得10米(what?…)。实际上,我们希望建模平面是无限的呢,所以多拿几张大纸。当然可以尝试在墙壁或白板上进行建模,但是我发现便签纸在白板或墙壁上不太能粘住,在纸上效果更好。你可以去艺术品商店,或五金商店或类似的商店购买,宜家一般也有这种纸(国内的好像没有…逃..)。拿一卷纸,用厚胶带粘在墙上,这就是我们的主要建模平面。 我们的建模元素是:橙色便笺纸为事件模型,蓝色便笺纸为命令,黄色便笺纸为聚合。这些是我们的三种基本建模元素。同样,策略或流程以淡紫色或紫色的粘滞便笺为模型,绿色用于用户接口视图,用户角色以黄色建模。

第一步:按照时间顺序建模事件

第一步,团队中的某人需要拿橙色便签,并在上面写一个事件。这是一个事实:域模型中发生了某些事情。将该事实命名为过去时的动词。例如我们之前所讨论的,productCreated 或backlogitemCommitted,事件就这样命名。这个事件不一定是要建模的核心域中可能发生的第一个事件,可以选择在业务流程中间发生的事件。重要的是要使第一个事件出现在建模平面上。

它提供了一个开始建模的地方,并且提供了一个提出有关问题并获得正确答案的活动。你将按时间顺序从左到右构建一系列域事件。如你所见,箭头显示了穿过整个业务流程模型的时间。最早发生的事件在最左边,然后随着时间的推移,下一个事件发生,下一个,下一个以及最后到最右边,最右边是业务流程中发生的最终领域事件。

这是第一步,可能需要一些时间。可能要花一两个小时来处理所有域事件。如果感到疲倦,或者团队中的每个人都开始对流程失去热情,那么该休息一下了。暂停会议几个小时甚至一天。如有可能就睡在大纸上(what,这就是要10米大纸的原因吗…),第二天继续会议,可能就会发现很多在第一次开会中遇到的问题,第二天将能够取得更好的进步。

第二步:给引起事件的命令建模

下一步是对导致域事件的命令进行建模。同样注意,我们要有意远离数据。在此过程中,我们并不是最先关注聚合或实体。你可能发现单个命令实际上会导致多个域事件,可能还会发现某些命令导致域事件并行发生。如果是这样,并且只有在开始对命令进行建模时才发现是这样,可以垂直表示发生的并行事件。因此,并行发生的事件是使用垂直空间而不是水平空间,上下并列就表示某些事情同时发生。

现在我们正在建立时间轴,并且有一系列有时序的命令和事件、命令和事件、命令和事件。第一条命令在建模平面的最左侧,而最后一条命令和事件在最右侧。

第三步:对聚合进行建模

领域专家可能对聚合一词不满意,你可以将其称为模型的实体,或者可以称为模型的数据。 对于领域专家而言,了解聚合或实体具有行为并不重要,但他们可以理解数据将接收命令,处理该命令并产生域事件。因此可以将聚合叫成任何名称,只要领域专家可以理解。

从最左边开始,我们有一个聚合或实体来处理命令并发出域事件。然后,我们有了下一个处理命令的聚合,并发出一个域事件,依此类推,直到到达图的最右边为止,那里我们有与聚合或实体相关的最终命令事件对。注意,随着时间的推移,同一聚合可能会收到不同的命令,要记得使流程保持时间顺序。 因此,不要对单个聚合或实体采取多个命令和事件,它们都要按时间顺序写在多个黄色便签上。所以如果同一聚合随时间推移收到不同的命令,那么就复制黄色便签,用相同的名称创建第二个、第三个、第四个黄色便签,然后将其移动到合适的时间序列区域。这对于使时间顺序保持正确非常重要,这样随着时间推移,模​​型中发生的事情就可以准确地表示时间。

第四步:确定上下文边界

在前面的建模过程中,你可能已经意识到其中一些适用于核心领域,而另一些不是。某些命令和事件将发生在属于其他有界上下文的实体上。怎么确定上下文边界呢? 尝试准确地确定什么是核心领域,什么对你们公司而言具有重要意义和竞争优势,哪些不是。无论是支持型的还是通用型的,都应移到其自己的有界上下文中。

现在你可能需要在图上绘制显示事情发生时间的线,还需要画椭圆形标志上下文边界。可能在某种程度上需要重新排列便签,但是不想失去顺序信息。这就是事件风暴的建模从大方向转为详细设计的过程。一开始我们使用事件风暴对大局进行建模,但是随着时间的推移,建模工作会越来越深入。也许在第二或第三次建模会议之后,将开始接触越来越多的细节。这很自然但很重要,实际上就是我们想要达到的。我认为,事件风暴在设计或实现模型时非常重要。你不会学习到所有细节,正如我之前课程所描述的,这将留给创建场景和验收测试的会议,但是将了解一定程度的实现细节,这有助于我们未来的建模工作。

第五步:其他

可能需要了解对用户很重要的某些视图,写在绿色便签上。

另一个建模步骤是确定某些策略。执行业务策略的过程很复杂,将策略或流程标记为淡紫色或紫色表示它的复杂性,策略将接收事件并发出命令。这很典型,因为策略是对域事件做出反应并告诉其他聚合该怎么做。因此,实际上它与聚合相反,尽管它类似于聚合,但是聚合接收命令并发出事件外,策略将接收事件并发出命令。你可能还会发现,即使在第一步建模域事件中,也可能较早地确定策略。如果是样,继续前进,并确定对整个业务流程至关重要的策略。

敏捷框架中的DDD

接下来,我介绍一些在敏捷执行框架中使用DDD进行管理的方法。首先请记住:拒绝任务板乱放。假设下面是你要使用的敏捷看板,其中包含待办事项列,进行中列和完成列。设计工作是从待办事项列中删除一个对象(例如appointment实体),并将其放入正在进行的列中,我们称其为“设计”。这实际上是不好的设计。

在我进行讨论时,我将主要就Scrum进行讨论。但是它仍然特别适用于看板或任何其他敏捷过程。有时,我可能会指出看板和Scrum的不同之处,但是您仍然可以用我将要展示的技术

在开始之前我要说的是,在敏捷项目上使用DDD时还可以应用其他工具。其中之一是SWOT分析图或建模平面。

在这里创建四个象限,分别是优势象限(strength)、劣势象限(weakness)、机会象限(opportunity)和威胁象限(threat),这就是SWOT名称的由来。可能你以前使用过,这不是新技术。但是,在确定优点和缺点、机会和威胁时会很方便。在优势象限中确定有利的事情;在劣势象限中找出需要改进的地方;在机会象限确定需要集中精力的地方;在威胁象限中写下必须克服的障碍。 这可以帮助您了解需要重点关注的事件风暴,需要设计验收测试的地方以及需要与领域专家一起的时间。最重要的是,我们要通过SWOT分析或任何其他工具确定模型中存在的知识缺口。因此,无论是否使用SWOT分析都要找到需要建模的地方,识别并使用所需的任何工具来取得好的结果。知识获取和消化将导致建模方面的突破,如果使用事件风暴则尤其如此。

DDD项目中会出现建模高峰和建模债务。我认为你将面临建模高峰和建模债务,我喜欢这术语,因为它非常适合敏捷框架,尤其是Scrum,但它也可以与看板一起使用可能在项目开始时就有一个建模高峰,你可以在高峰期间使用事件风暴,因为您可能要花几个小时到两三天来解决建模高峰。然后可以拿到事件风暴会议的结果,编写验收测试,并根据验收测试试验模型。这将帮助你和领域专家一起解决一些早期的设计和建模问题。该模型将需要不断完善,因此不要以为建模高峰会表达明白所有需求。绝对不会,模型将需要随着时间的推移不断完善。我还认为会有建模债务。可能因为时间关系,你有先修知识还没有或放到之后的学习,试验的结果让你想重构模型。但是由于时间原因,例如冲刺或迭代,每次都有一些未完成的建模。你希望在以后的冲刺或迭代中完善域模型,这自然会招致建模债务的积累。因此,必须在将来的某个时候偿还建模债务,因为你现在没有时间这样做。不要忽略这一点。

任务估时

现在我们想找到要执行的必要任务,以及如何估算每个任务所需的工作时间。在前面的时间风暴会议中当在确定实现细节时,实际上可以估算出单位。

如果我们已经确定了某种程度实施细节的聚合,也确定了聚合发出的命令和事件。因此,这些自然可以成为估计单位。假如此处以AdCredits聚合,以Consume Credit命令,以AdCredit Consumed事件为我们的估算单位,或者将AdSpot聚合、DefineDeSpot命令和AdSpotDefined域事件为单位,这使我们有一些估算单位。现在,我们可以创建一个表,标题为“组件类型”,后跟“简单”、“中等”和“复杂”3列。例如,一个易于实现的领域事件可能只需要一个小时的1/10或大约六分钟即可;一个中等复杂的域事件可能需要2/10小时或大约12分钟实现;复杂的域事件可能需要3/10个小时。我们可以为命令创建一行,为聚合创建一行。这可以扩展到任何其他种类的产品类型或组件类型,例如域服务、视图、流程管理器。无论哪种组件,我们都可以定义几分钟或几个小时为实现简单或中等或复杂任务的时间。 比如我们采用上图中的估算单位。AdCredits聚合、Consume Credit命令和AdCredit Consumed事件是简单还是复杂的呢?在事件风暴会上记录每个事件、命令、策略、视图等的实现估时,您最终将得出一个所需的目标估计时间。你要了解,起初在基于指标的估算过程中并不完美。以后在学习过程中,可能必须在简单、中等、复杂中调整。可能需要增加一些时间,也可能需要减少一些时间。 还应了解,这些估值要包括其中的单元测试时间。因此,如果您估计一个复杂的聚合需要四个小时,那么四个小时的估算就不准确。如果需要两个小时来执行单元测试,则应该将复杂性估计为六个小时。

现在我们看如何使用时间盒建模。我们的估计单位是从刚刚的表中得出的,我们现在将开始时间盒建模。

在“待办”列中,我们认为AdSpot聚合需要一个小时,命令花费一个小时,所有事件将花费一个半小时。我们有某种付款方式,大约需要30分钟才能实现。其中可能会有一些错误,比如创建命令可能用不了整个小时,事件也可能不会花费一个半小时,分配给AdSpot命令和AdSpot事件的某些时间可以合并到AdSpot聚合中。总之,时间可能会相当准确。在“进行中”列里有Appointment聚合,Appointment事件和ServiceShop聚合,已完成列中有另外一些。当有了实际耗费时间时,在便笺上记下实际时间。如果超出了在时间框中分配的时间,留意为什么超支了。是因为以较低的准确性错误估计了此聚合的复杂程度吗?如果是这样,要随着时间的推移学习更好地估计聚合的复杂性。

完善模型

我说过你可能还不具备实现事件风暴会中的所有细节所需要的能力,所有仍然需要制作场景和验收测试。例如,我们的场景一导致某种形式的验收测试,无论它是单元测试还是BDD。我们创建针对聚合A的测试,测试将证明聚合A根据领域专家信息、对话以及实验和协作是否有效。因此,当我们进行测试时,我们还将生成聚合A的实现方案。聚合A具有命令A1和事件A1。事件A1导致聚合B的最终更新。 这样可以将聚合A视为待办,聚合B视为冲刺,事件A1将是待办的提交事件。对聚合A1的测试牵引出了聚合A的全部行为,你就明白还需要设计聚合B或冲刺。而这导致了场景二的创建和针对聚合B的测试,并且针对聚合B的测试会导致对聚合B的优化。然后引出了场景3,如此反复。因此,可以看到场景设计会引出单元测试、模型的完善。场景之间的快速迭代帮你理解遵循通用语言的模型的完整实现。

现在的问题是,您需要多少时间与领域专家联系?根据我的经验,专家的时间可能非常有限,因此您不能过度使用他们的时间。如何限制时间并在模型优化中仍然有效?当然了在事件风暴会期间肯定需要专家参与。但是那时候是建模高峰,定义场景时还需要领域专家的时间。场景模型更为详细,很有必要与领域专家进行讨论。例如,对于集合A的测试需要领域专家来检查,根据验收测试来验证模型的正确性。必须假定测试从一开始就遵循通用语言并根据一开始定义的场景使用了质量测试数据。在继续开发模型、聚合A和命令A1的实际实现以及事件A1时,需要与领域专家一起来完善语言、名称、命令、事件,甚至测试数据都是在领域专家和整个团队的帮助下确定的。尽量将与专家的时间限制为高质量的时间,每次测试和建模可能只需几分钟。

<结课>
Written on October 25, 2019
分类: dev, 标签: ddd
如果你喜欢,请赞赏! davelet