【万字长文】详解每日站会的各种模式
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了【万字长文】详解每日站会的各种模式相关的知识,希望对你有一定的参考价值。
参考技术A本文首发于微信号“小船哥说敏捷”。
每日站会已经成为许多团队的常见仪式,特别是在敏捷软件开发中。然而,有许多微妙的细节可以帮助我们区分是在有效的开会还是在浪费时间。
每日站会(也称为“每日Scrum”、“每日小会”、“早晨点名”等等)描述起来很简单:
整个团队每天都会开会快速更新状态。站起来是为了保持会议的简短。
就是这样。
但这个简短的定义并没有真正告诉你通过哪些细节来区分团队是在有效的开会还是在浪费时间。
那你怎么能知道呢?
对于有经验的从业者来说,当站会出现问题时,他们会本能地知道该如何调整来解决这个问题。
但是对于新手来说,当进展不顺时,他们不太可能知道该怎么做……而且更有可能的是,在没有外在帮助的情况下,他们会干脆完全放弃这一实践。
如果出现这种情况那将是很不幸的,因为运行良好的站会会给团队带来巨大的价值。
为了解决这个问题,重要的是要明确每日站会常用模式的收益和问题。这些每日站会的模式可以帮助经验不足的从业者,也可以提醒经验丰富的从业者关注他们直觉背后的原因。
随着音乐的想起,就像巴甫洛夫的铃声一样,团队会在没有任何额外提示的情况下起身走到贴满卡片的看板前站好。这首特定的歌曲会在每天早上同一时间循环播放。一些人将卡片移动到工作流的正确位置,或者在不同颜色的便利贴上贴上附加说明。一些对项目感兴趣的项目组之外的人也在这里徘徊,查看工作的进展情况。
注意到大家都在看板墙边准备就绪,团队负责人启动了团队之前购买的一个大屏计时器:他们对每日站会实际花费的时间很感兴趣。
一个团队成员站出来谈论看板最右侧最靠近部署点的卡片。他的部署脚本仍然存在一些问题。另一个小组成员说她可以帮助解决这个问题。人们按照从右到左,从上到下的顺序阐述每个工作项的情况,如果其他人能帮助解决障碍他们就会自行发言。另一边,团队负责人正在改进板上记录提出的障碍。
有一次,大家在探讨如何处理一个特定问题时讨论的时间略长。注意到有一个停顿,团队负责人正准备举起手指打断他们……就在这之前,其中一个团队成员建议他们应该线下再讨论。
不久之后,所有的卡片都被覆盖到了,团队负责人问还有没有人要补充。有人提出她有一个关于新功能的有趣想法,该想法可能会使一些计划中的需求变得更好。这激起了总是试图参加站会的产品经理的兴趣,他们都同意在会后继续讨论这个问题。
当团队开始进行传统的结束仪式时,大家齐喊“1…2…3…精益求精!”团队负责人翻了个白眼,这不是他的事,但他不得不承认,这让站会在愉快中结束。
人们分散开并开始讨论提出的各种事情,包括障碍、新想法以及关于某些工作项的问题。
当一群人试图作为一个团队一起工作时,每日站会是一种针对一系列特定问题的重复性解决方案。
每日站会是一种定期同步的机制,以便团队…
每日站会的模式通过回答以下问题来给出:
以下人员和代表都可出席:其他领域(如市场、生产支持、高管、培训师等)的人、希望了解项目状态和进展的人、在必要时可以贡献出自己一份力量的人。在多个会议和报告中传达项目状态需要大量的重复工作。
因此
用每日站会来取代部分或全部会议和报告。任何直接参与或想了解项目日常运作的人都应该参加这唯一报告项目状态的会议。
但是
如果有人之前没有参加过每日站会,他们可能不知道会议的流程,他们可能会做出一些扰乱站会秩序的行为。这可以通过提前告知新参与者和观察员预期的行为规范来解决。
并非所有形式的报告内容都会(也不应该)被站会所涵盖。例如,项目的整体进展可以通过一个 大型可视化图表 进行沟通,这个图表可以是 燃尽图 、燃起图、累积流图等等。
也被称为: 以故事为中心的站会
人们有时会过度 专注于跑者,而忽略了指挥棒 。也就是说,每个人都很忙,但工作项却没有取得应有的进展。
因此
与其把每日站会视为是人的仪式,不如把它视为是工作项(例如,敏捷开发中常用的用户故事)的仪式,人们参会只是为了替工作项发言……因为很显然工作项是不会说话的。
昨天-今天-障碍 的问题仍然可以使用,但会从工作项而不是人的视角来使用。这也意味着可能并不是每个人都会发言,我们没有义务说任何与工作进展无关的事。
因为有了更清晰的焦点,人们才更有可能在没有提示的情况下提出障碍,并登记和解决障碍。
但是
不要求所有人都发言可能会掩盖那些害羞或不愿意说话的人的问题 。这在以工作项为重心的情况下更难发现。
也被称为: 三个问题
有些人很健谈,并且倾向于在讲故事的时候发散很多东西。还有些人在听到一个问题后就想立即解决这些问题。时间过长的会议往往会导致大家注意力不集中,与长时间讨论没有直接关系的参与者往往就会分心。
因此
可以用以下的格式来组织每日站会:
这些是满足每日站会目标的最小子集的问题。其他的讨论话题(如讨论设计、闲聊等)应该推迟到会议结束后进行。
Olve Maudal建议,这些问题的顺序应该倒过来,以突出问题的重要性:
Lasse Koskela以另一种形式提出了这些问题,他强调团队成员不应该 向领导汇报 :
Jonathan Rasmussen提供了不同的措辞,以改变站会的态势:
也有一些团队增加了额外的问题:
但是
每日站会问题的结构只是手段,在站会上同步进度、问题、风险、障碍等项目信息才是目的。如果通过这些结构化的问题我们收集不到想要的信息,那么就要考虑换一个问题清单了。随着团队的成熟,你可能会发现你想调整这些问题的结构,这也反映了这种模式是如何演进的。
更严重的问题是, 昨天-今天-障碍 可能会造成对个人承诺的过多关注,而不是关注正确的事情……这个问题可以参考“ 走板 ”。
也被称为 :阻塞板、障碍板、改善报(Kaizen Newspaper)
在站会中提出的障碍没有被及时解决或以其他方式解决。
因此
将提出的障碍张贴到 改进板 上。这是一个公开可见的白板或图表,用于记录已提出的障碍,并跟踪其解决进度。 改进板 可以在站会之外进行更新,并作为一种更直接、也许对抗更少的方式来初步提出障碍。一个常见的错误是描述障碍的字写得不够大,导致人们无法从远处阅读它。
把一个问题写下来并明确地承认它,这个行为是减少冗长讨论的非常简单、可靠的方法。因此,即使不是每个人都同意某个特定事项是一个障碍,也值得把它简单地记录下来,以便在会后讨论。
在每个提出的障碍上可以包括一个发生次数的统计,这样可以突出哪些问题通常更重要,需要首先处理。
改进板的设计可以有几种不同的方式。例如,一个板的结构如下:
另一种风格更像是一个任务板:
但是
如果在 改进板 上提出了太多团队无法解决的障碍,那么改进板就有可能演变成一个抱怨板。
在站会开始前,与会者需要知道谁应该先发言。由主持人决定谁应该先发言是一种微妙的、但肯定是反自组织的模式。团队应该知道谁先发言,而无需任何干预。
因此
同意 最后到达的人最先发言 ,这是一个简单的规则,同时它还有一个好处,就是鼓励人们准时出席站会。
但是
最后到达的人也可能是最没有准备好开始会议的人。
在站会期间,与会者需要知道接下来应该由谁发言。由主持人决定谁下一个发言是一种微妙的、但肯定是反自组织的模式。团队应该知道下一个发言的是谁,而不需要干预。
因此
使用一个预先确定的简单规则(如 顺序发言 )来确定下一个发言的人,顺序是顺时针还是逆时针并不重要,重要的是由团队主持会议,而不是由主持人或经理主持。
在简单的、可预测的排序机制下(如 顺序发言 ),与会者很容易忽略其他人的发言,直到接近轮到自己时才会集中注意力。在没有轮到自己时,他们可能会想一些其它事情,而不是注意别人在说什么。
因此
引入一个不可预测的排序机制,比如使用发言令牌(比如,一个球)来决定接下来谁应该发言。有了发言令牌,也就简化了决定谁先发言的过程,因为这将是碰巧拿到令牌的人(或他/她将令牌扔给的第一个人)。
传递令牌为每日站会带来了一些乐趣,同时避免了大家注意力可能不集中的问题。
我第一次了解到这种模式是在我和Simon Stewart合作的一个项目中。我们当时用的是一个小杂耍球,但几乎任何东西都可以用作令牌。其他团队也用过橄榄球,甚至是毛绒玩具。
但是
对于较大的团队,可能很难记住谁已经发言了。在这种情况下,继续使用像 顺序发言 这样的简单机制可能会更容易。
根据组织甚至团队的文化,拿一个球传来传去看起来可能不太专业,并且可能会让人对每日站会这个基本仪式产生不必要的负面看法。
在站会期间,与会者需要知道谁应该先发言,之后谁应该接着发言。由主持人决定谁应该发言是一种微妙的、但肯定是反自组织的模式。团队可能并不热衷于 传递令牌 ,因为通常他们手中拿着咖啡杯。
因此
可以让每个团队成员 拿一张卡片 来决定发言的顺序 。想象一下,有一叠卡片,每张卡片上都有一个数字,当每个团队成员来到会场时,他们可以选择一张卡片,然后告诉他们以什么顺序发言。
又称作为 :走墙
人们更专注于繁忙的工作,而不是真正的工作进展,所以这促使你切换到了让 工作项出席 而不是人出席的模式。然而,即使采用了这种专注于工作项的站会,在使用了诸如 顺序发言 或 传递令牌 等排序机制时,仍然很难理解项目的状态如何。
因此
走板 ,即通过走过可视化看板/任务版上的每个工作项来组织站会。
大多数敏捷和精益团队都会使用一个可视化管理系统来展示正在处理的工作。对于敏捷软件开发来说,这个可视化管理系统可能被称为“任务板”、“故事墙”或“看板”。这些板将展示工作项将流转的流程。进展通常是通过在板上移动卡片来表示。理想情况下,工作项的上下位置将表示优先级。
有了这个板,参加站会的人会从流程结束到流程开始(例如,从右到左)以及从最高优先级到最低优先级(例如,从上到下)的顺序检查工作项的进度。你甚至可以在板上明确指出应该使用什么顺序。
Pawel Brodzinski提出了一个 默认顺序 :
但是
显然,拥有一个看板/任务板是一个先决条件,但这并不是所有的团队都会有的。在这种情况下,逐人发言的模式会更合适。
如果不采用 轮流主持 或其他自组织的模式, 走板 更容易走向 向领导汇报 的泥潭。
工作场所有许多关于正在发生的事情的记忆触发器。
我们也不希望这种每日会议需要大量的精力来查找、预定并走到会议室。
因此
在工作现场开会 ,而不是在会议室。如果你有一个“故事墙”或“看板”,最好就在它前面开会。
但是
在“故事墙”或“看板”前面开会,会议的噪声可能会打扰到附近的人。这通常表明工作空间的设计是有问题的,但必须承认这个问题的存在。
我们希望团队对会议有一种主人翁的感觉。我们也希望感兴趣的利益相关者能够前来观看站会,以避免安排另一个类似的状态同步会议,如果允许某个团队成员随意推迟时间或改变地点,这些好处都将难以实现。
因此
让团队达成一致并在 同一地点、同一时间 举行每日站会。不要等待迟到者,包括架构师和经理。会议是为整个团队开的,而不是为某个特定人开的。如果你 使用站会作为一天工作的开始 ,这一点尤其重要。
一些更严格的团队可能会对迟到者处以罚款。我倾向于对任何形式的惩罚机制保持谨慎,而是更喜欢把这些事情拿出来公开讨论。
但是
同一地点,同一时间 并不是盲目地僵化。这里要重点强调的是,开始时间要基本一致,重新安排时间的情况应该会很少。如果需要经常重新安排会议时间,这可能是一个迹象,表明开始时间应该调整。如果一个特定的地点对每个人来说都很不方便,这可能也是一个迹象,表明这个地点应该调整。
每日站会提供了对未决问题的关注和觉察。如果站会发生在一天的晚些时候,这种关注和觉察就会被浪费掉。
因此
使用站会作为一天工作的开始 。由于很多公司采用弹性工作时间,并不是每个团队成员都会在同一时间赶到工作地点,应对“弹性工作时间”的一个常见做法是使用一组核心工作时间,即在某个时间段内团队成员是都在公司的(例如,中午12点到下午4点)。站会开始时间应该是在这组核心工作时间的开始。同样,如果团队成员因个人原因经常需要晚一点到达(例如,需要送孩子上学),那么开始时间应该设定在一个让所有人都能参加的时间。
但是
在站会之前,人们可能会倾向于不处理任何与项目相关的任务。如果 站会很晚才开始 ,工作时间的浪费可能就很严重。一般情况下,人们可能只会用来做一些检查电子邮件、填写时间表等工作。但将站立作为“一天的开始”,并将其安排在一天的晚些时候,这个实践或许值得研究一下。
站会往往作为设定一天工作焦点的仪式,特别是如果你 使用站会作为一天工作的开始 。正因为如此,团队成员往往在站会之前不会去做开发工作。当站会开始较晚时,这种倾向可能会对生产力产生重大影响。
因此
不要使用站会作为一天工作的开始 。不要把每日站会安排在早晨举行,这样就不会在心理上把它当成一天的开始。
但是
如果每日站会不是一天的开始,那么它就不能再用作在一天开始时设置团队工作焦点的共同的仪式了。根据团队的不同,这个代价可能抵不上效率的明显提高。
当有很多项目使用站会时,可能会有多个站会同时举行。对多个项目都感兴趣的观察者可能希望改变站会时间,以便他们都能够参加。这是有问题的,因为如果观察者可以强迫站会调整成他/她的时间表,这会危及团队的主人翁意识。尽管如此,在决定什么时候举行每日站会时,这也必须是一个考虑因素。
说话的音量会影响注意力以及沟通的有效性。物理距离会改变沟通所需的音量大小。有些人不会大声说话,而且觉得这样做不舒服。
因此
站会的时候应该更像是一个 抱团 ,而不是一个会议。如果难以听清,就让每个人都靠近一点。除了允许更轻松的说话音量外,身体的距离往往会使参与者更加专注。能够站得更近也是团队成员彼此信任的一种表现。如果大家还不熟悉站会,通常只需用手势招呼人们,并说一些类似“让我们围成一圈”的话就可以开始站会了。如果圈的大小已经有一段时间没变了,在试图缩小圈子以便让人们靠得更近之前,可以考虑解释一下缩小圈子的原因。
但是
团队必须平衡好亲密关系和个人隐私。即使在一个彼此非常信任的团队中,也存在人们因站得太近而不舒适的情况,症状往往是参与者紧张和/或烦躁不安。
有些人很健谈,并且倾向于在讲故事的时候发散很多东西。还有些人在听到一个问题后就想立即解决这些问题。时间过长的会议往往会导致大家注意力不集中,与长时间讨论没有直接关系的参与者往往就会分心。
因此
让所有与会者在会议期间 站起来 。利用站会将身体与感觉联系起来,当会议时间过长时,身体的不适就会提醒与会者。鼓励这样做的一个简单方法是在没有椅子的地方举行会议。
但是
站起来往往会使会议缩短,但并不能保证会议缩短到最佳长度。人们可能会慢慢适应这种不适,而不是尝试去缩短时间。另外,如果会议不会花费太多时间,也不会偏离主题,那么站起来就是一种不必要的仪式了。
大多数人在开长会时都会精神恍惚。以冗长的会议来开始一天的工作,这将是一种可怕的、耗费精力的方式。一个具体的时间要求有助于提醒我们何时应该考虑减少会议的时间。
因此
将每日站会的时间控制在 15分钟或更短 。一般来说,15分钟后,普通人的注意力就会飘忽不定,这不利于设定工作的重点。
但是
15分钟对于较小的团队来说可能还是太长了。由于注意力的影响,即使对于较大的团队,15分钟也是一个很好的限制。另外,也要注意有可能因为会议时间太短,在会议结束时,与会者仍然不知道发生了什么事,也不知道该和谁谈以了解情况。
在最后一个人发言后,团队可能不会立即意识到会议已经结束。当人们逐渐意识到会议结束而各自离开的话,这不能让会议在愉快中结束,反而会导致 低能量 。
因此
用一句话(例如, 好了,大家享用午餐吧。 )或其他一些动作来表示站会的结束。
很难定性地判断一个会议是否耗时过长,尤其是当它的长度逐渐增加时。
因此
为会议计时 并公布结果。大多数时候,与会者并没有意识到讲故事的影响、没有准备好“线下解决”或者没有准备好会议需要多长时间。我们最好让会议时间可量化。
但是
与所有措施一样,除非由于精力问题而又要完成实际的目标,否则不应该强制约束会议的时间安排。一旦目标完成,就应该放弃度量。没有特别原因的度量会导致怀疑和对度量指标的冷漠。
时间是精力、注意力和节奏的代表。比起时间,更要注意这些东西。
有些人在听到一个问题后就想立即解决掉这个问题。时间过长的会议往往使人精力不足,与长时间讨论没有直接关系的参与者往往会分心。承认需要线下进一步讨论以解决提出的问题是很重要的。不过有些人会觉得通过打断别人的发言来维护站会的时间可能让人不舒服。
因此
使用简单而一致的短语(如“ 线下解决 ”)提醒此类讨论应该在每日站会之后进行。如果讨论的内容就是闲聊,就不需要再做什么。如果讨论的是问题的解决方案,主持人(最终只应有团队)应确保提名或登记合适的跟进人,以便稍后处理问题。
另外,有些团队使用更多的间接信号。
例如,Mike Cohn描述了一个使用 橡胶老鼠来表示“我们正在进入一个老鼠洞” 的例子。
Benjamin Mitchell描述了一个两手法则(Two Hand Rule):
但是
解决问题 和澄清问题之间是有区别的。不被理解的信息是没有用的。允许澄清问题的程度应取决于团队的规模以及是否会影响“15分钟或更短”。
团队成员倾向于 向领导汇报 ,也就是说,他们只与会议主持人交谈,而不是相互交谈。只有会议主持人在提出和解决与站会有关的流程问题。我们希望团队能够拥有站会的所有权,这就需要消除对单一主持人的依赖。
因此
轮流担任主持人 。轮流担任主持人的角色,负责确保人们参加站会并遵守商定的规则。
但是
没有站会经验的团队可以从有经验的教练中学到很多有用的知识。但是更重要的是,应该让团队对站会有更大的主动权。在某些时候,应该根本不需要明确的主持人。
团队成员倾向于 向领导汇报 ,也就是说,他们只与会议主持人交流,而不是彼此交流。我们希望团队能够掌握站会的主动权,这就需要消除对单一主持人的任何依赖。
因此
作为一种巧妙的提醒发言者的方式,主持人应该 断开眼神接触 ,让他/她对着团队而不只是对着主持人讲话。这样做的一个方法是 四处走动,使当前发言者看不到主持人 。
有一些“味道”是站会出问题的良好指标。需要注意的是,即使没有“坏味道”,也并不意味着站会会顺利进行。这只是意味着它不“臭”。
下面的大多数“味道”都与之前的模式有关。对于那些不在乎站会模式的团队,潜在的问题往往更微妙,这超出了每日站会的范围,人们必须提出自己的解决方案。
人们过于关注他们正在做的事情,却忽略了他们的努力是否真的在推进工作。重新组织站会,让大家开始关注工作项。
团队成员面向经理或会议主持人说话,而不是与团队交流。这表明每日站会是为了经理/主持人而开的,但实际上站会应该是为了团队而开的。有多种方法可以打破这种依赖性: 轮换主持人 , 断开眼神接触 ,改变 昨天-今天-障碍 的形式,使用 传递令牌 ,等等。
这个问题由 同一地点、同一时间 直接解决,但如前所述,频繁出现这个问题可能表明站会的时间或地点是错误的。
有其他的模式可以用来应对这种情况,例如罚款。然而,我一般不会推荐这种做法,因为它们暗示问题与外在动机有关,而问题更可能是由其他原因引起的。
因为站会被认为是一天工作的开始,所以很多人在站会之前不会做什么工作。根据早上站会的时间,这可能会对可用的工作时间产生重大影响。这就引出了 不要使用站会作为一天工作的开始 。
站会的目的之一是增加团队的社交活动。然而,每日站会并不是为了让团队成员在与项目无关的事情上互相“叙旧”。很难提供一些例子来说明社交活动到底是提高了团队建设的水平还是分散了团队的注意力。但每日站会上社交活动的效果,可以从没有直接参与社交活动的参与者的行为中发现。如果他们的注意力仍然很高,那么可能只是团队建设;如果他们的注意力下降了,那么就 线下解决 ,也许还可以提供另一个讨论会来充当 冷水器 。
缺乏准备会导致站会节奏变慢,从而导致能量降低。这也有可能导致 15分钟或更短 的失败,从而进一步降低能量水平。
避免这个问题的一个好办法是改变站会的方式,让 工作项出席 ,通过 走板 更新工作项的状态。
否则,想让每个人都能知道 昨天-今天-障碍 的答案只能期望每个人都很有责任心了。
参与者没有提供问题的简要描述,而是提供了足够的细节和背景,这会导致其他人的注意力被转移。站会的一般的规则是只在站会期间识别障碍,在站会后讨论细节。这可以归纳为“描述标题,而不是整个故事”或“ 线下解决 ”。
将站会保持在 15 分钟或更短 的关键是限制 讲故事 ,不要在会议期间屈服于 解决问题 。让他们 线下解决 。
低能量可能意味着由于 讲故事 、 解决问题 等原因而导致的节奏减慢。在这种情况下,请引导团队成员 线下解决 。低能量可能还意味着团队规模太大,亦或是站会开始的时间较晚,建议尝试 不使用站会作为一天工作的开始 来替代 使用站会作为一天工作的开始 。
也被称为 : 游记
没有提出障碍可能有几个原因:不记得了,容忍度很高,对提出问题缺乏信任(因为 障碍没有被解决 ),没有方便的提出问题的方式,等等。主持人应注意鼓励人们提出障碍。
引入 改进板 可以提供一种低对抗的媒介。 回顾会 是发现障碍没有被提出的根因的有效途径。
除了指责的环境影响之外,阻止人们提出障碍的最可靠的方法就是不解决它们。为了使人们难以忘记和/或忽视障碍,可以用 改进板 公开跟踪它们。
站会可以作为兜底障碍的安全网,在最坏的情况下,障碍也会在一天之内被传达给整个团队。然而,站会并不是为了阻止问题在一天内随时被提出和解决。引入另一种实践(如 改进板 )来提出障碍可能会有所帮助。如果做了改进依然没有效果,可以通过回顾会来分析根本原因。
希望这篇文章能为你提供一些关于有效站会实践的细节和问题常见指标的更多方法。我们应该清楚,每日站会不仅仅是每天站在一起。
最后,重要的是不要太在意每一种模式,甚至是拥有一些“味道”。记住我们要解决的问题:人们是否精力充沛?人们是否在分享问题和想法?人们是否专注于我们的目标?人们是否作为一个团队一起工作?每个人都知道发生了什么吗?
如果你能对这些问题作出肯定的回答,那么会议可能会进行得很顺利。毕竟,这真的只是每天一起站起来而已。
本文首发于微信号“小船哥说敏捷”,全文完,感谢您的耐心阅读,请为自己的好学点个赞吧!
万字长文助你上手软件领域驱动设计 DDD
作者:faryrong,腾讯 CSIG 后台开发工程师
在聚合边界内保护业务规则不变性。最近看了一本书《解构-领域驱动设计》,书中提出了领域驱动设计统一过程(DDDRUP),它指明了实践 DDD 的具体步骤,并很好地串联了各种概念、模式和思想。因此,我对书本内容做了梳理、简化,融入自己的理解,并结合之前阅读的书籍以及实践经验,最终形成这篇文章。希望可以帮助大伙理顺 DDD 的各种概念、模式和思想,降低上手 DDD 的门槛。
法则 1 包含了两个关键点:a) 参与维护业务规则不变性的领域概念应该置于同一个聚合内;b) 在任何情况下都要保护业务规则不变性。比如,在 sms 系统中分数和绩点具有转换关系,这是业务规则的不变性,因此这两个概念被放在了同一个聚合边界内;当出现老师修改分数的场景时,需要保证绩点的换算同时被执行。由于这里绩点对象是值对象,不需要关心其生命周期管理的问题。当业务规则涉及到多个实体时,就需要通过本地事务来保证规则不变性(即实体间基于业务规则的数据一致性)。
法则 3 通过身份标识符关联其他聚合。
注意这里强调了关联关系,关联关系会涉及聚合 A 对聚合 B 的生命周期管理的问题,对于这种聚合间的关联关系,我们通过身份标识建立关联。而当聚合 A 引用聚合 B,但不需要对聚合 B 进行生命周期管理时,我们认为这是一种依赖关系(比如方法中的入参,而非类中的属性),对于聚合间的依赖关系,我们可以通过对象引用(聚合根实体的引用)的方式建立依赖。(PS:假设设计之初难以判断聚合之间到底是关联关系,还是依赖关系,我们就统一使用身份标识符作为关系引用即可)
聚合间的依赖关系通常分为两种方式
7.3.2.2 设计步骤
1. 理顺对象图
分析对象是实体还是值对象。
2. 分解关系薄弱处
聚合本质是一个高内聚的边界,因此我们可以根据领域对象之间关系的强弱来定义出聚合的边界。对象间的关系由强到弱可以分为:泛化关系,关联关系和依赖关系。其中关联关系和依赖关系在 7.3.2.1 小节已讲述,而泛化关系可以理解为是继承关系(即父子关系)。
泛化关系
虽然泛化关系是强耦合关系,但是根据对业务理解的视角不同,会产生不同的设计:
关联关系
上述提到过,聚合间的关联关系会涉及聚合 A 对聚合 B 的生命周期管理,这其实是一个比较宽松的约束。那聚合内实体的关联关系应该是怎么样的呢?生命周期一致的、共存亡的,当主实体被销毁时,从实体也随之会被销毁。比如商品实体和商品明细实体。而在示例-SMS 中,成绩和总成绩会被定义为两个聚合,原因是总成绩在成绩锁定后被统计,随后将不再发生改变,可见两者不存在上述的共存亡的关联关系。
PS: 实际上根据关联关系来区分边界的方法同样适用于限界上下文的边界划分。比如示例-SMS 中的课程和成绩生命周期不同,先有课程,后有成绩;而且成绩锁定后,课程被撤销也不会对成绩有影响,因此就可以定义出课程上下文和成绩上下问。
依赖关系
依赖关系主要体现的是实体间的职责委派和创建行为,可以分到不同的聚合边界。
3. 调整聚合边界
根据业务规则调整聚合边界。为了维护业务规则的不变性,相关的实体应该至于同一个聚合边界内。
└── TotalResultTask.java
├── ResultApplicationService.java
├── event // 应用事件,用于发布
└── adapter // 防腐层适配器接口
├── ... 这段有点长,其代码结构与成绩聚合一致,因此省略 ...
├── adapter
│ ├── CourseAdapterImpl.java
│ ├── facade
│ └── translator
└── repository
└── TotalResultRepositoryImpl.java
9.杂谈9.1 DDD 与微服务
微服务拆解指的是把一个单体服务拆分为粒度“足够小”的多个服务,而这里的“足够小”是一个主观的,没有任何标准的定义。尽管如此,我们对“微”这个词还是有一些基本要求的:足够内聚,足够独立,足够完备,这才使得拆分出来的微服务收益大于投入,试想如果一个微服务提供的业务功能会牵扯到与其他众多微服务的协作,那岂不是芭比 Q 了。
而上述我们对微服务的基本要求,实际上与限界上下文的特征(最小完备,自我履行,稳定空间,独立进化)不谋而合,因此,我们可以把限界上下文映射为微服务。我在日常实践中,都是将限界上下文和微服务的关系进行一一对应的,但这不是绝对的!限界上下文是站在领域角度给出的逻辑边界,而微服务的设计往往还要考虑物理边界,以及实际的质量需求(性能,可用性,安全性等),比如当我们采用的是 CQRS 架构,领域模型会被分为命令模型和查询模型,虽然它们同属一个限界上下文,但是它们往往是物理隔离的。因此,限界上下文只能作为微服务拆分的指导,而拆分过程中需要考虑质量需求,架构设计等技术因素。
9.2 事务
9.2.1 本地事务
上文在提及限界上下文识别和聚合设计的时候其实都提到需要考虑事务属性,即需要通过本地事务来保证业务规则的不变性/一致性。这里我们会疑惑的是:谁来承担管理事务的职责?事务管理的边界是什么?
应用层承担管理事务的职责
事务本质是一种技术手段,而领域模型本身与技术无关,因此事务应该由应用层负责管理。
事务管理的边界是聚合,有时限界上下文也可以
资源库操作的基本单元是聚合,因此事务管理的边界是聚合便是自然而然得出的结论。这里需要考虑的是当需要保证事务属性的不仅仅只有资源库操作,还包括发布领域事件时(即保证聚合落库和事件发布的原子性),我们可能需要采用可靠事件模式,即通过把领域事件落库事件表来表示事件的发布。此时应用层在管理事务时就没什么心智负担了。当然,采用可靠事件模式实际是限制了领域模型的实现,也算是技术对领域模型的一种入侵吧,但相比于解放应用层而言,应该是利大于弊。
我们也知道,应用层的核心职责是负责编排和协调不同聚合的领域服务,而应用层又负责事务管理,自然我们能推到出事务管理的边界是多个聚合(即限界上下文)。但这里有两个关注点:
a)一般是出于质量需求(性能会好一些,时效性更高一些);
b)同一个限界上下文内的多个聚合共享一个 DB。
9.2.2 Saga 事务
为了避免耦合,DDD 主张通过柔性事务来保证跨聚合、跨限界上下文的最终一致性。而目前业界比较主流的应用是 Saga 模式:通过使用异步消息来协调一系列本地事务,从而维度多个服务之间的数据一致性。而另一个非常著名的柔性事务方案 TCC 为啥没有 Saga 契合呢?
TCC 共分为三个阶段:
Try 阶段:准备阶段,对资源进行锁定或预留; Confirm 阶段:提交阶段,执行实际的操作; Cancel 阶段:补偿阶段,任意执行的操作出错了,就需要执行补偿,即释放 Try 阶段预留的资源。
可以看到 TCC 实际对领域模型的侵入是比较大的:
a)TCC 要求领域模型设计时,定义相关的属性以支持资源锁定/预留的问题;
b)TCC 对服务接口定义做出了要求,领域模型需要提供 Try,Confirm 和 Cancel 相应的领域服务。
Saga 模式并不要求其对资源进行锁定/预留,而其补偿操作也是通过执行操作的逆操作来完成(比如支付的逆操作是退款)。而大部分情况下,完整的领域模型都会对外提供操作及其逆操作。
10. 参考《解耦-领域驱动设计》 《领域驱动设计:软件核心复杂性应对之道》 《实现领域驱动设计》 《微服务架构设计模式》 极客时间《DDD 实战课》 极客时间《如何落地业务建模》 《领域驱动设计精粹》
最近其他好文:
深入揭秘 epoll 是如何实现 IO 多路复用的
低代码是什么?有什么优势
Go 高性能编程技法
├── event // 应用事件,用于发布
└── adapter // 防腐层适配器接口
├── ... 这段有点长,其代码结构与成绩聚合一致,因此省略 ...
├── adapter
│ ├── CourseAdapterImpl.java
│ ├── facade
│ └── translator
└── repository
└── TotalResultRepositoryImpl.java
9.杂谈9.1 DDD 与微服务
微服务拆解指的是把一个单体服务拆分为粒度“足够小”的多个服务,而这里的“足够小”是一个主观的,没有任何标准的定义。尽管如此,我们对“微”这个词还是有一些基本要求的:足够内聚,足够独立,足够完备,这才使得拆分出来的微服务收益大于投入,试想如果一个微服务提供的业务功能会牵扯到与其他众多微服务的协作,那岂不是芭比 Q 了。
而上述我们对微服务的基本要求,实际上与限界上下文的特征(最小完备,自我履行,稳定空间,独立进化)不谋而合,因此,我们可以把限界上下文映射为微服务。我在日常实践中,都是将限界上下文和微服务的关系进行一一对应的,但这不是绝对的!限界上下文是站在领域角度给出的逻辑边界,而微服务的设计往往还要考虑物理边界,以及实际的质量需求(性能,可用性,安全性等),比如当我们采用的是 CQRS 架构,领域模型会被分为命令模型和查询模型,虽然它们同属一个限界上下文,但是它们往往是物理隔离的。因此,限界上下文只能作为微服务拆分的指导,而拆分过程中需要考虑质量需求,架构设计等技术因素。
9.2 事务
9.2.1 本地事务
上文在提及限界上下文识别和聚合设计的时候其实都提到需要考虑事务属性,即需要通过本地事务来保证业务规则的不变性/一致性。这里我们会疑惑的是:谁来承担管理事务的职责?事务管理的边界是什么?
应用层承担管理事务的职责
事务本质是一种技术手段,而领域模型本身与技术无关,因此事务应该由应用层负责管理。
事务管理的边界是聚合,有时限界上下文也可以
资源库操作的基本单元是聚合,因此事务管理的边界是聚合便是自然而然得出的结论。这里需要考虑的是当需要保证事务属性的不仅仅只有资源库操作,还包括发布领域事件时(即保证聚合落库和事件发布的原子性),我们可能需要采用可靠事件模式,即通过把领域事件落库事件表来表示事件的发布。此时应用层在管理事务时就没什么心智负担了。当然,采用可靠事件模式实际是限制了领域模型的实现,也算是技术对领域模型的一种入侵吧,但相比于解放应用层而言,应该是利大于弊。
我们也知道,应用层的核心职责是负责编排和协调不同聚合的领域服务,而应用层又负责事务管理,自然我们能推到出事务管理的边界是多个聚合(即限界上下文)。但这里有两个关注点:
a)一般是出于质量需求(性能会好一些,时效性更高一些);
b)同一个限界上下文内的多个聚合共享一个 DB。
9.2.2 Saga 事务
为了避免耦合,DDD 主张通过柔性事务来保证跨聚合、跨限界上下文的最终一致性。而目前业界比较主流的应用是 Saga 模式:通过使用异步消息来协调一系列本地事务,从而维度多个服务之间的数据一致性。而另一个非常著名的柔性事务方案 TCC 为啥没有 Saga 契合呢?
TCC 共分为三个阶段:
Try 阶段:准备阶段,对资源进行锁定或预留; Confirm 阶段:提交阶段,执行实际的操作; Cancel 阶段:补偿阶段,任意执行的操作出错了,就需要执行补偿,即释放 Try 阶段预留的资源。
可以看到 TCC 实际对领域模型的侵入是比较大的:
a)TCC 要求领域模型设计时,定义相关的属性以支持资源锁定/预留的问题;
b)TCC 对服务接口定义做出了要求,领域模型需要提供 Try,Confirm 和 Cancel 相应的领域服务。
Saga 模式并不要求其对资源进行锁定/预留,而其补偿操作也是通过执行操作的逆操作来完成(比如支付的逆操作是退款)。而大部分情况下,完整的领域模型都会对外提供操作及其逆操作。
10. 参考《解耦-领域驱动设计》 《领域驱动设计:软件核心复杂性应对之道》 《实现领域驱动设计》 《微服务架构设计模式》 极客时间《DDD 实战课》 极客时间《如何落地业务建模》 《领域驱动设计精粹》
最近其他好文:
深入揭秘 epoll 是如何实现 IO 多路复用的
低代码是什么?有什么优势
Go 高性能编程技法
│ ├── CourseAdapterImpl.java
│ ├── facade
│ └── translator
└── repository
└── TotalResultRepositoryImpl.java
9.杂谈
9.1 DDD 与微服务
微服务拆解指的是把一个单体服务拆分为粒度“足够小”的多个服务,而这里的“足够小”是一个主观的,没有任何标准的定义。尽管如此,我们对“微”这个词还是有一些基本要求的:足够内聚,足够独立,足够完备,这才使得拆分出来的微服务收益大于投入,试想如果一个微服务提供的业务功能会牵扯到与其他众多微服务的协作,那岂不是芭比 Q 了。
而上述我们对微服务的基本要求,实际上与限界上下文的特征(最小完备,自我履行,稳定空间,独立进化)不谋而合,因此,我们可以把限界上下文映射为微服务。我在日常实践中,都是将限界上下文和微服务的关系进行一一对应的,但这不是绝对的!限界上下文是站在领域角度给出的逻辑边界,而微服务的设计往往还要考虑物理边界,以及实际的质量需求(性能,可用性,安全性等),比如当我们采用的是 CQRS 架构,领域模型会被分为命令模型和查询模型,虽然它们同属一个限界上下文,但是它们往往是物理隔离的。因此,限界上下文只能作为微服务拆分的指导,而拆分过程中需要考虑质量需求,架构设计等技术因素。
9.2 事务
9.2.1 本地事务
上文在提及限界上下文识别和聚合设计的时候其实都提到需要考虑事务属性,即需要通过本地事务来保证业务规则的不变性/一致性。这里我们会疑惑的是:谁来承担管理事务的职责?事务管理的边界是什么?
应用层承担管理事务的职责
事务本质是一种技术手段,而领域模型本身与技术无关,因此事务应该由应用层负责管理。
事务管理的边界是聚合,有时限界上下文也可以
资源库操作的基本单元是聚合,因此事务管理的边界是聚合便是自然而然得出的结论。这里需要考虑的是当需要保证事务属性的不仅仅只有资源库操作,还包括发布领域事件时(即保证聚合落库和事件发布的原子性),我们可能需要采用可靠事件模式,即通过把领域事件落库事件表来表示事件的发布。此时应用层在管理事务时就没什么心智负担了。当然,采用可靠事件模式实际是限制了领域模型的实现,也算是技术对领域模型的一种入侵吧,但相比于解放应用层而言,应该是利大于弊。
我们也知道,应用层的核心职责是负责编排和协调不同聚合的领域服务,而应用层又负责事务管理,自然我们能推到出事务管理的边界是多个聚合(即限界上下文)。但这里有两个关注点:
a)一般是出于质量需求(性能会好一些,时效性更高一些);
b)同一个限界上下文内的多个聚合共享一个 DB。
9.2.2 Saga 事务
为了避免耦合,DDD 主张通过柔性事务来保证跨聚合、跨限界上下文的最终一致性。而目前业界比较主流的应用是 Saga 模式:通过使用异步消息来协调一系列本地事务,从而维度多个服务之间的数据一致性。而另一个非常著名的柔性事务方案 TCC 为啥没有 Saga 契合呢?
TCC 共分为三个阶段:
Try 阶段:准备阶段,对资源进行锁定或预留; Confirm 阶段:提交阶段,执行实际的操作; Cancel 阶段:补偿阶段,任意执行的操作出错了,就需要执行补偿,即释放 Try 阶段预留的资源。
可以看到 TCC 实际对领域模型的侵入是比较大的:
a)TCC 要求领域模型设计时,定义相关的属性以支持资源锁定/预留的问题;
b)TCC 对服务接口定义做出了要求,领域模型需要提供 Try,Confirm 和 Cancel 相应的领域服务。
Saga 模式并不要求其对资源进行锁定/预留,而其补偿操作也是通过执行操作的逆操作来完成(比如支付的逆操作是退款)。而大部分情况下,完整的领域模型都会对外提供操作及其逆操作。
10. 参考《解耦-领域驱动设计》 《领域驱动设计:软件核心复杂性应对之道》 《实现领域驱动设计》 《微服务架构设计模式》 极客时间《DDD 实战课》 极客时间《如何落地业务建模》 《领域驱动设计精粹》
以上是关于【万字长文】详解每日站会的各种模式的主要内容,如果未能解决你的问题,请参考以下文章
关于SCRUM站会的实践 | IDCF FDCC认证学员作品
leetcode 28. 实现 strStr()----KMP算法,朴素模式匹配算法----超万字长文详解
二万字长文图文详解RabbitMQ6 种工作模式(理论与代码相结合)