如何用 DDD 驱动开发团队的沟通与协作?

领域驱动设计的核心是“领域”,因此要运用领域驱动设计,从一开始就要让团队走到正确的点儿上。当我们组建好了团队之后,应该从哪里开始?不是 UI 原型设计、不是架构设计、也不是设计数据库,这些事情虽然重要但却非最高优先级。试想,项目已经启动,团队却并不了解整个系统的目标和范围,未对系统的领域需求达成共识,那么项目开发的航向是否会随着时间的推移而逐渐偏离?用正确的方法做正确的事情,运用领域驱动设计,就是要先识别问题域,进而为团队提炼达成共识的领域知识

要做到这一点,就离不开团队各个角色的沟通与协作。客户的需求不是从一开始就生长在那里的,就好像在茫茫森林中的一棵树木,等待我们去“发现”它。相反,需求可能只是一粒种子,需要土壤、阳光与水分,在人们的精心呵护与培植下才能茁壮成长。因此,我们无法“发现”需求,而是要和客户一起“培育”需求,并在这个培育过程中逐渐成熟。

达成共识

“培育”需求的过程需要双向的沟通、反馈,更要达成对领域知识理解的共识。原始的需求是“哈姆雷特”,每个人心中都有一个“哈姆雷特”,如果没有正确的沟通与交流方式,团队达成的所谓“需求一致”不过是一种假象罢了。

由于每个人获得的信息不同,知识背景不同,又因为角色不同因而导致设想的上下文也不相同,诸多的不同使得我们在对话交流中好像被蒙了双眼的盲人,我们共同捕捉的需求就好似一头大象,各自只获得局部的知识,却自以为掌控了全局:

或许有人会认为客户提出的需求就应该是全部,我们只需理解客户的需求,然后积极响应这些需求即可。传统的开发合作模式更妄图以合同的形式约定需求知识,要求甲、乙双方在一份沉甸甸的需求规格说明书上签字画押,如此即可约定需求内容和边界,一旦发生超出该文档边界的变更,就需要将变更申请提交到需求变更委员会进行评审。这种方式从一开始就站不住脚,因为我们对客户需求的理解,存在三个方向的偏差:

  • 我们从客户那里了解到的需求,并非用户最终的需求;

  • 若无有效的沟通方式,需求的理解偏差则会导致结果大相径庭;

  • 理解到的需求并没有揭示完整的领域知识,从而导致领域建模与设计出现认知障碍。

Jeff Patton 在《用户故事地图》中给出了一副漫画来描述共识达成的问题。我在 ThoughtWorks 给客户开展 Inception 活动时,也使用了这幅漫画:

这幅漫画形象地表现了如何通过可视化的交流形式逐渐在多个角色之间达成共识的过程。正如前面所述,在团队交流中,每个人都可能成为“盲人摸象的演员”。怎么避免认知偏差?很简单,就是要用可视化的方式表现出来,例如,绘图、使用便签、编写用户故事或测试用例等都是重要的辅助手段。在下一课,我会结合着领域场景分析来讲解这些提炼领域知识的手段。

可视化形式的交流可以让不同角色看到需求之间的差异。一旦明确了这些差异,就可以利用各自掌握的知识互补不足去掉有余,最终得到大家都一致认可的需求,形成统一的认知模型。

团队协作

在软件开发的不同阶段,团队协作的方式与目标并不相同。在项目的先启(Inception)阶段,团队成员对整个项目的需求完全一无所知,此时与客户或领域专家的沟通,应该主要专注于宏观层面的领域知识,例如,系统愿景和目标、系统边界与范围,还有主要的需求功能与核心业务流程。在管理层面,还需要在先启阶段确定团队与利益相关人(包括客户与领域专家)的沟通方式。

先启阶段

在敏捷开发过程中,我们非常重视在项目之初开展的先启阶段,尤其是有客户参与的先启阶段,是最好的了解领域知识的方法。如果团队采用领域驱动设计,就可以在先启阶段运用战略设计,建立初步的统一语言,在识别出主要的史诗级故事与主要用户故事之后,进而识别出限界上下文,并建立系统的逻辑架构与物理架构。

在先启阶段,与提炼领域知识相关的活动如下图所示:

上图列出的七项活动存在明显的先后顺序。首先我们需要确定项目的利益相关人,并通过和这些利益相关人的沟通,来确定系统的业务期望与愿景。在期望与愿景的核心目标指导下,团队与客户才可能就问题域达成共同理解。这时,我们需要确定项目的当前状态与未来状态,从而确定项目的业务范围。之后,就可以对需求进行分解了。在先启阶段,对需求的分析不宜过细,因此需求分解可以从史诗级(Epic)到主故事级(Master)进行逐层划分,并最终在业务范围内确定迭代开发需要的主故事列表。

迭代开发阶段

在迭代开发阶段,针对迭代生命周期和用户故事生命周期可以开展不同形式的沟通与协作。在这个过程中,所有沟通协作的关键点如下图所示:

迭代生命周期是针对迭代目标与范围进行需求分析与沟通的过程。团队首先要了解本次迭代的目标,对迭代中的每个任务要建立基本的领域知识的理解。在迭代开发过程中,我们可以借鉴 Scrum 敏捷管理的过程。

Scrum 要求团队在迭代开始之前召开计划会议,由产品负责人(Product Owner)在会议中向团队成员介绍和解释该迭代需要完成的用户故事,包括用户故事的业务逻辑与验收标准。团队成员对用户故事有任何不解或困惑,都可以通过这个会议进行沟通,初步达成领域知识的共识。每天的站立会议要求产品负责人参与,这就使得开发过程中可能出现的需求理解问题能够及时得到解答。

Scrum Master 则通过每天的站立会议了解当前的迭代进度,并与产品负责人一起基于当前进度和迭代目标确定是否需要调整需求的优先级。迭代结束后,团队需要召开迭代演示会议,除了开发团队之外,该会议还可以邀请客户、最终用户以及领域专家参与,由团队的测试人员演示当前迭代已经完成的功能。

这种产品演示的方法更容易消除用户、客户、领域专家、产品负责人与团队在需求沟通与理解上的偏差。由于迭代周期往往较短,即使发现了因为需求理解不一致导致的功能实现偏差,也能够做到及时纠偏,从而能够将需求问题扼杀于摇篮之中。

每一个功能的实现、每一行代码的编写都是围绕着用户故事开展的,它是构成领域知识的最基本单元。用户故事指导着开发人员的开发、测试人员的测试,其质量会直接影响领域驱动设计的质量。

敏捷方法非常重视发生在用户故事生命周期中的各个关键节点。对于用户故事的编写,敏捷开发实践强调业务分析人员与测试人员共同编写验收测试的自动化测试脚本,这在《实例化需求》一书中被称之为“活文档(Living Document)”。测试人员与需求分析人员的合作,可以为需求分析提供更多观察视角,尤其是异常场景的识别与验收标准的确认。

当用户故事从需求分析人员传递给开发人员时,不管这个用户故事的描述是多么的准确和详细,都有可能导致知识流失。因此,在开发人员领取了用户故事,并充分理解了用户故事描述的需求后,不要急匆匆地开始编码实现,而是建议将需求分析人员与测试人员叫过来,大家一起做一个极短时间的沟通与确认,我们称这一活动为“Kick Off”,这种方式实际就是对“盲人摸象”问题的一种应对。

在这个沟通过程中,开发人员应尽可能地多问需求分析人员“为什么”,以探索用户故事带来的价值。只有如此,开发人员才能更好地理解业务逻辑与业务规则。同时,开发人员还要与测试人员再三确认验收标准,以形成一种事实上的需求规约。

当开发完成后,是否就意味着我们可以将实现的故事卡移交给测试呢?虽然通过迭代开发以及建立特性团队已经大大地拉近了开发人员与测试人员的距离,缩短了需求从开发到测试的周期。但我们认为,有价值的沟通与交流怎么强调都不过分!磨刀不误砍柴工。

我们认为从开发完成到测试开始也是一个关键节点,建议在这个关键节点再进行一次交流活动,即在开发环境下,由开发人员向需求分析人员与测试人员“实地”演示刚刚完成的功能,并对照着验收标准进行验收,我们称这个过程为“Desk Check”,是一个快速迷你的功能演示,目的是快速反馈,也减少了任务卡在开发与测试之间频繁切换的沟通成本。

通过 Desk Check 的用户故事卡才会被移动到“待测试”,不用等到迭代结束,更不用等到版本发布,只要开发人员完成了用户故事,测试人员就应该在迭代周期内进行测试,未经过测试的用户故事其交付价值为 0,可以认为这张用户故事卡没有完成,这也是大多数敏捷实践对所谓“完成(Done)”的定义。

无数研究与实践也证明了,修改 Bug 的成本会随着时间的推移而增加,如果在开发完成后即刻对其进行测试,一旦发现了 Bug,开发人员便能够快速响应,降低修改 Bug 的成本。当然,测试的过程同样是沟通与交流的过程,是最有效的需求验证和质量保障的手段。

敏捷思想强调个体和团队的协作与沟通,强调快速反馈与及时响应。前面探讨的这些敏捷实践都是行之有效的沟通机制和交流手段,可以帮助团队对需求的理解更加全面、更加准确。只有频繁的沟通,才能就业务需求达成整个团队的共识;只有良好的协作,才能有助于大家一起提炼领域知识,建立统一语言;只有快速反馈,才能尽可能保证领域模型与程序实现的一致。这些都是实践领域驱动设计的基本前提。

为什么要学习领域驱动设计

如果你已经能设计出美丽优良的软件架构,如果你只希望脚踏实地做一名高效编码的程序员,如果你是一位注重用户体验的前端设计人员,如果你负责的软件系统并不复杂,那么,你确实不需要学习领域驱动设计!

领域驱动设计当然并非“银弹”,自然也不是解决所有疑难杂症的“灵丹妙药”,请事先降低对领域驱动设计的不合现实的期望。我以中肯地态度总结了领域驱动设计可能会给你带来的收获:

  • 领域驱动设计是一套完整而系统的设计方法,它能带给你从战略设计到战术设计的规范过程,使得你的设计思路能够更加清晰,设计过程更加规范。

  • 领域驱动设计尤其善于处理与领域相关的高复杂度业务的产品研发,通过它可以为你的产品建立一个核心而稳定的领域模型内核,有利于领域知识的传递与传承。

  • 领域驱动设计强调团队与领域专家的合作,能够帮助团队建立一个沟通良好的团队组织,构建一致的架构体系。

  • 领域驱动设计强调对架构与模型的精心打磨,尤其善于处理系统架构的演进设计。

  • 领域驱动设计的思想、原则与模式有助于提高团队成员的面向对象设计能力与架构设计能力。

  • 领域驱动设计与微服务架构天生匹配,无论是在新项目中设计微服务架构,还是将系统从单体架构演进到微服务设计,都可以遵循领域驱动设计的架构原则。

大家好,我是张逸,去年在 GitChat 平台上上线了《领域驱动战略实践》的第一部分,累计销量已过 6000 份,同时建了两个读者群,也邀请了十几位领域驱动设计方面的专家加入到了读者群,共同探讨和交流领域驱动设计的相关知识。

至今,两个群依然很活跃,每天都有许多问题抛出,同时又有许多问题得到了解答,还有更多的问题悬而未决,因为每个人都有自己心目中的“哈姆雷特”,谁也无法说服对方,谁也无法给出一个让所有人都认同的标准答案。这恰恰是领域驱动设计最棘手的一部分,当然,也是最让人神往的一部分——唯有不确定,方才值得去探索

在探讨领域驱动战术设计的一些问题时,总会有人纠结:这个领域对象应该定义成实体,还是值对象?领域服务和应用服务的区别是什么?聚合的边界该怎么划分?于是,各种设计问题纷至沓来,问题越辩越糊涂,到了最后,已经脱离了最初探讨问题的场景,变成了“空对空导弹”一阵乱发射,最后蓦然回首,才发现目标已然消失了。

这是不合理的。在软件开发领域,没有什么一劳永逸的实现,也没有什么放之四海而皆准的标准,必须结合具体的业务场景做出合理的决策,无论建模和设计再怎么完美,也需要通过落地的检验才知道好还是坏。任何脱离具体业务场景的问题分析,都是空谈;任何不落地的完美方案,都是浮夸。领域驱动设计没有标准,有的只是持续不断的不确定性。

正所谓“以不变应万变”,我们要从实证主义的角度看待领域驱动设计,窃以为,只需守住三项基本原则即可:

  • 必须通过领域建模来驱动设计

  • 领域专家或业务分析师必须参与到建模活动中

  • 设计必须遵循面向对象分析和设计的思想与原则

只要做到这三点,领域驱动战术设计就不会做得太差,剩下的不足,就需要靠经验来填补了。

本专栏由两个部分组成,第一部分内容全面覆盖了领域建模分析与架构设计的战略设计过程,从剖析软件复杂度的根源开始,引入了领域场景分析与敏捷项目实践,帮助需求分析人员与软件设计人员分析软件系统的问题域,提炼真实表达的领域知识,最终建立系统的统一语言。同时,将主流架构设计思想、微服务架构设计原则与领域驱动设计中属于战略设计层面的限界上下文、上下文映射、分层架构结合起来,完成从需求到架构设计再到构建代码模型的架构全过程。

第二部分内容要解决的则是前面所提及的战术层面的设计问题。单以战术设计阶段来看,我个人认为 Eric Evans 做出的贡献并不多。在《领域驱动设计》一书中,他讲到了模型驱动设计与领域建模,却没有深入阐述该如何正确地进行领域建模;他引入的资源库模式和工厂模式,不过是面向对象设计原则的体现;至于模型的演化与重构带来的突破,其实更多是经验之谈,缺乏切实可行的方法。

不可否认,若要做到优良的领域驱动设计,建模和设计的经验是必不可少的,这需要多年的项目实战打磨方可萃取而成,但如果在开始之初,能有一些更为具体的方法作为指引,或许可以让掌握技能的周期大幅度缩短。此外,我还清楚地看到:许多领域驱动设计的门外汉,之所以迟迟不得其门而入,是因为他(她)们连最为基本的面向对象分析和设计的能力都不具备,因此,无法理解领域驱动的战术设计要素也就不足为奇了。

关键在于,许多设计问题因为其不确定性,根本没有标准答案,没有任何人能给你指出明确的设计方法和设计思路。这时,就必须要吃透面向对象分析和设计的思想与原则,用它们来指导我们的设计,而不是死板的遵循领域驱动设计的模式。

针对一些设计能力不足的开发团队,若希望采用领域驱动设计来改进设计和编码质量,往往会适得其反,做出来的是一锅“夹生饭”。从理想角度讲,决定是否采用领域驱动设计,不在于团队成员的能力高低,而在于业务的复杂度。然而,我们又不得不面对现实,如果团队成员的设计能力差了,是做不好领域驱动设计的。

因此,我在专栏中,一方面分享了我的设计体验和方法,以帮助团队成员的成长,另一方面也给出了一个操作性强的设计过程,可以让基础相对薄弱的开发人员能够依样画葫芦,做出还算不错的设计与实现。

这些考虑帮助我确定了专栏的基本思路,即以能学习和模仿的战术设计方法来弥补经验之不足,以设计思想和设计原则作为指导来解决争议之问题,以能够落地的解决方案来体现领域驱动设计之价值。

本专栏并非是对 Eric Evans《领域驱动设计》的萧规曹随,而是吸纳了领域驱动设计社区的各位专家大师提出的先进知识,并结合我多年来运用领域驱动设计收获的项目经验,同时还总结了自己在领域驱动设计咨询与培训中对各种困惑与问题的思考与解答。专栏内容既遵循了领域驱动设计的根本思想,又有自己的独到见解;既给出了权威的领域驱动知识阐释,又解答了在实践领域驱动设计中最让人困惑的问题。

我强烈建议读者诸君要学会对设计的本质思考,不要只限于对设计概念的掌握,而要追求对设计原则与方法的融汇贯通。只有如此,才能针对不同的业务场景灵活地运用领域驱动设计,而非像一个牵线木偶般遵照着僵硬的过程进行死板地设计。

分享交流

我们为本专栏的付费读者创建了微信交流群,以方便更有针对性地讨论课程相关问题,订阅后即可入群。阅读文章过程中有任何疑问随时可以跟其他小伙伴讨论,或者直接向我提问(我看到后会回复)。

订阅小攻略:现在 成为年会员,即可以 3 折的价格换购本专栏,并且全场 Chat 免费读!

点击阅读原文,查看更多试读章节

猜你喜欢

转载自blog.csdn.net/GitChat/article/details/103516241
ddd