可撤消性
如果某个想法是你惟一的想法,再没有什么比这更危险的事情了。
——Emil-Auguste Chartier, Propos sur la religion, 1938
工程师们喜欢问题有简单、单一的解决方案。与论述法国大革命的无数起因的一篇模糊、热烈的文章相比,允许你怀着极大的自信宣称x = 2的数学测验要让人觉得舒服得多。管理人员往往与工程师趣味相投:单一、容易的答案正好可以放在电子表格和项目计划中。
现实世界能够合作就好了!遗憾的是,今天x是2,明天也许就需要是5,下周则是3。没有什么永远不变——而如果你严重依赖某一事实,你几乎可以确定它将会变化。
要实现某种东西,总有不止一种方式,而且通常有不止一家供应商可以提供第三方产品。如果你参与的项目被短视的、认为只有一种实现方式的观念所牵绊,你也许就会遇到让人不悦的意外之事。许多项目团队会被迫在未来展现之时睁开眼睛:
“但你说过我们要使用XYZ数据库!我们的项目已经完成了85%的编码工作。我们现在不能改变了!”程序员抗议道。“对不起,但我们公司决定进行标准化,改用PDQ数据库——所有项目。这超出了我的职权范围。我们必须重新编码。周末所有人都要加班,直到另行通知为止。”
变动不一定会这么严苛,甚至也不会这么迫在眉睫。但随着时间的流逝,随着你的项目取得进展,你也许会发现自己陷在无法立足的处境里。随着每一项关键决策的做出,项目团队受到越来越小的目标的约束——现实的更窄小的版本,选择的余地越来越小。
在许多关键决策做出之后,目标会变得如此之小,以至于如果它动一下,或是风改变方向,或是东京的蝴蝶扇动翅膀,你都会错过目标。而且你可能会偏出很远。
问题在于,关键决策不容易撤消。
一旦你决定使用这家供应商的数据库、那种架构模式、或是特定的部署模型(例如,客户-服务器 vs. 单机),除非付出极大的代价,否则你就将受制于一个无法撤消的动作进程(course of action)。
可撤消性
我们让本书的许多话题相互配合,以制作灵活、有适应能力的软件。通过遵循它们的建议——特别是DRY原则(26页)、解耦(138页)以及元数据的使用(144页)——我们不必做出许多关键的、不可逆转的决策。这是一件好事情,因为我们并非总能在一开始就做出最好的决策。我们采用了某种技术,却发现我们雇不到足够的具有必需技能的人。我们刚刚选定某个第三方供应商,他们就被竞争者收购了。与我们开发软件的速度相比,需求、用户以及硬件变得更快。
假定在项目初期,你决定使用供应商A提供的关系数据库。过了很久,在性能测试过程中,你发现数据库简直太慢了,而供应商B提供的对象数据库更快。对于大多数传统项目,你不会有什么运气。大多数时候,对第三方产品的调用都缠绕在代码各处。但如果你真的已经把数据库的概念抽象出来——抽象到数据库只是把持久(persistence)作为服务提供出来的程度——你就会拥有“中流换马(change horses in midstream)”的灵活性。
与此类似,假定项目最初采用的是客户-服务器模型,但随即,在开发的后期,市场部门认为服务器对于某些客户过于昂贵,他们想要单机版。对你来说,那会有多困难?因为这只是一个部署问题,所以不应该要很多天。如果所需时间更长,那么你就没有考虑过可撤消性。另外一个方向甚至更有趣。如果需要以客户-服务器或n层方式部署你正在开发的单机产品,事情又会怎样?那也不应该很困难。
错误在于假定决策是浇铸在石头上的——同时还在于没有为可能出现的意外事件做准备。
要把决策视为是写在沙滩上的,而不要把它们刻在石头上。大浪随时可能到来,把它们抹去。
|
提示14 |
|
|
There Are No Final Decisions |
|
灵活的架构
有许多人会设法保持代码的灵活性,而你还需要考虑维持架构、部署及供应商集成等领域的灵活性。
像CORBA这样的技术可以帮助把项目的某些部分与开发语言或平台的变化隔离开来。Java在该平台上的性能不能满足要求?重新用C++编写客户代码,其他没有什么需要改变。用C++编写的规则引擎不够灵活?换到Smalltalk版本。采用CORBA架构,你只须改动替换的组件:其他组件应该不会受影响。
你正在开发UNIX软件?哪一种?你是否处理了所有可移植性问题?你正在为某个特定版本的Windows做开发?哪一种——3.1、95、98、NT、CE、或是2000?支持其他版本有多难?如果你让决策保持软和与柔韧,事情就完全不困难。如果在代码中有着糟糕的封装、高度耦合以及硬编码的逻辑或参数,事情也许就是不可能的。
不确定市场部门想怎样部署系统?预先考虑这个问题,你可以支持单机、客户-服务器、或n层模型——只需要改变配置文件。我们就写过一些这么做的程序。
通常,你可以把第三方产品隐藏在定义良好的抽象接口后面。事实上,在我们做过的任何项目中,我们都总能够这么做。但假定你无法那么彻底地隔离它,如果你必须大量地把某些语句分散在整个代码中,该怎么办?把该需求放入元数据,并且使用某种自动机制——比如Aspect(参见39页)或Perl——把必需的语句插入代码自身中。无论你使用的是何种机制,让它可撤消。如果某样东西是自动添加的,它也可以被自动去掉。
没有人知道未来会怎样,尤其是我们!所以要让你的代码学会“摇滚”:可以“摇”就“摇”,必须“滚”就“滚”。
相关内容:
l 解耦与得墨忒耳法则,138页
l 元程序设计,144页
l 它只是视图,157页
挑战
l 让我们通过“薛定谔的猫”学一点量子力学。假定在一个封闭的盒子里有一只猫,还有一个放射性粒子。这个粒子正好有50%的机会裂变成两个粒子。如果发生了裂变,猫就会被杀死;如果没有,猫就不会有事。那么,猫是死是活?根据薛定谔的理论,正确的答案是“都是”。每当有两种可能结果的亚核反应发生时,宇宙就会被克隆。在其中一个宇宙中,事件发生;在另一个宇宙中,事件不发生。猫在一个宇宙中是活的,在另一个宇宙中是死的。只有当你打开盒子,你才知道你在哪一个宇宙里。
怪不得为未来编码很困难。
但想一想,代码沿着与装满薛定谔的猫的盒子一样的路线演化:每一项决策都会导致不同版本的未来。你的代码能支持多少种可能的未来?哪一种未来更有可能发生?到时支持它们有多困难?
你敢打开盒子吗?







