.. Kenneth Lee 版权所有 2020
:Authors: Kenneth Lee :Version: 1.0
三个锦囊
本文记录一个最近一些架构讨论时总结的观点。
(特别说明一下:本文举的例子都是作者杜撰出来的,和实际的设计没有任何关系,更和 作者做的工作没有任何关系。作者举例子都是根据现实工作去找有那么远离那么远的技术 来做平行对比的,所以,请聚焦在逻辑Pattern上,不要由此猜作者本身在做什么技术。)
小时候听演义故事,经常碰到“三个锦囊”的故事:一个武将/二愣子/儿子/徒弟(反正代表 出力的角色)出去办事,军师/父亲/师傅(反正代表出脑的角色)给他三个锦囊,遇到什 么情况就打开第一个锦囊,照方取药,再遇到什么情况,再打开一个锦囊,又按方取药…… 如此这般。当然,最后一个锦囊通常是个逗逼主意,比如“快逃”,“等死”之类的。说书人 通过这种方法说明这些出脑力的角色们有多么的“多智近妖”。因为不多智近妖,也没法形 容这个人牛出天际。至少得比说书人和观众牛,否则如果整个战略逻辑说书人和观众都能 理解,那有什么牛的?
这种锦囊式的行为也常常出现在我们的构架定义中,我对这个本能反感。我原来没有想过 这种反感的来源。今晚给别人解释,现场我把逻辑梳理了一下,我自己才搞明白了这个逻 辑,所以在这里记录下来:
构架这种东西,就是面对未来,面对变化。要面对未来,面对变化,我们通常有两种方法 :
预判,并基于预判进行设计
尽可能留下余地,以便出现不能预判的变化的时候,可以躲避和进行权衡和放弃
第一点没有什么可说的,这完全是个经验和调研的活,受人力(能力)所限。而第二点是 本文要讨论的关键。我们定下很多目标,针对每个目标的设计,我们都会制造规矩(约束 ),为了在约束下实现更多的功能,我们还要细化更多的约束,但我们总会遇到自相矛盾 的时候,解决自相矛盾的方法是比较两个约束的收益,然后放弃其中部分收益。但这个过 程最怕的是遇到锦囊了:这是绝对的,无条件的约束,根本没法权衡,而我看不到它的收 益。这种横切一刀的设计约束,斩断架构设计一切自由度,关键提出这种锦囊的人还没有 主角光环,不能保证我按这个来操作“果然逢凶化吉”。这种东西定义出来,就很让人,特 别是架构师,觉得不安全了。
用一个生活的例子来做类比,比如我们确定明天出去春游,有人提出要爬山,有人要运动 完大吃一顿,有人提出要浸温泉。我要组织这个活动,我就得搞清楚,到底有几个人想要 爬山,对这个事情有多喜欢,对吃有兴趣的人又有多少,想吃啥,浸温泉的又如何……知道 这些了,一查资料,能爬山的和能浸温泉吃饭的不在一地。那就没有什么可说的,比较两 边的收益,选一边呗,这种东西可以权衡。但如果我收到某人递给我的一个锦囊,里面说 一定要爬山。这个东西就不安全了,关键是这锦囊是谁拿过来的?出问题他负责吗?
换成设计,比如我做一个ARM应用在x86平台上运行的解决方案,最优的当然是这个应用静 态编译也能跑,动态编译也能跑,可以做成x86的安装程序,速度和x86本地程序一样,可 以作为容器运行,也可以作为虚拟机运行……反正这些东西有总没有什么不对。尽管如此, 你还是基本知道每个这种需求(背后就是约束)的收益是什么。你是可以进行取舍和放弃 的。然后这时你在构架设计中发现有人给出这么一个判词:“ARM程序必须可以调用x86的库 ”。这就变成一个锦囊了。如果我这个设计不是我做的,作为整个架构设计的其中一方,我 看了这个判词,我没法判断这个判词到底是因为技术约束引入的,还是逻辑冲突引入的, 和谁冲突了……但如果我承认它可以存在在我们的架构设计中,那我就需要认为它是个必须 无条件遵守的“锦囊”。它的地位就和其他的约束不一样了。这个判词在整个逻辑空间中铁 锁横江,横插一道,整个本来还有自由度的空间,一下变硬了,这样的地方,就是构架开 始被锁死的起点了。因为未来补充逻辑的时候,每个人都会首先找“最硬”的约束作为依赖 。这样本来是个假的依赖,后来被其他真依赖所依赖,它就变成一个真依赖了,整个系统 就做歪了。比如下一步我实现PIC delay binding的时候,发现做这个delay binding的成 本很高,收益不足,但因为你前面已经承诺ARM程序可以调用x86的库,这个无论如何都要 做,这个成本我们就必须接受了,但接受了这个约束,我们整个性能都做不上去,这个解 决方案就只能永远地走向低性能(多功能)的方向了。
这甚至可以直接导向项目的失败。比如前面春游问题中,如果锦囊是“必须爬山吃饭”,那 就不用去了。
所以架构师讨厌这种锦囊。我们讨厌的是架构的自由度被关掉了,而架构师的所有工作, 其实只是营造这个自由度而已。
更重要的是——很多人不一定注意到,前面的设计例子还可以反过来的,如果你下这样的判 词:ARM程序不可以调用x86的库。这和前面的那个判词是一样的效果,它同样是个“锦囊” 。所以,锦囊不在于左右,锦囊在于它不能动。
所以,架构设计中,你不能给我没有理由的约束,然后跟我说:留着呗,又无害。错!在 架构设计中,任何多余的约束都有害。因为架构设计不是细节逻辑设计,架构设计要响应 不在逻辑链中的变化的。
一个好的架构设计,就好像一个洋葱。最核心的约束包在最里面,弱一点的约束包在中间 ,更弱的包在外面,这样在整个架构发展的过程中,你是有放弃的机会的,你才有生存的 本钱。
而这也解释了为什么架构师这么重视依赖的的控制,因为如果你的逻辑依赖全部都弄在一 起了,前面提到的这个策略根本无法实施。你放弃任何一个收益,所有相关的依赖都得拆 除,而你的依赖都是关联在一起的,要拆除就只能全部放弃了。