为什么我不喜欢用建筑比喻软件

转自:https://techsingular.org/2011/09/24/为什么我不喜欢用建筑比喻软件/

最近在读《 Code Complete, 2nd Edition 》。谈论比喻 (metaphor) 的重要性时,这本书把建筑作为软件开发的主要比喻之一,并且认为这个比喻很贴切很有用。我认为这本书有很多正确的结论,但不包括对这个比喻的看法以及随之而来的某些直接推论。

对于一个建筑,很容易区分哪些是基础,哪些是附属(或者分辨各个部分更接近基础还是更接近附属的程度)。墙面的装潢很容易修改,改变墙体的构造就很困难。对摩天大楼来说,改变顶层的尖塔很容易,而改变首层的承重结构就几乎不可能。基础和附属在修改成本方面的巨大区别令人直观的意识到规划的重要性。构建一个各部分都「摸得着、掰得下来」的狗窝和构建一个很多东西「封在里面、压在底下」的摩天大厦绝对需要完全不同的规划方式、设计手段、和管理模式。对于后者,构建之前的确需要仔细分析,针对基础部分的决定一旦作出很难更改。

但是把这个比喻延伸到软件会引入众多似是而非的问题。可以从修改的难度来界定软件的基础和附属吗?可以从暴露的程度来区分软件的核心和外围吗?让我们尝试几种判断的方法。

首先,可以把软件系统中靠近硬件的部分,或者被最多的模块依赖的部分称为基础吗?可是,有无数的成功实例说明应用软件可以从一个操作系统移植到另一个操作系统,或者一个操作系统从一种内核迁移到另一种内核。在整个软件栈 (software stack) 中这种釜底抽薪的替换工作并不鲜见。在软件栈稍靠上的地方,也不乏保留上层模块而替换相对底层模块的例子。就在最近的 Adobe Creative Suite 5 for Mac 大部分产品从 CS4 的基于 Carbon 转换到基于 Cocoa。

可以把靠近用户的部分称为基础吗?大多数完全不了解编程的人可能都会反对。软件的界面、皮肤、look and feel 都是可以不断变化的。可以把与具体算法无关的机制称为基础吗?不久前我的 blog 里关于微内核和 XNU 的文章里可以看到内核的演化中,各个模块的运行级别可以在内核态和用户态之间切换,通信机制也可以发生变化。可以把与具体机制无关的算法称为基础吗?Linux kernel 的调度算法在不改变进程切换机制的情况下从线性时间复杂度变成常数时间复杂度。Mac OS X 的 built-in VNC 实现 (Share Screen.app) 在不修改基本机制的情况下加入了大大优于其它实现的屏幕数据压缩算法。符合标准的接口和协议是不能轻易修改的基础吗,比如 x86 指令集或者明文协议?你总是可以用某种中间翻译层来替换它们,比如 VMWare、Linux 的 Wine、Windows 下的 Cygwin、以及 Mac 下的 Rosetta 或者 ssh tunnel 这样的 gateway 方案。

所以,软件和建筑根本的不同是前者不可能存在被「封在里面、压在下面」的「基础」。《 The Art of UNIX Programming 》里告诫程序员,让软件系统长久保持生命力的唯一手段,是把它分解成功能独立而且可以替换的模块。换句话说,软件系统中出现了如同建筑中那种不能轻易修改的基础才是失败的设计。软件需要一定程度的规划,却并非如同建筑所比喻的那样。相反,这种规划是为了让软件具有完全不同于建筑的灵活性。软件同样需要事前考虑避免重复投入,但是在软件系统中,并没有建筑中那种一损俱损的中心基础模块,修复不同模块的设计缺陷的花费并无数量级的区别。适度的事前规划软件开发是必要的,但是我见过很多的新手惧怕的风险其实来自「建筑的基础」这个蹩脚的比喻,事后往往证明,很多在他们看来很严重的必须在 coding 之前分析透彻的潜在问题,都能非常容易在 coding 进行到中后期的时候被解决。而且在这个时候,他们往往已经从 coding 和初步的 testing 中吸取了很多事前分析无法获得的知识和分析手段。而他们认为的一些「关键」组件,即使不幸存在设计缺陷,也并不比外围组件的缺陷修复起来更难。

你可能感兴趣的:(为什么我不喜欢用建筑比喻软件)