为什么我们应该像盖房子那样写软件?
莱斯利.兰伯特是一个计算机科学家,擅长分布式系统、时态逻辑和并行算法。他是工程和国家科学院国家科学院成员。兰伯特在麻省理工学院攻读数学本科,在布兰迪斯大学赢得了他的硕士和博士学位。他为微软研究所工作。
在砌上一块砖或钉下一支钉子之前,建筑设计师会制定好详细的计划。程序员或者软件工程师却不会。这难道就是房子很少塌倒而程序经常会崩溃的原因?
蓝图保证建筑设计师的设计的建筑按规划建成。“建成”不仅仅意味不会塌倒,还意味达到业主要求的功能。建筑设计师和他们的客户在着手建造之前,通过蓝图来沟通,以理解他们将要建造成的建筑的样子。
但是很少有程序员在编码之前,会勾画哪怕是简单的草图来说明他们的程序将是会怎么样子。
大多数程序员认为做任何不产生代码的事情都是浪费时间。思考并不会产生代码,没有想好就开始编码,那只是产生糟糕代码的菜谱。我们应该理解这些代码到底要实现哪些功能。理解需要思考,思考很难。借用一句漫画家迪克.圭尼登的话:
写作是一种让你知道你想法有多伤感的本能方法
蓝图让我们想清楚我们打算要建造的建筑。在写下一段代码之前,我们应该先写蓝图。软件的蓝图称为技术说明书。
已经有太多的借口说撰写技术说明书只是浪费时间。比如:技术说明书毫无用处,我们不能通过它来产生代码。这就好像说建筑设计师应该不要画蓝图,因为他们最终还是需要承包商去建造房子。另外一个反对撰写技术说明书的争论也能够用蓝图的例子来反驳。
还有一些程序员争辩说,把蓝图和技术说明书作比较,是无用功,毕竟程序不是建筑物。他们认为推倒一堵墙要比改变代码难多了,所以程序的蓝图不是必须的。
错了,改变代码也很难,特别是如果我们不想导入缺陷的话。
我最近为要加入一个小小的功能而修改一些不是我写的代码。要完成它需要理解一个接口。我花一整天使用调试器来找出该接口到底是干什么的–有时候需要花5分钟读读技术说明书就搞定的事情。为了避免导入缺陷,我不得不弄清楚我每次修改之后的结果。因为没有技术说明书,这个事情变得更加困难。我必须要阅读上千行代码,我花了数天来琢磨怎样才能修改尽可能少的代码。最后,我花了一周,新增或修改180行代码。这可仅仅是这个程序的一个很小的变更啊。
修改代码只是一项大任务中小小的一块工作,大多数代码已经是我十几年之前写的了。尽管我几乎不记得这些代码是干嘛的,要修改它还是挺容易的。通过阅读我写的技术说明书,很容易就找到我要修改的地方。尽管这些修改工作量不少,而且还影响到其它代码,我还是很快搞定它。
我所说的技术说明书到底是什么东东?它经常被认为需要使用非常正式的技术语言。但是正式的技术说明书只是这光谱的一端,如果我们仅仅是盖个工具棚的话,我们不需要画摩天大楼所要求的那种蓝图。对于大多数软件来说,我们不需要正式的技术说明书。然而,哪怕是小小的程序,没有技术说明书都很傻。就好像要盖一个工具棚,最初没有画一个哪怕是简单的计划那样。
这些日子,我写的程序往往只是像小房子而不是摩天大楼这样的级别。我常常写下每个算法的实现方法,大多数算法很简单,可能需要一两句话就能够写清楚。有时写清楚一个算法到底是怎么起作用的需要好好构思,并可能花上一段话,或者几页纸来写清楚。我有一个简单的规则:技术说明书应该写清楚该算法的使用者需要知道的每一件事情。在代码写好,编译好之后,估计没有人会再去阅读它了。
我往往能够指出一段代码是怎么工作的,一些代码很直白,但另外一些并不是这样,它要求很复杂的算法。让一个算法运作起来,需要精心构思,这就要求技术说明书。
我写的大多数技术说明书都是非正式的。偶尔一段代码很精妙,也很关键,这就需要正式地写。要保证准确性,甚至要使用编写工具仔细检查。这种正式的事情过去十几年只是有那么十几次罢了。
对于复杂系统的设计师,一份正式的技术说明书是必须的,就好像摩天大楼的蓝图一样。但很少工程师会作撰写技术说明书,因为他们根本没有时间去学会做好这个事情,而且学校里也不教。一些学校会讲授技术说明书用语,但是很少教怎么在实际工作中应用。如果你连一个工具棚的蓝图都不会画的话,怎么能会画摩天大楼的蓝图?
要学会撰写技术说明书,需要实践。没有简单的规则来保证你写出一份好的技术说明书。一个应该避免的事情就是不要用代码。通过代码去理解代码是一个糟糕事情。建筑设计师不会用砖来制作蓝图。
理解一件复杂的事情的关键是抽象,这意味着比代码上一个层次。简单和准确的最好语言是数学,初等数学就教过这些了:集合,函数和简单的逻辑。不过,大多数正式的技术说明书使用的语言不在初等数学班里,比如:类型。然而,越是远离简单数学的语言,越会妨碍我们去理解一个复杂的程序或系统。
无论是为复杂系统使用正式的技术说明书或者简单代码的非正式的技术说明书。撰写技术说明书会提升我们的代码质量。它有助于我们理解我们正在做的事情,并减少出错。当然,即使撰写技术说明书也不保证你的程序就不会崩溃。我们依然要使用已有的其它方法和工具来减少代码缺陷。
思考不会保证我们不会犯错误。但是不思考那肯定会犯错误。