《卓有成效的程序员》本书就是讲述如何在开发软件的过程中变得更加高效。本章讲述哲学家是怎么评说代码的,本节为大家介绍奥卡姆剃刀原理。
奥卡姆剃刀原理
奥卡姆 的威廉爵士是一个厌恶华美装饰以及复杂解释的修士。他对哲学和科学的贡献是奥卡姆剃刀原理:如果对于一个现象有好几种解释,那么最简单的解释往往是最正确的。显然,这跟我们讨论的事物本质和附属性质理论紧密关联。这个原理对于软件的影响度也是出乎我们意料的。
作为软件工业中的一员,过去十年我们一直在进行着某项实验。这个实验始于上世纪90年代中期,主要是由于开发人员发现其开发进度远远跟不上软件需求的增长而引发的(其实在那时这已经不是一个新问题,这个问题自商业软件的想法出现之后就一直存在)。实验的目的是:创造一些工具和环境来提高那些普通开发人员的生产率,即使一些人比如Fred Brooks(去看他的《人月神话》)已经告诉我们软件开发中的一些混乱事实。此实验试图验证:我们是否可以创造一种能限制程序员破坏力的语言而使人摆脱麻烦;我们是否可以无需支付荒唐的大量金钱给那些令人生厌的软件技工(即使在那时候你可能还为找不到足够的软件技工而发愁),而同样生产出软件呢?这些思考让我们创造出了如dBase, PowerBuilder, Clipper和Access这样的工具,并促成了工具和语言相结合的4GL(第四代语言)的崛起,比如FoxPro和Access。
但问题是,即使有这样的工具和环境你也不能完成所有的工作。我同事Terry Dietzler为Access创建了一个叫做"80-10-10"的准则(而我喜欢把它称之为Dietzler定律)。这个定律说的是:80%的客户需求可以很快完成;下一个10%需要花很大的努力才能完成;而最后的10%却几乎是不可能完成的,因为你不能把所有的工具和框架都"招致麾下"。而用户却希望能满足一切需求,所以作为通用目的语言的4GL(Visual BASIC、Java、Delphi以及C#)应运而生。Java和C#的出现主要是由于C++的复杂性和易错性,语言开发者们为了让一般程序员摆脱这些麻烦而在其内建了一些相当严格的限制。在此之后"80-10-10准则"才发生了改变,无法完成的工作已经微乎其微。这些语言都是通用目的语言,只要付出足够的努力,大多数工作都可以完成。但Java虽然比较易用却常常需要大量编码,所以框架出现了,Aspects出现了,大量其它框架蜂拥而至。
下面有一个例子。这段Java代码是从一个广泛使用的开源框架中提取出来的,试着找出它的用途吧(关于它的名字我只会提示你一点点):
public static boolean xxXxxxx(String str) {int strLen;if (str == null || (strLen = str.length()) == 0) {return true;}for (int i = 0; i < strLen; i++) {if ((Character.isWhitespace(str.charAt(i)) == false)) {return false;}}return true;}
花了多少时间?这实际上是一个从Jakarta Commons框架(它提供了一些或许本该内置于Java的帮助类和方法)中提取出来的isBlank方法。一个字符串是否为"空白"由两个条件决定:这个字符串是空字符串,或者它只由空格组成。这段代码的计算公式非常复杂,因为要考虑参数是null的情况,而且还要迭代所有的字符。当然,你还要把字符包装成Character类型以确定它是否空白字符(空格、制表符、换行符等)。总之,太麻烦了!
下面是用Ruby实现的版本:
class Stringdef blank?empty? || strip.empty?endend
这个定义跟之前的那个非常相近。在Ruby里,你可以把String类打开并且加入一些新方法。这个blank?方法(Ruby里返回布尔值的方法通常用问号结尾)会检查字符串是否为空,或者在去除所有空格之后是否为空。在Ruby里方法的最后一行就是返回值,所以你可以忽略可选的return关键字。
这段代码在一些预想不到的情况下同样工作。看看这段代码的单元测试吧:
class BlankTest < Test::Unit::TestCasedef test_blankassert "".blank?assert " ".blank?assert nil.to_s.blank? assert ! "x".blank?endend
1. 在Ruby里,nil是NilClass类的一个对象,就是说它也有to_s方法(等价于Java和C#中的toString方法)。
其实我讲这些的主要意旨是:一些在"企业级开发"中非常流行的主流静态类型语言有很多附属复杂性。Java中的基本数据类型就是一个语言附属复杂性的绝佳例子。当Java还是新语言的时候它们确实非常有用,但如今它们只是让代码更加难以看懂而已。自动装箱 能起到一些帮助,但是它会引起其它一些异常问题。看看下面这段代码吧,肯定会让你挠头:
public void test_Compiler_is_sane_with_lists() {ArrayList<String> list = new ArrayList<String>();list.add("one");list.add("two");list.add("three");list.remove(0);assertEquals(2, list.size());}
这个测试通过了。再看看下面这个版本,它们之间的区别只有一个单词(ArrayList被换成了Collection):
public void test_Compiler_is_broken_with_collections() {Collection<String> list = new ArrayList<String>();list.add("one");list.add("two");list.add("three");list.remove(0);assertEquals(2, list.size());}
这个测试失败了,抱怨说list的大小还是3。说明了什么问题?它很好地解释了当使用泛型和自动装箱来改装一些复杂的库(比如集合)时会发生什么事情。测试失败的原因在于:Collection接口虽然也有remove方法,但是它删除的是与其参数内容匹配的项,而不是索引指定的项。在这个例子中,Java把整数0自动装箱成一个Integer类的对象,然后在列表中寻找一个内容是0的项,当然最后没有找到,所以也就不删除任何东西。
现代语言非但没有让程序员摆脱麻烦,而且其附属复杂性还迫使他们艰难地寻找复杂的解决方法。这个趋势影响了构建复杂软件的生产率。我们真正想要的,是4GL作为强大的通用目的语言所具有的通用性和灵活性所带来的高生产率。让我们看看用DSL(领域特定语言)构建的框架,目前一个很好的范例是Ruby on Rails。当编写Rails程序时,你不用写太多"纯"Ruby代码(即使写,大部分也只在处理商业逻辑的模型层)。你主要是在Rails的DSL部分编写代码,这意味着编码工作都投入在最有价值的部分,当然也带来了更大的产出。
validates_presence_of :name, :sales_description, :logo_image_urlvalidates_numericality_of :account_balancevalidates_uniqueness_of :namevalidates_format_of :logo_image_url,:with => %r{.(gif|jpg|png)}i,:message => "must be a URL for a GIF, JPG, or PNG image"
只要小小的一段代码,却实现了大量的功能。DSL构建的框架提供了4GL级别的生产率,但它们有一个关键的差异。用4GL(目前一些主流的静态类型语言)做一些非常强大的东西(比如元编程)是极其困难或者说不可能的,而在一个基于一种超级强大语言的DSL里,你不仅可以用少量的代码完成大量的功能,而且可以跳到底层语言去实现任何你想做的东西。
"强大的语言加上特定领域元层次"提供了目前最好的解决方案。生产率来自DSL跟问题域的紧密相连;能力来自于表层之下的强大语言。基于强大语言并且易于表达的DSL将会成为一个新的标准。框架将会用DSL来编写,而不再是语法拘束且无必要规范过多的静态类型语言。请注意这并不代表只能使用动态语言(比如Ruby),只要有合适的语法,静态类型推断语言也非常有可能从这种设计风格中获益。比方说Jaskell[43],特别是基于它的DSL:Neptune[44]。Neptune拥有和Ant一样的基本功能,但它是基于Jaskell的领域特定语言。Neptune展示了在一个熟悉的问题域之内,你可以用Jaskell写出多么易读以及简洁的代码。
提示
Dietzler定律:即使是通用目的编程语言也逃不出"80-10-10准则"的魔咒。
《卓有成效的程序员》节选
《卓有成效的程序员》热门书评
-
上帝的归上帝,程序的归程序
37有用 1无用 Yurii 2009-03-29
http://www.luanxiang.org/blog/archives/593.html程序员,就是整天与机器打交道的那群人。在计算机并不普及的年代,这样的描述毫无疑问;然而,这些年来,得益于计算机成本的不断下降,软件使用门槛的不断降低,如今,昔日昂贵而又神秘不可莫测电脑,已经成了随处可见、人...
-
卓有成效的程序员──咱码农如何实现自我加速
25有用 0无用 masque 2010-07-04
写在BLOG上,原文粘过来。额,有几张图片粘不了,链接在这里:http://www.oeddyo.com/%E3%80%8A%E5%8D%93%E6%9C%89%E6%88%90%E6%95%88%E7%9A%84%E7%A8%8B%E5%BA%8F%E5%91%98%E3%80%8B%E2%94%...
-
人有多大懒,才有多大闲
14有用 1无用 张凯峰 2009-08-15
《卓有成效的程序员》给我的震撼很大,程序员作为特殊的群体,有的人可以这么懒,懒到事情都交给机器去做,而有的人又可以那么勤奋,每天都孜孜不倦得做着重复单调的工作。在看这本书之前,我属于勤奋的人,而看完这本书以后,我要努力变成懒惰的人。不要在去庞大的开始菜单里面一项一项搜索自己的应用程序,也不要在自己的...
-
卓有成效的电脑使用者
8有用 0无用 Urumchi 2009-05-30
说实话,我只重点看了第一部分<机制>,第二部分<实践>倒只是走马观花的扫了一遍.不得不说,前5章很对我的口味.一些有些人可能认为难登大雅之堂,或者说零零碎碎的小技巧第一次(至少对我来说)写在书里.而这些之前大多只是在网上以新工具推荐方式出现,这本书却改变了这点,这些工具/技巧...
-
高效开发的敲门砖
6有用 0无用 dreamhead 2008-10-06
回想一下:* 怎样启动一个程序?* 怎样切换到一个文件上去?曾经的我这样做:* 点开“开始”菜单,在“程序”中,一项项寻找过去……* 在IDE中,找到目录的根,然后一层层目录展开……现在的我这么做的:* 用快捷键调出一个启动程序,比如Launchy,敲入我要启动程序的名字,比如firefox,然后回...
书名: 卓有成效的程序员
作者: [美] Neal Ford
出版社: 机械工业出版社
原作名: The Productive Programmer
副标题: 一本揭示高效程序员的思考模式,一本告诉你如何缩短你与优秀程序员的差距
译者: ThoughtWorks公司
出版年: 2009-3
页数: 216
定价: 45.00元
ISBN: 9787111264064