关键点
- 相比起取得成功而言,软件工程主要的目标是避免失败
- 软件项目都是独一无二的,应用套路式的方法会很危险,开发流程必须为项目进行调整
- 多数情况下短迭代没什么问题,但有时它会严重影响生产力
- 测试是至关重要的,但是我们必须搞清楚怎样做测试以及测试些什么
- 任何来自高层、教练、书本、方法论的规则都应接受全面考察,否则就不能应用到实际当中
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
感谢薛命灯对本文的审校。
给InfoQ 中文站投稿或者参与内容翻译工作,请邮件至 editors@cn.infoq.com 。也欢迎大家通过新浪微博( @InfoQ , @丁晓昀),微信(微信号: InfoQChina )关注我们。
评论