暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

【技术学习】DDD的一些理解

梦新起点 2021-11-04
188
近日,另一个项目团队分享了关于领域驱动开发的实践过程。这次分享于我而言,余音绕梁,三日不绝于耳。不仅仅是对于工作而言,对自己之前读过的书,有过的想法产生了一些碰撞。一方面我在尝试更深层次的去理解,用来指导自己的工作;另一方面,也开始有点惊讶这样一个事实:有的事情并不是越了解就越能掌握的,一个好的思想就像打开新世界的大门,感觉到的更多的是渺小。

分类的哲学

我曾经有过这样一个困惑,制约我们的那些规则到底都是哪里来的?有的人说是从老祖宗那里流传下来的,但事实上,从过去能影响到现在的一些习俗多多少少都已经不再是原先的样子的,就拿最常见的做菜来说,很多说从古法中研习的菜肴,却放了很多当代的调料,单靠这一点,肯定和曾经的味道是有所差别的。即便是能从古书中了解个大概,但是就算制作佳肴用的器皿工艺不同,也终究是不一样的。
从这样一个示例来审视的话,想象中那个不变的概念,实际上也是在发生微妙的偏移,直到完全变了个样子。这就涉及到了一个悖论:忒休斯之船,这艘船随着一点点的被更换掉,那这艘船还是不是原来的那艘船?我们的习惯也是如此,如果一点点的在改变,那么还能不能被称作习惯?
在编写代码的时候,实际上就是有这样的困局,编写一点点代码的时候,看这部分是一个样子;但是随着慢慢的调整,之前定义的规则边界就开始模糊,总会出现很多模棱两可的答案,再加上大型软件工程参与者比较多,很容易出现不同的风格。即使出自同一个工程师的手笔,也会随着时间发生偏移和转变。从这样一个视角看过去,我们要编写的代码,必须得有一个特点,它需要有一点点成长的空间,而不能是一成不变的。
在面向对象编程中,大部分时候,会定义一个对象,然后定义好对象的职责,然后把它编排到系统中去,这里面会出现两种极端场景:有的对象从诞生之日起就少有人问津,或者就是在历次迭代中早就该退出舞台了;然后有的对象则是多面手,在哪里都被用到。对于第一类,因为它很少被用到,所以在被用到的时候,可能已经时过境迁,这个时候很容易出现场景迁移,新的场景范畴大于了原有设计范畴,功能就会和预期不同。第二类,用到的地方太多,但是在每种场合又有细微差异,如果轻易的归纳成一个通用的尺码,那么就像在所有场合都穿运动衫一样,或者所有场合都着正装一样,也是比较尴尬的,一个牵一发而动全身的类,实际上变更的成本是非常大的。
所以,分类是一个难事儿,特别是准确的分类,总有一些处在边界上的可以在两个相似的语义间来回跳动。文化的自然生长会让一些看起来牢不可破的边界变得很脆弱。这就引入了DDD要解决的第一个问题:标准化的语义上下文。团队首先要达成的是一种分类的一致,解决开发者团队内部产生的分歧。但问题来了,如何定义和拆分?

收纳的艺术

在学习CMMI过程的时候,有这样一句话贯穿始终:记录的文档和资料是有区别的,它们的区别就是能否对你后续和未来的工作产生更深远的影响。这句话主要是针对这样一种错误观点“CMMI过程就是对文档的检查”,有两种途径去制造这些文档,一、贯穿始终,这些文档的形成依赖于一个资料库,这个资料库在规划团队前进的方向;二、事后补充,这些文档或许就是为了应付检查去制造出来的,离散的散落在每一个环节,评估过去后,很难有什么深远的影响。
这里定义第一种材料就是资料;而第二类的只能算作文档。可能到这里,还是有点不太好理解,曾经有一本书叫做《超级整理术》,讲述的就是怎么规划自己的物品,最终达到的目的就是能够快速的存放和找到自己想要的东西,这就是在整理这个过程中的一个双行道,既能存放进去,又能检索出来。同样对于文档和资料的区别就是:文档是单行道,只有存进去;而资料则是有一定的结构,可以被快速的整理到一个特定的位置,同时也能快速的取出来,用于指导别的工作。
那么这就是一个理想的典范,DDD如何定义边界和拆分,实际上演绎的就是这样一种魔术。传统的软件工程,最容易出现的问题就是调用关系没有妥善维护,时间久了,代码就如同不加整理和分类的衣橱一般,混乱不堪。冬天和夏天的衣服堆在一起,上衣和裤子也混在一起,每次想找一套得体的衣服都需要花很多时间。
那试想,如果在衣柜中,做了几种分类,可以是这样的一组分类方式:上衣在一个盒子里,裤子在一个盒子里;但也可以这样分类:一套礼服在一起,一套工装在一起,一套运动衫在一起。然后选择不同的场景进行处理就可以了。但是如果团队中,有的人认为采用第一种分类方式,有的人采用第二种分类方式,分歧便又产生了。即使已经在努力把衣橱变得更加容易存放和取用,但依旧在看待分类上有不同的视角,该如何统一视角呢?什么又是最佳的实践呢?

然的边界

如果说真的存在一个最好的实践,实际上就有点夸夸其谈了。所有的好坏脱离场景去讨论优劣,都是片面的认识,常言说的好“彼之砒霜,吾之蜜糖”,所以任何评价都要带上它的背景上下文。不能因为场景描述起来繁琐,就放弃观察细微差别引起的变化。
好的领域建模一定是要基于场景去定义的,如果想最大程度上去保证灵活性,那么领域的粒度就会变得非常小;而如果服务于一个比较特定的场景,那么领域的粒度就可以微微放大。这之间就会产生一种微妙的平衡,犹如自然的边界或者树叶的纹理。
如果每一座山都能如同华山峭壁一般,这样山川与平原的边界就一目了然,但是更多的时候,评论山川与平原,可能要依赖一个准确的高度攀升变化来表明。很像函数的导数,直观的结论可能需要深层次的理论去支持才能得出。
那领域的模型到目前为止还是没有办法统一,在思考这个边界怎么确定的时候,想起来了一个《庖丁解牛》的典故:

庖丁释刀对曰:“臣之所好者,道也,进乎技矣。始臣之解牛之时,所见无非牛者。三年之后,未尝见全牛也。方今之时,臣以神遇而不以目视,官知止而神欲行。依乎天理,批大郤,导大窾,因其固然,技经肯綮之未尝,而况大軱乎!良庖岁更刀,割也;族庖月更刀,折也。今臣之刀十九年矣,所解数千牛矣,而刀刃若新发于硎。彼节者有间,而刀刃者无厚;以无厚入有间,恢恢乎其于游刃必有余地矣,是以十九年而刀刃若新发于硎。虽然,每至于族,吾见其难为,怵然为戒,视为止,行为迟。动刀甚微,謋然已解,如土委地。提刀而立,为之四顾,为之踌躇满志,善刀而藏之。”    
--《庄子·养生主
对于一个需要实践的团队而言,最重要的可能并不是期待别人给出一个终极答案,可能在探索领域建模的路上也是需要从最开始大刀阔斧的拆分,随后不断的细化与调整,最终找到一种领域模型定义边界,然后找到这个边界也绝不是旅途的终点,因为遇到的问题是在不断变化和成长的,所以最终的方案也是需要是一个成长的方案,能够在不同的场景下绽放自己的优势和特点。简而言之,最好的答案一定是在路上。

【图1】


最后,在和同事进行探讨的时候,发现自己还是有很多想法,可能并不契合书中讲到的思想。但是想了许久,还是想借此谈谈对领域驱动的理解:DDD更像是一种收纳艺术,传统方案解决的是数据存储和流程建设的问题,但是却忽视了数据取用和流程维护的工作,这样就像只有一个单向道,不能形成一个自组织的体系自给自足的进行修改,更多的时候,是在增加补丁缝缝补补,这样的系统从诞生之日起就已经限制了它最高的高度。而领域模型,可以赋予组织模式的自生长,通过一种良好的领域共识和维护机制,让模型能够适应性的调整与生长,从而成为一种最大程度贴合业务需求的软件结构。



【图1】选自网络图片,如有侵权请联系删除。
文章转载自梦新起点,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论