[置顶] 计算机科学箴言集 -- <编程珠玑续>

6 计算机科学箴言集

程序员常常要转换时间单位; e.g. 一个程序每秒能处理100条记录, 那处理100w条需要多久? 用除法算, 就知道要花100000秒, 按每小时3600秒算, 差不多3小时;
而一年有多少秒? 如果我直接告诉你 3.155x10^7秒, 你可能很快就忘了; 事实上, 要记住这个很简单, 在误差不超过0.5%的约束下:
          π 秒就是一个纳世纪    ——Tom Duff 贝尔实验室    [nano  1 × 10 −9  ]
所以, 如果程序要运行10^7秒, 就要准备等上4个月;

1985Feb的"ACM通讯"向读者征集与计算有关的箴言; 读者来稿中有些是无争议的, e.g. Duff法则是一种很方便的记忆常数的方法; 而下面这个关于程序测试方法的法则中的数字则不那么绝对(回归测试方法保存老版本的输入/输出数据, 以确保新版本程序能得出同样的输出);
        回归测试能将测试区间减半     ——Larry Bernstein 贝尔通信研究院
Bernstein的观点中所说的数可能是30%也可能是70%, 然而可以确定的是, 这些测试节约了开发时间; 

不怎么定量的忠告也存在问题; 相信大家都会同意;
        小别胜新婚;     ——佚名 
但也说 
        眼不见, 心不烦;    ——佚名
最后这句话对每个人都适用, 对这些话本身则不适用; 本章中的很多箴言也存在类似的矛盾; 尽管每句话都有真理存焉, 还是应该有所保留地看待它们;
  关于箴言的出处, 不得不声明一下; 箴言下的名字基本上都是最早把这句话发给我的人; 在一些地方我列出了更早的参考文献以及作者的单位; 我知道这样做对不起那些最早说出这句话的人, 只能用下面这句话表达遗憾:
  剽窃即是最诚恳的恭维      ——佚名

6.1  编码
  如果还没想清楚, 就用蛮力算法吧         ——Ken Thompson,贝尔实验室

  不要使用反正弦和反余弦函数——总能用优美的恒等式, 或者是计算向量点积来更好地解决这些问题         ——Jim Conyngham, Arvin/Calspan高级技术中心

  在存储日期中的年份的时候, 请使用四位数字: 千禧年快到了         ——David Martin, 宾夕法尼亚州诺里斯敦

  避免不对称结构         ——Andy Huber, Data General公司

  代码写得越急, 程序跑得越慢             ——Roy Carlson, 威斯康星大学

  用英语都写不出来的东西就别指望用代码写了         ——Peter Halpern, 纽约州布鲁克林

  注意细节         ——Peter Weinberger, 贝尔实验室

  如果代码和注释不一致, 那很可能两者都错了         ——Norm Schryer,贝尔实验室

  如果发现特殊情况太多, 那你肯定是用错方法了         ——Craig Zerouni, Computer FX公司(英国伦敦)

  先把数据结构搞清楚, 程序的其余部分自现         ——David Jones, 荷兰阿森

6.2  用户界面
  【最小惊异原则】尽可能让用户界面风格一致和可预测         ——几位读者提出

  计算机生成的输入通常会让一个原本设计接受手工输入的程序不堪重负         ——Dennis Ritchie, 贝尔实验室

  手工填写的表单中有20%都包含坏数据         ——Vic Vyssotsky, 贝尔实验室

  80%的表单会要你回答没有必要的问题         ——Mike Garey, 贝尔实验室

  不要让用户提供那些系统已经知道的信息         ——Rick Lemons, Cardinal数据系统公司

  所有数据集的80%中, 有95%的信息量都可以用清晰的图表示         ——William S. Cleveland, 贝尔实验室

6.3  调试
  在我所有的程序错误中, 80%是语法错误; 剩下的20%里, 80%是简单的逻辑错误; 在剩下的4%里, 80%是指针错误; 只有余下的0.8%才是困难的问题        ——Marc Donner, IBM沃森研究中心

  在系统测试阶段找出并修正错误, 要比开发者自己完成这一工作多付出2倍的努力; 而当系统已经交付使用之后找出并修正一个错误, 要比系统测试阶段多付出9倍的努力; 因此, 请坚持让开发者进行单元测试         ——Larry Bernstein, 贝尔通信研究院

  不要站着调试程序; 那会使得你的耐心减半, 你需要的是全神贯注         ——Dave Storer, 艾奥瓦州锡达拉皮兹

  别在注释里陷得太深--注释很可能会误导你的, 你要调试的只是代码         ——Dave Storer,艾奥瓦州锡达拉皮兹

  测试只能证明程序有错误, 而不能证明程序没有错误         ——Edsger W. Dijkstra, 得克萨斯大学

  新系统的每一个新用户都可能发现一类新的错误         ——Brian Kernighan, 贝尔实验室

  东西没坏, 就别乱修         ——罗纳德•里根,加州圣巴巴拉

  【维护者箴言】如果我们没能力修好它, 我们就会告诉你它根本就没坏         ——Walt Wei, 美国陆军中校

  修正程序错误的第一步是要先重现这个错误         ——Tom Duff, 贝尔实验室

6.4  性能
  【程序优化第一法则】不要优化
  【程序优化第二法则—仅对专家适用】还是不要优化        
            ——Michael Jackson, Michael Jackson系统公司

  对于那些快速算法, 我们总是可以拿一些速度差不多但是更容易理解的算法来替代它们     ——Douglas W. Jones, 艾奥瓦大学

  在一些机器上, 间接寻址比基址寻址要慢, 所以请把结构体或记录中最常用的成员放在最前面         ——Mike Morton, 马萨诸塞州波士顿

  在一个非I/O密集型的程序中, 超过一半的运行时间是花在不足4%的代码上的        ——Don Knuth,斯坦福大学

  在优化一个程序之前, 请先用性能监视工具找到程序的"热点"         ——Mike Morton, 马萨诸塞州波士顿

  【代码规模守恒定律】当你为了加速, 把一页代码变成几条简单的指令时, 请不要忘了增加注释, 以使源码的行数保持为一个常量         ——Mike Morton,马萨诸塞州波士顿

  如果程序员自己模拟实现一个构造比编译器本身实现那个构造还要快, 那编译器的作者也太失败了         ——Guy L. Steele, Jr., Tartan实验室

  要加速一个I/O密集型的程序, 请首先考虑所有的I/O; 消除那些不必要的或冗余的I/O, 并使余下的部分尽可能地快;         ——David Martin,宾夕法尼亚州诺里斯敦

  最快的I/O就是不I/O         ——Nils-Peter Nelson,贝尔实验室

  那些最便宜, 最快而且可靠性最高的计算机组件压根儿就不存在         ——Gordon Bell,Encore计算机公司

  大多数的汇编语言都有循环操作, 用一条机器指令进行一次比较并分支; 尽管这条指令是为循环设计的, 但在做普通的比较时往往也能派上用场, 而且很有效         ——Guy L. Steele, Jr.,Tartan实验室

  【编译器作者箴言——优化步骤】把一个本来就错了的程序变得更糟绝不是你的错         ——Bill McKeeman, 王安公司

  电每纳秒传播一英尺         ——Grace Murray Hopper, 美国海军准将

  Lisp程序员知道所有东西的值, 却不知道那些东西的计算成本         ——Alan Perlis, 耶鲁大学

6.5  文档
  【否定测试】如果一句话反过来就必然不成立, 那就根本没必要把这句话放进文档         ——Bob Martin, AT&T公司

  当你试图解释一条命令, 一个语言特性或是一种硬件的时候, 请首先说明它要解决什么问题         ——David Martin, 宾夕法尼亚州诺里斯敦

  【一页原则】一个{规格说明, 设计, 过程, 测试计划}如果不能在一页8.5英寸×11英寸的纸<译注1 216mm x 279mm的Letter型纸>上写明白, 那么这个东西别人就没办法理解     ——Mark Ardis, 王安公司

  纸上的工作没结束, 整个工作也就还没结束         ——佚名

6.6  软件管理
  系统的结构反映出构建该系统的组织的结构         ——Richard E. Fairley, 王安公司

  别坚持做那些没用的事         ——佚名

  【90—90法则】前90%的代码占用了90%的预定开发时间, 余下的10%代码又花费了90%的预定开发时间<译注2 由于程序员难以事先预见到困难, 所以开发时间经常延长几乎一倍(90%+90%=180%), 很多软件企业据此制定开发计划, 把合理估计出来的开发时间再加倍>         ——Tom Cargill, 贝尔实验室

  只有不到10%的代码用于完成这个程序表面上的目的, 余下的都在处理输入输出, 数据验证, 数据结构维护等家务活         ——Mary Shaw, 卡内基—梅隆大学

  正确的判断来源于经验, 然而经验来源于错误的判断         ——Fred Brooks, 北卡罗来纳大学

  如果有人基本上做出了你想要做的东西, 你就没必要自己写一个新程序; 就算你非写不可, 也请尽可能多地利用现有的代码         ——Richard Hill, 惠普公司(瑞士日内瓦)

  代码能借用就借用         ——Tom Duff, 贝尔实验室

  与客户保持良好的关系可以使生产率加倍         ——Larry Bernstein, 贝尔通信研究院

  把一个现有成熟程序转移到一种新语言或者新平台, 只需要原来开发的十分之一的时间, 人力, 成本         ——Douglas W. Jones, 艾奥瓦大学

  那些用手做就已经很快了的事情, 就不要用计算机去做了         ——Richard Hill, 惠普公司(瑞士日内瓦)

  那些能用计算机迅速解决的问题, 就别用手做了         ——Tom Duff, 贝尔实验室

  我想写的程序不只是程序, 而且是会写程序的程序         ——Dick Sites, DEC公司

  【Brooks原型定律】计划好抛弃一个原型, 这是迟早的事         ——Fred Brooks, 北卡罗来纳大学

  如果开始就打算抛弃一个原型, 那恐怕你得抛弃两个         ——Craig Zerouni, Computer FX公司(英国伦敦)

  原型方法可以将系统开发的工作量减少40%         ——Larry Bernstein. 贝尔通信研究院

  【Thompson望远镜学徒定律】先做一个4英尺镜片的(望远镜), 再做一个6英尺镜片的, 这比直接做6英尺镜片的更省时间         ——Bill McKeeman, 王安公司

  拼命干活无法取代理解         ——H. H. Williams, 加州奥克兰

  做事应该先做最难的部分; 如果最难的部分无法做到, ,那还在简单的部分上浪费时间干嘛? 一旦困难的地方搞定了, 那你就胜利在望了;
  做事应该先做最简单的部分; 你开始所预想的简单部分, 做起来可能是很有难度的; 一旦你把简单的部分都做好了, 你就可以全力攻克最难的部分了;
      ——Al Schapira,贝尔实验室

6.7  其他
  【Sturgeon定律—在科幻小说和计算机科学中同等适用】毫无疑问, 90%的软件都没什么用; 这是因为对任何东西而言, 其中的90%都是没什么用的;         ——Mary Shaw, 卡内斯—梅隆大学

  对计算机撒谎是要受到惩罚的         ——Perry Farrar, 马里兰州

  如果不要求系统可靠, 它可能做任何事情         ——H. H. Williams, 加州奥克兰

  一个人的常量是另一个人的变量         ——Susan Gerhart, Microelectronics and Computer Technology公司

  一个人的数据就是另一个人的程序         ——Guy L. Steele, Jr., Tartan实验室

  【KISS法则】用最简单, 最笨的方法做事          ——佚名

6.8  原理
看到这里, 你一定会接受下面这条不错的箴言:
  别轻信那些看似聪明的法则         ——Joe Condon, 贝尔实验室

6.9  习题
尽管每一条箴言只用了寥寥数语, 但其中大多数是可以很大程度上进行扩写的(e.g. 可以扩写为一篇本科生论文); 下面的问题告诉我们应该如何扩展这些箴言;
  先让程序跑起来, 再考虑怎么让程序跑得快         ——Bruce Whiteside, 伊利诺伊州伍德里奇
用类似的方式扩写其他箴言;
1.) 用更精确的语言重新表述箴言; 上面的实例可以扩写为:
  在确定程序的正确性之前, 请忽略程序的效率;
或是
  如果程序不能工作, 那运行再快也没用; 毕竟, 一个总是给出错误结论的空程序是根本不花时间的;
2) 举一个小而具体的实例支持你的表述; Kernighan和Plauger在"Elements of Programming Style"第7章中列出了从一个程序源码中截出的10行纠结而难以理解的代码; 这段绕人的代码节省了一次比较, 却引入了一个小错误; 通过"浪费"时间进行一次本可以节省的比较, 他们把十行晦涩的代码变成了两行一目了然的代码; 从这一现实教训中, 他们总结出这个道理:
  欲求快, 先求对;
3) 寻找这些箴言用于大型程序设计的"实战故事"
 a) 很高兴这个箴言对于项目实践有所帮助; e.g. 1.2描述的几个例子, 对系统所进行的性能监视指向了程序执行的关键点, 然后可以通过简单调整这些关键点来提高系统性能;
 b)  忽略这些箴言, 可能导致灾难性的结果; 20世纪60年代, Vic Vyssotsky修改一个Fortran编译器源码, 想让一个原本正确的程序更加快速, 却因而引入了一个程序错误; 两年过去, 这个程序错误一直没有被发现, 因为在100 000次编译中连一次也没有调用这个程序; Vyssotsky花在这次不成熟的优化上面的时间比仅仅浪费时间更加糟糕, 因为他使一个原本好好的程序出错了;(不过, 故事教育了Vyssotsky和贝尔实验室一代代程序员)
4) 请评价这些箴言; 哪些是"不变的真理", 
哪些在某些情况下会产生误导?  有一次我曾对Tartan实验室的Bill Wulf说"如果程序不能工作, 运行得再快也没有用"; 他举了一个我们都在用的文档格式化程序的例子; 尽管这个程序比其前一版本明显快很多, 但在有些时候会慢得难以忍受, 比如编译一本书要花上好几个小时; 
Wulf用下面这个论据赢得了这场论战" 正如其他所有大型系统一样, 这一程序有10个记录在案的轻微程序错误, 而下个月它又将会有10个新的小错误被我们发现; 如果给你机会进行选择, 是要解决现在已知的10个小错误, 还是让程序快10倍呢?"
-- <编程珠玑续>
---YCR---



你可能感兴趣的:(Proverbs)