作者 王强
,译者关键点
- 相比起取得成功而言,软件工程主要的目标是避免失败
- 软件项目都是独一无二的,应用套路式的方法会很危险,开发流程必须为项目进行调整
- 多数情况下短迭代没什么问题,但有时它会严重影响生产力
- 测试是至关重要的,但是我们必须搞清楚怎样做测试以及测试些什么
- 任何来自高层、教练、书本、方法论的规则都应接受全面考察,否则就不能应用到实际当中
Darius Blasband是The Rise and Fall of Software Recipes的作者。在书中他挑战了软件工程的传统观念,抨击了行业中流行的开发套路(recipe)与标准化方法,并对现状表达了不满。他自称代码狂人(codeaholic),认为开发者应该仔细推敲特定的上下文对象(specific context),并尽可能使用领域特定语言。
InfoQ:请问你为何撰写本书?要指出什么问题?
Darius Blasband:我经常花费很多时间在路上颠簸,用几小时甚至几天时间坐火车飞机,住宾馆,穿越多个时区进行长途旅行。结果跑了那么远经常只是为了开个一小时不到的商务会议,简直是浪费光阴。然后我就开始在路上写笔记,积少成多,最后就有了这本书。
但这并不只是用来打发无聊时间的产物。
我想在书中指出的问题是软件工程中缺乏历史视角的现象。人们把新技术、新方法或新的编程语言当成万能的魔法石,却忽视了过去四十年间有数以百计类似的出色发明曾涌现和消亡。
就拿敏捷运动来说吧。敏捷被认为是软件领域所有相关问题的终极解决方案。但如果它自夸的这套说辞真的可信,21世纪之前就没人写过任何优秀的软件应用了。
显然(而且是幸好)事实并非如此。
稍稍回顾下历史就能发现,敏捷所推崇的许多方法已经存在许久了。抛开时髦的术语和狂热的追随者不谈,敏捷对现代软件开发行业几乎就没什么贡献。
另一方面,缺乏大局观的一个重要表现是,大多数软件项目首要考虑的是开发周期,人们会用尽最先进的技术和技能来控制项目耗时。
很多任务关键型软件系统需要运转二十年甚至更久。它们必须跨越多个技术变革周期,目睹曾经强大的供应商逐渐消亡,具备来之不易的专业技能的关键工程师也会成批退休,诸如此类。
如果从大局考虑,对于重要的软件系统而言,为控制开发周期而忽视系统长期运行的需求(虽然后者没那么吸引人)显然是对资源的极大错配。
InfoQ:为什么你会是写这样一本书的最佳人选?
Darius Blaband:我真的是最佳人选吗?我看不见得。
但如果非要我回答这个问题,我要说:
- 因为别人都不写
- 因为在工业软件开发行业有30年以上经验的人大都已经离开纯技术领域很久了。而技术细节比一般的管理理论所认为的重要得多
- 因为我不搭理任何人的问题(除了我太太,我们的交流自在不言中),所以我可以质疑现状,抨击现在的陈词滥调,而不用担心这会影响我的私人生活
- 因为我足够幸运,多年来参与过诸多差异明显的项目。这些项目有大有小,有为小商店开发的,也有为跨国公司开发的,有的用于普通的行政用途,也有独一无二的尖端项目
InfoQ:什么是“软件套路”,它们的本质问题是什么?
Darius Blasband:我所说的套路指的是约束开发者开发方式的东西,包括所有的方法论、所有的软件开发流程定义、所有分解任务的优先规则等。这些套路与具体的应用、技术环境和性能约束等因素都无关。
瀑布流方法论就是套路。
敏捷运动声称它推崇的东西并不算方法论,但他们还是坚持使用短迭代、持续测试这些东西。这是非常规范化的,在我眼中这当然也是一种套路。
简单来说,我不喜欢软件套路。
因为软件有很多形式,环境约束可以大相径庭,项目规模也是如此。软件的关键程度、与外界的交流界面、对时间和预算的敏感性等等,这些因素都会千差万别。
简而言之,各个软件项目之间有着明显的不同。用一套预先写好的规则应用到所有场景中就会忽略这些差异,并假设这些区别相比项目之间的共通点是无关紧要的。但这种假设未经充分的实践验证是不能随意下定论的。
不夸张地说,几乎没人正式对上述假设做过验证,就算有过,结果也是不确定的。
InfoQ:你的结论是否意味着团队不应该遵循任何流程或方法?那么他们应该怎么做呢?
Darius Blasband:关于软件开发行业,我并不倡导无约束的状态(虽说这种状态不像很多人想象的那么可怕)。我们可以规划项目,也可以定义任务。简单说,很多情况下我们可以预先制定一套流程。
但这套流程必须为项目本身进行适配,不应该照抄一体通用的规则册子:
- 多数情况下短迭代是可行的,但有时它会变得效率非常低下。每周堆一截梯子看起来也是在取得进展,但如果目标是登上月球时就是另一回事了。
- 测试是至关重要的,但我们必须知道怎样去测试以及测试些什么:
组件,系统,性能,功能,稳定性,鲁棒性,等等;
有些人是为测试而测试,测不到正确的点上,结果产生不了什么实际价值。总之,我们可以为当下的项目制定一套对应的流程,流程中所有的决策都应该根据现实情况进行合理的评估。不要武断地做任何事情。任何来自高层、教练、书本、方法论的规则都应接受全面考察,否则就不能应用到实际当中。
在解决任何问题时,如果给出方案的理由最终归结到“因为敏捷宣言是这么说的”,你就该知道麻烦大了。
InfoQ:代码狂人是什么意思?它和code hacker、fix hacker有什么区别?
Darius Blasband:hacker专注于尽快找到解决方案,他们了解书里书外的所有技巧,知道怎么走捷径来实现目标。hacker几乎只看重执行力。“它奏效了”就是他们的格言。
代码狂人的动机是完全不同的。
他们意识到代码是一次写就,多次读取的。他们不会为了尽快赶工而牺牲代码的质量。在代码狂人眼中,一份软件的真正价值体现在它的可维护性、可读性与易于修改的程度上。
由此,代码需要优雅,需要有描述清晰的用途,需要遵循规范。因为这些会让代码更易预测,更容易管理,也更方便理解。
让软件正常运行,配备所需的功能并实现足够的性能的确重要,但这并不是终结,而只是漫长道路的起步。真正的功夫在于让代码可管理、可读、优雅并井井有条,这才是最难做到的部分。
InfoQ:你声称“相比起取得成功而言,软件工程主要的目标是避免失败”——为什么这么说,它对我们开发软件有什么启迪?
Darius Blasband:关于“为什么”这一点,这个观点来源于行业本身的复杂性。当设备有如此之多的活动组件时,往往就会出现组件损坏的情况。
对于整个行业来说,我们强调这一点有多种含义:
- 我们使用冗余来减轻故障的影响
- 我们投入大量精力进行测试,说明我们对开发团队的交付质量缺乏信心,而这种怀疑往往是理直气壮的
- 如果可以,我们会简化解决方案,缩小适用范围,进而有效减少活动组件的数量
- 我们使用分批交付策略,这样在最坏情况下,就算项目跳票超支,也起码能展示并交付一些有价值的成果
- 听起来不可思议,我们甚至要做到教育用户必须要容忍某些故障的程度(如果一家车行提醒你他卖的车一年总会有几次打不着火,但就算打不着也没关系,你可以下车,锁门,然后再开门进车试着再发动一次,如此往复。他还说这种事儿一年出个两回不是什么大事儿,用不着抱怨——你会买他的车吗?)
InfoQ:你推崇领域特定语言(DSL),那么DSL有什么用,实践中面临哪些机遇和挑战?
Darius Blasband:公平来讲,对不同的人而言,DSL概念可以呈现出非常多的形态。很多人关注它到底是什么(是不是已有语言的扩展,或者它的不同概念之间的交集是怎样的)。
我个人对DSL的理解更看重它是怎样应用的:DSL是由一小组人管理或定义的语言,小组可以根据自身的特定需求来调整他们的DSL。
某种程度上,受众的规模是一个主观因素:小组要成为DSL的受众,最小的规模是多大?
另一方面,可变性是更主观的衡量指标。
DSL策略可以让DSL用难以度量的参数进行调整,由此使项目在范式的复杂程度、DSL的预定义能力和使用DSL撰写的用户代码中的组件之间取得平衡。
它是分治的终极形式。
我的意思是,我对DSL非常着迷。我擅长语言和编译器。对我来说,写DSL是最轻松的事情。
即便有的工程师缺乏丰富的编程语言技能,但严谨的DSL项目对语言基础架构知识(词义、语法和语义分析)的要求相比其他任务却小得多:这些任务包括将它与其他基础设施对接,提供基本范式区块,支持用户,等等。
问题在于,忽视语言的基础架构,转而扩展一种已有的语言,结果将DSL仅仅用作一个库,这种设计思路是很低级的。
如上所述,仅用DSL操作句法就无法让DSL变得更具弹性,更有表现力了。
重要的不仅是句法。DSL也是一种能以较低成本较容易地轻松获得成果的途径。
InfoQ:你在书中提到了一些debug的技巧,那么有哪些关键点呢?
Darius Blasband:如果只把debug看作是从系统中挑出bug的流程,那么它的性价比就很低了。聪明人会在debug阶段细心地研究为什么实际行为与期望会出现差异,这种差异是怎样产生的。
debug不仅消耗很多资源,还会让人抓狂。我们经常会奇怪这些bug当初是怎么钻进系统里去的。
不过其实我们没必要纠结。debug并不仅是一个流程,它也可以是一种可交付的内容。它能提升软件的价值,软件从debug中得到的可以不仅是修正缺陷。
提升价值的最简单方法是引入一种规则,在给出bug的解决方案之前先在测试用例中重现它们。这样一来,bug一旦再出现就能被测试套件侦测到。除了去除bug以外,期望的行为被可执行的测试用例正式记录下来,这也是对软件的改进。
不过软件debug并没有通用的最优手段。每一位开发者都有自己偏好的debug工具或流程。
有些人会对复杂的调试器无所不用其极。
我个人更像是个科技恐惧者,也比较懒,不喜欢研究越来越复杂的debug工具。我就是烦它们。
我用的是简单得多的技巧。倒不至于原始到把代码打出来慢慢研究,不过也够简单的了。
在软件出现bug的地方,我会添加断言(几乎所有现代编程语言都支持)来检查代表系统应有行为的情况。通过增加越来越多的断言,我会逐渐缩小bug的出现范围(就是进入之前一切正常,离开时就出错了的部分),最后我就能锁定源头并解决bug。
这套方法的美妙之处在于代码中的断言会保留下来。
有了这些断言,相同或类似问题再现时可以被迅速侦测,而且它们会正式成为系统的一项资产,包含了开发者的知识,并为未来的代码维护人员留下了参考。
这些断言远比简单的注释可靠,长久以来代码升级时没人会去维护注释内容。断言会渐渐偏离自己实际的行为,它们可执行,也可用来测试。
InfoQ:对本书的读者你有什么话想说吗?用一句话总结一下。
Darius Blasband:以史为鉴。
硬件在不断升级:存储、带宽和计算资源如今丰富得像免费一样,新的编程语言也不断涌现。但最重要的原则几乎没有改变:我们,作为软件开发者,并不比我们的前辈们聪明得多(或愚蠢得多)。我们与古人一样充满智慧,却也没比他们进化到哪儿去。
整个行业用了超过三十年时间寻找万能的魔法石,寻找一种让开发流程井井有条的手段,一种方法论,一种任务的分解规范以使开发者可靠而确切地产出所需的成果。总而言之,行业期待的就是一种软件开发套路。
一次又一次,人们都失败了。
经过三十年时间,我们该意识到这种努力永远不会成功了。因为它被一种未曾进化的元素卡住了:就是我们人类。
在我看来,这种企图就像是寻找独角兽。人们陷入一种谬论,觉得没人见过独角兽不代表它不存在。
但是有些东西真的是不存在的。
接受现实吧。
关于作者
Darius Blasband有法语布鲁塞尔自由大学(比利时ULB)的硕士和PhD学位。他专注于老旧代码的翻新,研究编译器对老旧语言的兼容手段。Darius是Raincode的创始人兼CEO,也是该公司的主设计师和核心技术制定者。他是学术和工业圈中著名的演说家。
查看英文原文:Q&A on The Rise and Fall of Software Recipes
转自 http://www.infoq.com/cn/articles/book-review-rise-software-recipes