软件开发是一门手艺活images.china-pub.com/ebook3800001-3805000/3804233/ch16.pdf · 2015....

4
96 16 软件开发是一门手艺活 2003 12 1 日,星期一 开发软件并不像是工厂在制造产品。20 世纪 80 年代,大家惊闻日本在建造 “软件工厂”,这些工厂能通过流水线作业批量生产高质量的软件。而这在当 时的技术水平下是天方夜谭,即使是现在的技术也还达不到。把一群程序员 塞进车间,让他们站成一排,并不能有效地减少 bug 数量。 如果写代码不同于流水线作业,那它更像什么呢?有人提出,软件开发是一 手艺活。当然,这种说法也并不总是成立的,因为不知你怎么想,反正我 觉得那个询问你该如何索引帮助文件的 Windows 对话框,从形状到样式,无 论从哪个角度看,都和人们常说的“工艺品”差远了。 写代码不是工业生产活动,也不总是一门手艺活(但它可以是),它其实更 像是一种设计活动。设计是一个很模糊的概念,其特征在于用较慢的成本增 长换取较快的价值增长。《纽约时报杂志》对 iPod 赞不绝口 ,称赞苹果公司 是世间少有的知道如何用优秀设计来增加价值的公司。 图片由苹果公司提供,详情参见:http://www.apple.com/pr/photos/ipod/03ipod.html —————————— 鲍勃·沃克,“The Guts of a New Machine”,《纽约时报杂志》,2003 11 30 日,第 78 页,第一栏。

Upload: others

Post on 02-Oct-2020

5 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: 软件开发是一门手艺活images.china-pub.com/ebook3800001-3805000/3804233/ch16.pdf · 2015. 4. 14. · 97 软件开发是一门手艺活 有三种: 16 但是,关于设计这个话题我已经讲了很多,现在想谈谈软件开发的工艺品特

96

第一部分

比特和字节:编程实践

16

软件开发是一门手艺活

2003 年 12 月 1 日,星期一

开发软件并不像是工厂在制造产品。20 世纪 80 年代,大家惊闻日本在建造

“软件工厂”,这些工厂能通过流水线作业批量生产高质量的软件。而这在当

时的技术水平下是天方夜谭,即使是现在的技术也还达不到。把一群程序员

塞进车间,让他们站成一排,并不能有效地减少 bug 数量。

如果写代码不同于流水线作业,那它更像什么呢?有人提出,软件开发是一

门手艺活。当然,这种说法也并不总是成立的,因为不知你怎么想,反正我

觉得那个询问你该如何索引帮助文件的 Windows 对话框,从形状到样式,无

论从哪个角度看,都和人们常说的“工艺品”差远了。

写代码不是工业生产活动,也不总是一门手艺活(但它可以是),它其实更

像是一种设计活动。设计是一个很模糊的概念,其特征在于用较慢的成本增

长换取较快的价值增长。《纽约时报杂志》对 iPod 赞不绝口①,称赞苹果公司

是世间少有的知道如何用优秀设计来增加价值的公司。

图片由苹果公司提供,详情参见:http://www.apple.com/pr/photos/ipod/03ipod.html

—————————— ① 鲍勃·沃克,“The Guts of a New Machine”,《纽约时报杂志》,2003 年 11 月 30 日,第

78 页,第一栏。

Page 2: 软件开发是一门手艺活images.china-pub.com/ebook3800001-3805000/3804233/ch16.pdf · 2015. 4. 14. · 97 软件开发是一门手艺活 有三种: 16 但是,关于设计这个话题我已经讲了很多,现在想谈谈软件开发的工艺品特

97

软件开发是一门手艺活

16

但是,关于设计这个话题我已经讲了很多,现在想谈谈软件开发的工艺品特

性,包括它是什么以及如何辨识。

我想和大家分享一段我正在重写的代码,它实现的是 CityDesk 3.0 的文件导

入功能。(插播一条广告:CityDesk 是我的公司发布的一款方便易用的内容

管理产品。)

功能规格说明非常简单。用户通过标准的对话框选择一个文件,然后程序把

该文件复制到 CityDesk 数据库中。

结果这个例子很好地说明了,有的时候“写好最终 1%的代码要耗去 90%的

时间”。程序的第一版设计草案是这样的:

(1) 打开文件;

(2) 把全部内容装进一个庞大的字节数组;

(3) 把字节数组储存为数据表中的一个条目。

这个程序在通常情况下运行得很顺畅。对于一般大小的文件,程序基本上一

眨眼的工夫就跑完了。但是它存在几个小 bug,容我一一列举。

其中一个较大 bug 出现在压力测试中,当时我试着把一个 120MB 的文件拖

入 CityDesk。一般情况下,人们不会在网站上放这么大的文件。这在实际

中几乎不可能出现,但也不是没有可能。程序运行了大概一分钟才结束,

其间没有任何视觉反馈,界面呈现假死状态,点击哪里都没有反应。这明

显不够理想。

从用户界面设计的角度来考虑,我应该在程序进行耗时操作的时候显示某种

进度条,以及一个取消按钮。更理想的情况是让文件在 CityDesk 的后台进行

复制,不影响用户进行其他的操作。要实现这一功能,比较容易想到的方案

有三种:

(1) 只开一个线程,每隔一段时间检查是否有输入事件;

(2) 再开一个线程,仔细地做好线程同步;

(3) 再开一个进程,不需要很仔细地做好进程同步。

我的经验是,方法 1 的效果总是不够理想。当程序正在进行文件复制操作时,

很难保证其他所有代码能安全运行。埃里克·雷蒙德的论述让我相信,多线

程的方案不如多进程的方案①,而且根据我多年的经验,多线程编程增加了

—————————— ① 参阅http://www.faqs.org/docs/artu/ch07s03.html#id2923889。

Page 3: 软件开发是一门手艺活images.china-pub.com/ebook3800001-3805000/3804233/ch16.pdf · 2015. 4. 14. · 97 软件开发是一门手艺活 有三种: 16 但是,关于设计这个话题我已经讲了很多,现在想谈谈软件开发的工艺品特

98

第一部分

比特和字节:编程实践

太多额外的复杂度,会引入不少这种方案所独有的、危险的海森堡 bug①。3

号方案看起来更好,尤其是考虑到我们使用的数据库支持多用户操作,并不

介意多进程的并发访问。所以过了这个感恩节假期,我准备用方案 3 来实现

这个功能。

但是退一步想,我们从最初简单的读取文件、保存到数据库出发,最终采取

了一个复杂得多的方案:开一个子进程,让它读取文件并保存到数据库;子

进程还要有进度条和取消按钮; 并且要建立一种机制,让子进程能在文件保

存完毕时通知父进程,即时显示处理完毕的文件。另外要做的一部分工作是

通过命令行把参数传递到子进程;还要处理窗口焦点的行为,让它符合使用

者的心理预期;以及特殊情况的处理,比如用户在程序正在复制文件的时候

关闭电脑。我猜最后要写的代码量是原来的 10 倍,只是为了优雅地处理大

文件,而这些工作的成果只有大概 1%的用户能看到。

当然了,还有一种程序员会认为,子进程的方案还不如原来的方案。它被“过

度设计”了,增加了太多额外的代码行,这也导致程序更有可能出现错误。

这叫过犹不及。他们会说,这种做法是是典型的 Windows 思维,Windows

在他们眼中并不是一个设计得很高明的操作系统。他们对设计进度条的必要

性嗤之以鼻。因为在 UNIX 下,只要敲击 Ctrl+Z 然后用“ls -l”看看文件体

积有没有增加就知道程序是否还在运行了!

这个故事告诉我们,修复出现概率为 1%的问题,有时候需要花 500%的精力。

这种情形并不是软件开发活动所独有的,我这样说是因为我管理过一些建筑

施工工程。上周,我们的建筑承包商最终完成了对 Fog Creek 新办公楼②的装

修完善工作,包括给正门装上崭新的蓝色丙烯面板,并在门的边缘每隔 20

厘米包上一条铝片。仔细看下面这张照片,你会发现每扇门的四周都有铝条。

在两扇门接触的部分,两条铝片呈竖向对齐排列。在图上可能看得不明显,

但这两条铝片中央的固定螺丝并没有完全对齐,大约相差 2 毫米。木工师傅

事先做了仔细测算,但是在安装铝条的时候,门是放在地上的。等到门挂到

轴上才发现,坏了,螺丝很明显地没有对齐。

—————————— ① 详情参阅http://c2.com/cgi/wiki?HeisenBug。

② 参阅http://joelonsoftware.com/articles/BionicOffice.html。

Page 4: 软件开发是一门手艺活images.china-pub.com/ebook3800001-3805000/3804233/ch16.pdf · 2015. 4. 14. · 97 软件开发是一门手艺活 有三种: 16 但是,关于设计这个话题我已经讲了很多,现在想谈谈软件开发的工艺品特

99

软件开发是一门手艺活

16

这种情况绝非个例,我们的办公室里有很多螺丝不是完全对齐的。问题在于

打完孔后再矫正位置的成本是很高的。正确的位置只偏那么几毫米,因此不

好重新打孔。如果追求完美的话,只能换掉整扇门,太不值了。这个例子再

一次阐释了有时候修复出现概率为 1%的缺陷需要 500%的努力,也同样揭示

了为什么这个世界上有那么多工艺品的完美程度停留在 99%,而不是 100%。

(我们的建筑师总是喋喋不休,声称亚利桑那州的某些豪宅中,每颗螺丝都

是完全对齐的。)

大部分人都认为,软件具有与之类似的特性,让它带有工艺品的气息。当一

群真正具有工匠情怀的人们构建一个软件产品时,他们会想办法对齐所有的

螺丝。也就是说对于一些极其罕见的情况,软件也能处理得很漂亮。但要做

到这一点,开发者势必将大部分的精力投入到对各种罕见情况的正确处理

上,而不是集中精力让主要的业务逻辑正常运转。这也就意味着开发者要用

500%的精力去处理好出现概率为 1%的情况。

要达到一定的工艺水平,需要付出巨额的开发成本。软件行业里唯一值得付

出巨额的开发成本的情形,是开发面向海量用户的软件。很遗憾,譬如保险

公司的内部人力资源系统,就永远不会达到这种完美的工艺水平,因为没有

足够的用户数量来摊薄成本。然而对于开发零售软件的公司,这种不断追求

并完善软件品质的做法正是用户想看到的,因为那将会为公司提供长期的竞

争优势,所以请广大用户耐心期待,我们会慢慢来,因为慢工才能出细活。