仓库源文

.. Kenneth Lee 版权所有 2018-2020

:Authors: Kenneth Lee :Version: 1.0

抽象还是不抽象的问题


今天评审了一个IP设计方案,有个地方定义了一个完整性校验算法,这个算法有两个控制 变量,可以组合出12种校验效果,这12种校验效果作用在不同大小的控制块上(控制块的 大小当前有5种情况:512, 1024, 2048, 4096, 8192),会出现稍微的差别。做这个IP模 块设计的人呢,希望分每种不同的情形来进行设计,如果其中有些情形用不上,他就打算 直接忽略了。做软件驱动的人呢,显然很不喜欢这样的形式,因为这会产生非常多的重复 代码。但使用这个代码的人呢,更大程度上支持前者,因为这个立即解决他的问题,而且 设计时抱的包袱很少。使用这个代码的人的领导呢,更大程度上支持后者,因为这样他的 代码也很难维护……

谁对?

这种情况无处不在,我做过一个嵌入式网管产品,支持二三十种企业路由器和交换机,每 种路由器和交换机的形式基本上是差不多的,都是基于SNMP确定设备类型,然后匹配它的 mib数据库,提取它的界面素材,绘制界面,然后把功能索引到不同的MIB表管理程序中去 处理。接到这个任务后,组里就激烈地分成了两派:一派要设计一种语言,用来“定义”一 个设备的特征,然后,用一个通用的算法来绘制不同的交换机和功能。一派要各自为政, 除了在确定设备类型的时候使用一个公共的界面,其他就各自根据自己的客户调查和认识 ,做成啥样是啥样,最后拼在一起。

谁对?

又比如拉分支的问题,一线的,对着客户的人,最喜欢拉分支。你对着A客户,要求都定了 ,最重要是不要出问题,出哪个问题就具体修复那个问题。然后你告诉我B客户要修改Code Base?B客户关我鸟事?反过来,家里负责开发和测试的团队就特喜欢版本归一,One Track这类的概念:尼玛每次修改一个特性,要合主版本,A客户分支,B客户分支,C客户 分支,D客户分支……然后每个都要测试,你做给我看看?

谁对?

还有我们编码中无处不在的,你需要一个链表,你是直接在你的数据结构中放next指针呢 ?还是建立一个list数据结构,抽象这个逻辑呢?你把几个radio button合在一起使用, 是直接放几个button,然后加一个控制对象呢?还是实现一个radio button group来“自动 ”完成这个逻辑呢?

这些情况,大部分都是在现有信息下无解的。这个时候,不往前走是错误的,乱往前走也 是错误的。这种情况,你就发现,你习惯的那些“因为……所以……”的理由是完全无力的。这 个时候能够采取的策略就是“道法自然”了:有目标,但守弱,整个过程是放松的,先奔着 直线去,自己不添加这个力之外的其他的力,然后让现实去冲击你(的策略),从而形成 一条合理的路径。

一旦从这个角度考虑这个问题,你就发现你的决策模型不再是因为-所以了。而是不断在过 程中比较所有力量哪个对结果的作用力更大,不断进行观察,调整,和平衡。而且这种判 断仅在当时有效,过后就失效了。你不能因为项目开始的时候没有抽象一个模块,项目结 束的时候抽象这个模块了,你就认为当时“决策失误”。所以,对外行来说,架构师最讨厌 给你讲理由,讲理由本身就是成本,在这种快速决策中,不断消耗“讲理由”的成本,这个 事情就不用干了。

理解这一点,对于进行工程实施非常重要,比如前面这个链表的问题,我从来不纠结到底 要不要抽象的,我的策略是(我只是说大部分情形,前面说了,具体情况要靠“感受”,有 细节在左右),我先不抽象,直到我写到有两个地方都要用到类似的情形了,我才开始把 两者扭合在一起。

如果是个大团队怎么办呢?我的策略是开源(不是对外开源,而是所有开发者间开源), 代码Review。你们互相看到代码了,你们要一起来抽象,那是你们的事,我只保证架构中 给你这个机会(比如我们有这个平台本身的common.lib),你们的东西可以放到一起。架 构的抽象策略是靠系统自然生长,不靠人为的期望(比如“实现抽象”)来控制系统。

而“强控制”放在哪里呢?“强控制”放在强权上。你要卖给某个大型企业,对方有企业安全 规范,这明显是强权,那我基于这个强权需求来设计功能,增加模块,这个模块一旦出现 ,由于其他人要和它接口,自然就形成约束了。架构师通过创建关联来控制系统,而不是 通过定义每个子系统的行为来控制系统。高明的构架设计是什么都不做(请正确理解这句 话的意思),越想表现构架设计做得多么好,这个架构设计就越失败。

求道的团队,每个人都不成为系统的“代理”,这个系统的“代理”就是这个系统本身。架构 好,是这个软件架构好,不是“这个架构师做得好”,代码好,是这个代码本身好,不是“这 个工程师写得好”。这就叫自然之道。架构师用设计师的思维去考虑问题,就是错误的开始 。