简介DDD是一套方法论,也是一套思路。各种各样的元模型和名词概念。其本质是与指导思想相对应的“一解”,初学者容易被表象所困。你应该始终保持清醒,并保持“DDD的各种元模型是为了解决实际开发中的某些类型的问题而创建的”的意识。在接触各种元模型时,结合自身业务问题进行验证,有助于避免被概念表象所困,回归问题解决的本质。背景数据架构团队从2018年开始以业务需求为驱动开发电话机器人,转眼已近5年。目前,平台下已搭建100+款不同类型的机器人,为公司经销商、二手车、整车厂、金融等BU业务提供外呼能力,日外呼量达数十万次。电话机器人项目已经初具规模,但过程中也遇到了很多挑战。为了应对这些挑战,我们团队最终采用DDD思想进行重构和开发。在应用DDD的过程中,数据架构团队实现了一些自己的开发规范。在这里我将一些经验和想法分享给大家,希望能起到招玉的作用。让我在这里解释一下。许多元模型在空间中没有讨论,也没有给出具体案例。一是考虑长度问题。二是了解DDD的思想,并结合各自业务实现。在我的业务中举例说明意义不大。此外,这种情况很容易找到。同时我觉得大家把我们团队遇到的问题和解决方案,实施过程和我们形成的开发规范给出来更有价值。对DDD感兴趣,想了解更多或者对本文有疑问的同学,欢迎联系我进行讨论。下面,我将从这几个部分来分享:在机器人项目中遇到的挑战,为什么要做DDD,DDD的落地步骤,给团队带来的提升,从理论到实战遇到的冲突,以及未来在DDD应用中的改进和总结。一、遇到的挑战挑战一:业务逻辑复杂度高。随着各种服务的接入,为了应对不同场景下的具体服务,不断增加新的逻辑。如:流程中的意图识别逻辑。意图识别需要依赖AI的多模型识别。多个模型识别的意图可能会发生冲突,需要在冲突的意图配置规则之间进行权衡。同时,对于一些冷启动或者紧急优化的场景,需要通过实时生效的配置规则来支持意图识别。并且需要在规则的意图识别中支持匹配词槽。词槽的种类很多,优先区分有场景的全局词槽和进程上的词槽。从数据识别的来源来看,可以分为AI识别的、字典规则匹配的、业务方传入的。经过一段时间的业务发展,不同类型的词槽增加了不同的属性。例如car系列的词槽包括product、businessscope、non-business等;挑战二:代码结构结构不清晰。随着业务需求和功能的增加,代码量也随之增加。再加上逻辑复杂,团队开发人员代码千差万别,逐渐导致各种逻辑边界混乱。例如:我们通常的开发方式是按照功能模块进行拆解,将各个模块与业务流程串联起来,共同完成业务需求。但是要处理这类业务的复杂逻辑,这种方案设计有很大的弊端,模块边界容易被穿透。各个模块之间是相互调用的关系。原本作为模块使用的隔离设计,在实现过程中其实被彻底打破了。将原本理想的垂直分割模块做成网状结构。中间环节的模块领导者开发的属性或方法,由于其他模块的外部依赖而产生分歧。导致后期需求变更时风险加大,或者发现依赖的方法可以随意更改的方法不能更改,必须增加额外的逻辑代码来实现.这使得本已复杂的代码变得更加复杂。业务需求拆解不合理,需要的功能实现就近开发。没有严格按照模块拆解,缺乏统一的思想作为指导。挑战三:产品需求量大,难以区分是否有实际价值。挑战四:逻辑变化快,需求多导致需要重新设计代码逻辑。挑战五:业务较多,各业务表述不一致,沟通成本高。垂直边界被打破,代码复杂度增加,业务流程频繁调整。这些多个维度相互叠加,使得开发和维护的难度成倍增加。电话机器人一级应用系统稳定性难以保障。技术同学就算是高级工程师,也按照自己看得懂的微服务思路进行设计,按照模块对项目进行拆解。平台质量工具,写了很多单元测试。然而,当项目的新需求迭代时,还是有不少“惊喜”,让整个团队都头疼不已。2.为什么是DDD为什么是DDD?每天有那么多的技术栈,那么多的idea,为什么要DDD去处理呢?首先,DDD很好地修改了“处理软件核心复杂性的方式”,这让很多人都想一探究竟。那么我们就来看看DDD是如何解决项目中遇到的挑战的。首先我们看一下DDD对复杂度的分类,搞清楚DDD要处理的复杂度是不是我面临的挑战。在DDD相关资料中,从理解能力和预测能力两个维度探索分析复杂性的原因。理解能力(即软件系统复杂,开发人员难以理解):第一尺度:影响理解能力的第一要素。代码有上亿行,各个需求点之间的关系相互影响。修改一点就会牵一发而动全身。第二种结构:结构不合理甚至混乱,开发者难以维护功能。可预测性(即业务的发展难以预测):当需求发生变化时,软件实现的方向难以预测,会出现设计过度和设计不足的问题。过度设计,保留了很多接口,构造了很多模式,增加了代码实现的复杂度,后来发现并没有用到。设计不足,需求的实现没有考虑到后期的开发,变更来了,需要推翻已有的设计,重新开发,产品抱怨设计能力差。DDD复杂的原因是:规模、结构和变化;规模和结构对理解造成了障碍,变化对预测造成了障碍,两者的结合形成了一个复杂的问题。其次,DDD不仅仅是代码设计阶段的理论,还包括从需求分析、架构映射和建模到实现的全过程设计指导。在需求分析阶段,通过相关指导思想可以提前准确知晓业务价值,捕捉未来变化的方向。在架构映射阶段,给出了从需求到架构过程的指导思想,增加了设计权重和规范。通过子域拆分、系统分层、限界上下文业务分类,给出指导方针,保证系统架构清晰,降低系统复杂度。在建模和实现阶段,给出领域驱动设计的相关元模型,使各部分的功能划分清晰,能够快速响应业务需求和未来的功能变化。再看看DDD给出的指导思想:尺度问题:去掉边界。用子字段和有界上下文分而治之。对于分而治之的思想,DDD给出了两个重要的设计元模型:BoundedContext和ContextMapping。结构问题:分层架构+边界隔离。分层在隔离业务逻辑和技术实现复杂性方面发挥着作用。DDD引入的分层架构将业务逻辑封装到领域层,将支撑业务逻辑的技术实现放到基础设施层。领域层之上的应用层封装了应用服务,将两者粘合在一起进行协作。变更问题:主动设计变更。变化无法控制,只能拥抱。在需求分析阶段,采用5W思维,识别变化规律,控制业务变化。DDD通过模型驱动的设计元模型对限界上下文进行领域建模,形成结合分析、设计和实现的领域模型。最后看看DDD给出的解决方案。它引入了一套细化为模式的设计元模型,实现了业务软件的规模控制、结构拆分和对变化的主动响应。简单介绍一下这张图,整体分为两部分。第一部分就是下面虚线圈圈出的部分,不涉及具体的技术实现。在需求分析阶段,一些元模型解决方案来处理问题空间。另一部分在第一部分的基础上,进行了具体的系统架构分层、对象分离与聚合、服务拆解。在这个阶段,将实施相应的设计。我的理解是这套设计元模型提供了一套完整的从需求分析、设计到实现的解决方案。需求分析阶段的系统拆解(对应图中的子域元模型)。然后拆分到更新粒度的有界上下文。并给出每个边界的协作关系方案(对应图中的contextmappingmeta-model)。在设计和实现阶段,通过对系统分层架构、领域服务和聚合的粒度设计,给出了模型驱动设计的设计元方案。提供一套完整的、有理论支持的、可实施的标准方案。上述DDD对问题复杂度的分析和定位,完全是电话机器人系统的痛点。给出的解决方案也完美解决了企业面临的各种挑战。意识到其价值后,团队很快达成共识,在后续项目中实施。3、DDD实现步骤的元模型和业务边界的拆解细节不再赘述,直接给出我们团队实战中的步骤和产品。3.1预研阶段的第一步我们在这部分的经验是团队中有人作为先行者,先花精力深入研究DDD相关概念,然后同步到整个团队。就我们团队而言,研究阶段比较分散,需要多长时间不好评估。科普阶段前后四次,团队共花费8小时。之后,团队中的学生在概念引导的基础上,具备了快速深入学习的能力。并组织小组成员相互讨论,确认理解。3.2第二步引入指导思想和实施规范3.2.1需求分析阶段引入5W模型的理论支撑,有助于识别真实需求,主动控制变化方向,剔除无意义需求。这部分是5W理论作为产品分析需求的理论支撑,对于识别真实需求,更好的分析业务的发展方向很有帮助。也可以从源头上直接减少无效需求;3.2.2引入服务规范,通过文档比对代码实现业务功能。有助于开发和后续需求整理,也可以作为单元测试覆盖率的考量。3.2.2.1团队成员的共识是先写服务规范,再开发。写服务规范所花的时间,其实就是梳理技术对需求的理解,理清思路,把这部分时间在后面写代码的时候赚回来。3.2.2.2服务规范及要求,服务规范对应单项测试。顺便解决了之前单测没有标准的问题(我理解的代码、方法覆盖率等都不能称为标准)。下面是我们团队采用的服务规范模板:编号:标识业务服务的唯一编号。名称:业务服务的名称,采用动词短语形式。描述:作为一个
