61 | 全局性功能的架构设计
在架构设计中,我们会有一些难啃的骨头。其中最为典型的,就是全局性功能
全局性功能特征:
很难被独立分成模块
读盘 / 存盘功能
以 Office
软件作为例子
- 读盘 / 存盘:每增加一个功能,都需要考虑这个功能的数据如何存储到磁盘,如何从磁盘中恢复。
Undo/Redo
:每增加一个功能,都需要考虑这个功能如何回滚 / 重做,很难剥离。- 宏录制:每增加一个功能,都需要考虑这个功能执行的结果如何用
API
表达,并且得支持将界面操作翻译成 API 语句。
需求交织在一起,全局性功能往往难以彻底进行正交分解。但对于架构师来说,难不代表应该轻易就放弃对正交分解的追求。
引入 IO DOM
来进行正交分解
关键点:
- “读盘 / 存盘” 本身需求是发散的,因为要支持的文档格式只会越来越多。所以我们必须把它独立成一个子系统,比如叫它
IO
子系统。 - 要独立子系统,就需要抽象出它对核心系统的稳定依赖.为什么这个稳定依赖最后设计为 IO DOM,是因为 DOM 是核心系统的常规界面
因为读盘存盘是全局功能,我们没法消除这种全局性,但是可以尽可能削弱到最低。
因为 IO DOM
名称上虽然带了 IO
,但是它只是一个归类,实际上这些接口都是核心系统的常规接口,并非为 IO
子系统定制。这样一来,读盘与存盘带来的全局性影响就近乎被消除
IO DOM
则是反其道而行之,通过抽象核心系统的接口,让全局性功能反向依赖这些接口来完成。这不容易,但是这样做核心系统受到的伤害值最低。
Undo/Redo 功能
在设计模式中有一个模式叫 Command
模式,专门用于解决 Undo/Redo
这个功能场景的。它的基本思路是,每个用户操作都实现为一个 Command
,每个 Command
需要实现反操作,以便做到 Undo
的能力
但实际上框架只节省了 1% 的工作量。其余 99% 的工作量在实现一个个 Command 身上,框架使用方的心智负担不是一点点的大。
快速存盘
存盘的时候并不是把完整的文档写到磁盘文件中,而是将上一次存盘到这一次存盘的增量部分,追加到文档的尾部。这样一个 Word
文件就有多个版本的文档,每次读盘的时候只需要读出一个最新版本即可。
要想避免系统无法响应用户编辑的另一个思路是异步存盘
只要支持了多版本,就有了镜像能力,也有了Undo/Redo
能力。
数据层(DataLayer)
可以把它类比为服务端的数据库。它是一个存储中间件,负责托管所有的数据
随着今天软件服务化(SaaS)大行其道,基于某种存储中间件来写业务逻辑,越来越多人意识到它已经是一种必然的趋势。
宏录制功能
什么是宏(Macro)?
所谓宏(Macro),是指二次开发的代码。微软几乎所有的产品都有二次开发接口,也就是 API 层,典型代表是 Office
和 Visual Studio
有了二次开发接口,就可以有生态,有围绕着 Office 和 Visual Studio 的生态厂商,来争强产品的能力,也可以让 Office 和 Visual Studio 更容易地融入到企业的业务流中。可以说,支持宏是微软做得最牛的地方。
什么是 “宏录制”?
就是把用户的界面操作用 API
调用的方式记录下来,把它变成一段二次开发代码。
好处:
- 被录制下来的 “宏”,可以被反复重放,如果某件事情经常发生,它就可以改善我们的工作效率。
- 被录制下来的 “宏”,可以进行修改迭代,进行功能的增强。这有助于二次开发的新手学习
Office
或Visual Studio
的API
接口,大幅降低二次开发的入门难度
怎么支持 “宏录制”?
宏录制也像日志一样,会去记录一段文本。我们想象一下,如果我们的 Model 层 DOM API 也基于 RESTful AP
I 接口,那么我们就可以在 API
入口的地方去实现 “宏录制”。
“宏录制” 需要考虑 API
嵌套,我们实现某个 API
可能会调用另外某个 API
,但是录制的时候,肯定只能录最外层的 API
,而不是所有 API
调用都被录制下来。
架构师的信仰
任何功能都是可以正交分解的,即使我目前还没有找到方法,那也是因为我还没有透彻理解需求
怎么做业务分解?
核心系统一定要最小化,要稳定。坚持不要往核心系统中增加新功能,这样你的业务架构就不可能有臭味。
记住最重要的一点:
保持核心系统的纯洁性比什么都重要

本作品采用知识共享署名-非商业性使用-禁止演绎 4.0 国际许可协议进行许可。
- 上一篇: 60 | 架构分解:边界,不断重新审视边界
- 下一篇: 62 | 重新认识开闭原则 (OCP)
目录