代码防腐

共 2215字,需浏览 5分钟

 ·

2021-03-20 10:45

代码腐化似乎注定的

  • 最初:没有谁是不想好好写的。都有一个宏伟的规划,这次一定

  • 途中:Code Review 如同“堂吉诃德”一般,根本架不住大批量大批量的修改

  • 放弃:躺平了,下次一定

如此循环往复。然而腐化了之后,是无法起死回生的。

  • 食品防腐是 low tech 的事情,但是中毒身亡之后起死回生是天顶星技术

  • 新冠疫苗已经被人类掌握,但是逆转免疫风暴造成的多脏器衰竭仍然是天顶星技术

虽然很多人醉心于遗留代码改造之道。笔者也从事铲屎业务很多年,仍未掌握此项技术。还是让代码一直保持在未腐化的状态更简单一些。

那么代码如何防腐呢?不靠 Code Review 又靠什么呢?

信息隐藏

如果我们要给 vscode 添加"列出单元测试",以及"执行单元测试"的功能,例如实现下图所示的功能:

是不需要给 vscode 提交 pull request 的,可以通过新建 Git 仓库以插件的方式给 vscode 扩展功能。

用 Git 仓库的依赖关系图来看

通过这样的依赖关系,我们就把插件的实现细节,也就是其私有的信息(比如 ts server,mocha这些)给隐藏起来了。vscode 不可能反向依赖去知道 mocha-test-explorer 使用了 mocha,同僚插件 typescript-language-feature 也不会对 mocha-test-explorer 的 mocha 产生耦合关系。这种做法叫信息隐藏。

更通用的说,这是一种 主板 + 插件 的结构。


这种结构和常见的“聚合 API”是不同的

如果我们在插件中持有私有的数据,插件自己再怎么开接口,也无法把信息主动暴露出去。因为主板不依赖插件,插件之间也不互相依赖。除非主板提供接口,由插件来实现才能暴露信息。什么信息隐藏,什么信息暴露,完全由主板决定。

如果是上图所示的“聚合 API”风格的依赖关系。服务自身持有的数据就未必是私有的了,很有可能退化成代持的关系。比如服务如果把没有任何额外逻辑的 CRUD 接口都暴露出去了,这个服务就退化成了 database proxy 了。这样的信息是否隐藏,完全取决于“每个”服务对自己接口的设计。而不能像上图所示,把所有的裁量权集中到主板手上。

太理想了吧!这玩意能写业务?

如果我们要实现下面这样的离散型 UI

要拆成主板和插件两部分并不难,比如主板可以是这样的

插件自然是把上面的坑给填上。

如果我们要实现下面这样的混合型 UI

与离散型 UI 不同。这样的界面没有明显的槽可以开出来。一个区块可能是由多种源数据综合计算出来的。这样的情况,主板可以是这样的:

然后插件就是不断地填充这个数据结构

除了只读的界面渲染,还包括响应用户输入和表单提交的写操作。比如下面这样的离散型流程:

显然这样的业务类型非常适合事件驱动。我们让下单完成去触发 OrderCreated 事件,由其他感兴趣的 Git 仓库去订阅这个事件。插件和主板是这样的一种依赖关系:

但不是所有的流程都是这么简单的离散型。比如下面这样的混合型流程:

可以把混合型流程拆分成多个子流程的复合

如果不想插件与插件之间产生直接的依赖关系,但是又要进行流程复合,那只能把一些接口给下沉到主板里。比如这样的 Git 仓库依赖关系

通过以上4个例子,我们可以看到实际的业务需求是可以用类似 vscode 的插件架构来实现的。这么别扭的写业务是为了啥?


代码防腐

1971 年 David Parnas 就已经写成了软件工程的开山名著《On the Criteria to be Used in Decomposing Systems into Modules》。业内的前辈们已经意识到了按流程图来拆分模块肯定是错误的(it is almost always incorrect to begin the decomposition of a system into modules on the basis of a flowchart)。然而50年过去了,我们主流的模块拆分的思路仍然是“函数套函数”,“中台套中台”的想法。为什么?

这是国外一个开发者调查中受访者的从业时间的分布图

国内的开发者分布会比这个更偏年轻得多。这说明了新人还在不断地涌入这个行业。如果指望一个项目上所有的人都能遵守很高的标准,能够独立对“好”和“坏”的设计做正确的判断,这是不现实的。并不是说软件工程教育不重要,教育仍然是要做的。但是仅仅靠教育来提高软件工程的质量是不现实的。

如上图所示的“信息隐藏”的做法,其实质是为了“代码防腐”。在这样的依赖关系下,插件的 Git 仓库是不会造成全局的影响的。所有的重大决策权都收敛到了主板手里,插件无法自己决定接口是什么以及如何与其他插件集成。这样我们就可以放心地分配新人去写插件,而不用担心插件中的设计选择造成大面积的代码腐化(大不了也就是重写这个插件)。Code Review 也从螳臂当车,变成了只需要重点关照主板的修改即可。


点击”阅读原文“,访问《业务逻辑拆分模式》电子书 https://autonomy.design


浏览 52
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报
评论
图片
表情
推荐
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报