一文探究学习DDD的意义
发布时间:2023-02-14 14:28:29 所属栏目:服务器 来源:互联网
导读:《阿甘正传》中,阿甘开始了不停地跑步,一段时间后,后面就有了很多追随者一起跑,他们为什么跑哪? 阿甘:我也不知道,只是想跑而已。 追随者:感觉这样做是有意义的,而且阿甘也还在前面领跑。 类似地,一开始我也不知道DDD是什么,但当发现大家都在提DDD
《阿甘正传》中,阿甘开始了不停地跑步,一段时间后,后面就有了很多追随者一起跑,他们为什么跑哪? 阿甘:我也不知道,只是想跑而已。 追随者:感觉这样做是有意义的,而且阿甘也还在前面领跑。 类似地,一开始我也不知道DDD是什么,但当发现大家都在提DDD、都在学DDD的时候,我也像跟跑者一样不由自主地加入了前行:既然有大牛提出了DDD,既然那么多人趋之若鹜,那么肯定有可取的地方。 然而,有一天,阿甘停止了跑步,他不想跑了,追随者遇到了一个问题:我们还要跑么?当我们在学习DDD的过程中,感觉学而不得的时候,可能也会问:我们还要学么?这的确引人深思。 本文基于工作经验,尝试谈谈对DDD的一些理解,希望能够更好地探寻学习DDD的意义。 我们选择各种框架、进行各种组织设计,核心是为了提高生产效率。但如果业务逻辑都是 case by case 地进行实现、缺少复用,那么研发成本是非常高的、投入周期也会非常长。 为了增加复用、缩短业务的落地时间,就需要很多通用的能力、产品。在我们的交付过程中,主要有两个层次: 基础能力:相对原子的能力是基础(域)能力,这个可以较好地支持业务定制。由于比较基础,表达的产品能力范围也是很大的。但是,一个完善的产品需要串联的基础能力是非常多的,串联的成本也是非常高的。 平台产品:基础能力的通用性,意味着缺少对场景的理解,缺少了进一步提升生产效率的“基因”。所以在交付的时候,会基于一些高频场景进行抽象,形成平台的产品能力,争取做到“拆箱即用”。业务基于“平台产品”这层进行定制的时候,理解成本会大大减少。 研发效能降低的重要原因在于:更多的时候,我们还是按照“业务能跑起来,怎么快怎么来“的逻辑去做相关工作,遇水搭桥,遇山开洞,然后直达目的地,进行信息的传达、数据库字段的操作。 这样的过程,违背了我们”希望通过业务场景,丰富平台能力,同时保证内核干净“的初衷。能力应该是基于相对多的用例、相对完善的思考进行抽象,是横向统一看,有更深刻的理解,但是垂直的交付,让我们更加纵向地处理问题,往往只是“窥探”了链路,在交付时长和业务节点的限制下,很难想得更加全面、深刻,难以做出更通用的设计。 ●机制保障,不依赖易变的事物:DDD其实在总结很多通用的技巧和经验,能够让这样的实施更具有确定性。无论是聚合根对领域实体的管控能力、限界上下文的交互策略、领域内核的抽象地位...等等,一旦选择尊奉,确定下来,就能够落在代码结构、组织关系、团队文档中,形成共识,不会因为人员等因素的变化而剧烈波动。 对DDD的关注,可以类比于我们对“工匠精神”的关注,对DDD的重视,也是我们对业务理解的重视。贴近业务,更要理解业务,不仅要理解业务,更需要理解大多数的业务。这样的追求,让我们往上看了一个层次,回归了最本质的问题:我们要解决什么问题?如何能够解决得更好? 叔孙武叔语大夫于朝曰:“子贡贤于仲尼。” 子服景伯以告子贡,子贡曰:“譬之宫墙,赐之墙也及肩,窥见室家之好;夫子之墙数仞,不得其门而入,不见宗庙之美、百官之富。得其门者或寡矣,夫子之云不亦宜乎!” 正如要感受到孔子达到的境界,自己的学问也需要有一定的积累。我们要感受到DDD的力量,自己本身就要成长到一定程度(如:经历了一些成功或者失败的设计,有自己的经验或者教训),才能形成共鸣和认同。 工作中,的确很少看到DDD的优秀实践。在复杂的业务面前,谁也没有勇气说,哪个软件结构是理想的设计: 因为这不是一个确定性的问题分解,你的设计会被放在显微镜下研究,总能找到各种反例。 而且,我们深知,优秀的实践,一定是做得足够的“软”,对扩展留有设计,能够随着业务发展而迭代,不是一个静态的结果。 因此,打开学习的大门不是几个案例就能一蹴而就的,需要结合我们自己的工作,慢慢累积、体会。 困难:模式发散 我们有一种困惑,到底怎么样算是DDD: 实践的个例,难以信服:当我们看到”DDD实践“的时候,可能会发问:这也算DDD?不就是一个正常的服务端框架与方案,也无法涵盖其它的场景或者部门系统。 抽象的理论,觉得空洞:当我们看到”抽象的DDD定义与策略“的时候,可能会发问:这也算DDD?不就是一些软件设计的共识,然后强加了一些名词定义,有些策略与我们手上的系统也并不匹配。 无论往抽象看,还是往具体实现看,都很难找到令人信服的理论与实践(能够有确定性的落地能力)。因为这不像23个设计模式那样,可以通过N个模版就能涵盖大多数的模式。 为什么不能产生特定的模式呢?可以结合下图进一步来看: 抽象理论:如同抽象的接口一样,"DDD理解"最上面的学习主要是理论定义,比如:聚合根、值对象、资源库、核心域、支撑域等各种定义,这些是易于理解掌握的。 通用实践:如同相对具体的抽象类一样,"DDD理解"中间层次是一些通用原则和技巧,比如:上下文的映射策略、架构的选择等。这些因素是确定的,但需要自主进行取舍与选择,并且需要与时俱进,增量的部分需要你自己学习补充。 “领域驱动理解层次”中无法提供明确的约束,都是多个策略的取舍、一些关键的建议。 因此,由于问题的抽象层次较高,各种策略的不确定性较高,很难在DDD中产生像”23个设计模式“那样精炼的模式。一定要有的话,也是一系列的模式,比较发散。 这的确引入深思。切分比较容易的时候,往往是因为已经有了行业的标准(如:电商系统有订单、支付、物流、库存等领域是比较合理的)。那行业的标准来自哪里?是来自于演化: 开始的时候,可能只是一个大交易,比如:支付开始的时候只是买卖双方自己协议,也不需要建模。 后面支付发展了,也就独立出来一个域。原来不需要专人维护,后面会渐渐拉出一个团队来承接相关研发。 所以,领域的演化和划分,很类似“启发式算法”(一个基于直观或经验构造的算法,在可接受的花费下给出待解决组合优化问题每一个实例的一个可行解): 初始化:按照的经验初步的划分,也可以是行业标准(没有行业标准的时候,就只能靠经验了)。 花费评价:生产、交付过程的人力成本度量,关注理解成本、开发效率、系统稳定性、运维成本等因素。 更优解:在业务发展过程中,计算花费评价,分析影响评价的“好因素”、“坏因素”,进行进一步调整。 往往到最后,我们会发现: 调整的内容:其实是匹配生产关系。 调整的原则:追求职责的内聚,精细化分工。 不断调整的原因:业务在发展,内聚的标准需也要与时俱进。 此外,从关联的角度看,往往我们看组织架构,就能看到领域的边界,核心原因还是组织架构也是要适应生产关系,follow更优解的结构,是相辅相成的,也就能互相窥探。 在刚开始学习DDD的时候,我们可能会强行把一些逻辑放到实体中,进行控制和收敛。但后面随着业务的变化,会发现在实体中承担行为逻辑很难受: 影响较大:很难有勇气去频繁地修改一个核心类。 过于集中:随着方法和逻辑的增多,实体越来越臃肿。 场景较多:很多逻辑并不是正交的,不是 if 这样 else 那样的,充满着交集与叠加。 抛弃 POJO 的get、set,走向实体的丰富行为,让我们编写代码更加困难了么?其实,我们的烦恼来自于,太关注实体行为的收口,忽略了扩展的设计: 原来 get set 写法很舒服的本质在于,很多的扩展被放在了业务脚本中,业务脚本虽然千疮百孔,但是是在应用层,远离核心逻辑。底层模型、通用组件等基础逻辑还是比较干净的。 应用DDD的时候,把一些行为下沉到领域层之后,也是要考虑扩展的。如果只关注收口,不关注扩展,那的确是“画地为牢”、“捡了芝麻,丢了西瓜”。 但是,要突破这一个困境,能够在实体行为中设计扩展,其实要有这样的认同:要往上看一个层次,就是实体行为的表达,不一定只有一个类完成,可以通过策略模式等方式的路由,由一个模块中的一些类进行完成,只要对外有封装和管控其实就可以了。 突破一个类的限制,走向更多的类的协作设计,也是我们进阶的方 【资源库的替代性需求】 在原来的分层的架构中,数据库等存储能力作为一种底层基础设施,是被视为稳定的下层服务的。但在实际的交付过程中,往往要遇到不同场景: 本地部署:线下零售交易为了服务稳定性,期望可以具备本地保存数据的能力。 云上产品:售卖给外部企业的交易产品,成本的要求也不尽相同,期望在云上采购不同的存储服务。 (编辑:甘南站长网) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |