你听过,代码逃逸,逃逸出原有的设计。
你听过,架构腐化,导致出现了坏味道。
可是,你听过逻辑泄露吗。
在应用领域驱动设计的时候,聚合与聚合根(Aggregation Root)是构成“富含知识的模型(Knowledge Rich Model)”的关键。通过聚合关系,我们可以将被聚合对象的集合逻辑放置于聚合 / 聚合根里,而不是散落在外,或是放在其他无关的服务中。这么做可以使得逻辑富集于模型中,避免“逻辑泄露”。
早在之前,我们这个系列中,我写过一篇文章。
《写代码,你以为的快方法,可能是慢方法》里面讲到过“业务逻辑复杂了,业务的逻辑、状态会散落到大量方法中,你没有抽象,就没有办法模块化,就不能区分核心和周边,需求越来越多,你就只能硬写,你的这种硬写,往往都是写到了核心模块里面了,之所以成为核心,不就是希望你不要总是改变它吗,要尽可能将其变为只读的,否则,你当初的快就是后来的慢;”
Martin Fowler 称作“贫血对象模型”(Anemic Model)的实现风格,即:对象仅仅对简单的数据进行封装,而关联关系和业务计算都散落在对象的范围之外。这种方式实际上是在沿用过程式的风格组织逻辑,而没有发挥面向对象技术的优势。
凡是都有个两端,向左和向右,任何走向极端都是不好的。
到这里,有的同学可能就会想到,如果我不想把逻辑散落在外面,我把它们集中到一起,就可以避免逻辑逃逸了。
所有的逻辑都集中到一个类里面去,会有什么后果?
会导致过大的类产生,会导致违反单一职责,会导致代码僵硬,会导致阅读这个类的程序员的认知负担加重,会导致最终这个类,“看不懂、改不动”。
留下一堆祖传代码。
我在京东上购买了一台iPhone13手机,我在讨论区中又跟其他购买者交流手机的功能特点,我同时还订阅了手机周边的通知信息,比如有更漂亮的手机壳,就通知我。
我,作为一个用户User。同时参与了三个上下文。
购买手机产生的订单关系上线文、交流功能特点的社交上下文、订阅周边设施的订阅上线文。
如果,我们本着“富含知识的模型”的原则,我们所有的逻辑关系都会跑到这个User对象中,结果就会导致一个大大的类产生。
根据构建“富含知识模型”的做法,被聚合对象的集合逻辑放置于聚合 / 聚合根里,而不是散落在外,或是放在其他无关的服务中。这么做可以使得逻辑富集于模型中,同时有利于通过聚合关系管理一组对象与领域概念的映射,保持领域概念与逻辑的完整性。
不是应该要遵循“富含知识的模型”的原则吗?
是要。
但,如果一个实体对象在不同的上下文中扮演了多个角色,购买者,交流者,订阅者,结果就会把这个实体用户搞得“精神凌乱”。
我们要做的就是把角色对象和上下文区分开来,实际上就有三个角色对象,不是么,购买者、交流者和订阅者。如果你让一个实体同时扮演这三种角色当然就会把这个实体搞得迷茫了。
可能,你会发现,我们是不是需要建模了。
先给你说个例子。
程序员小明,某一天接到一个需求,分析过后,发现需要修改到程序的核心模块,于是,小明评估了一个较大的工作量,也导致了一个较长的交付时间点。业务人员小强,于是就怀疑程序员小明,对开发工作量留了buff,随后的日子里,小强开始不断地挑战工期进度。这个场景是不是很熟悉,为什么会导致这样的情况发生呢。
可能的原因之一,核心模块没有业务建模,建模了,业务方也没有达成统一。
业务建模,最难的是什么?是建模的过程吗,是建模的方法吗,可能对于大多数的我们来讲,最难的是如何说服业务人员来接受模型作为一种统一的语言,也就是,下次大家一看到这个模型,就发出这样的感觉,“哦,就是这样的,它表示了...流程”。
或者你的建模模型中把所有的业务维度的内容都隐藏了起来,当然这个隐藏不是你故意的,而是很有可能,当时就没有意识到,无意间把这些业务维度的内容都埋起来了。哪些内容呢,比如流程、交互、功能和规则等等。
建模成功的关键取决于逻辑的收敛,而不是发散。
----END----
这里记录,我每周碰到的,或想到的,引起触动,或感动的,事物的思考及笔记。不见得都对,但开始思考记录总是好的。
与爱学习、爱思考、爱记录的你共勉。
参考资料:
https://time.geekbang.org/column/article/395650 《如何落地业务建模》