现代软件工程:如何高效构建软件

978-7-115-59958-2
作者: [美] 戴维·法利(David Farley)
译者: 赵睿茹炳晟
编辑: 郭媛

图书目录:

详情

本书探讨了软件工程的真正含义,汇集了一些重要的软件开发基本原则,将它们紧密结合成一个一致的模型,旨在帮助读者有效、快速地构建软件。全书共4个部分:第1部分探讨软件工程的真正含义,以及如何将工程的原则和原理应用到软件开发中;第2部分讲述运用科学思想优化软件开发过程的方法,包括迭代式、增量式工作,获得并利用快速、高质量的反馈,采用实验性和经验主义的科学方法;第3部分介绍管理软件复杂性的方法,深入探讨模块化、内聚力、关注点分离、信息隐藏和抽象、管理耦合等原则;第4部分介绍支持软件工程的工具,以及一些贯穿本书的软件开发理念,包括可测试性、可部署性、速度、控制变量、持续交付等。

图书摘要

版权信息

书名:现代软件工程:如何高效构建软件

ISBN:978-7-115-59958-2

本书由人民邮电出版社发行数字版。版权所有,侵权必究。

您购买的人民邮电出版社电子书仅供您个人使用,未经授权,不得以任何方式复制和传播本书内容。

我们愿意相信读者具有这样的良知和觉悟,与我们共同保护知识产权。

如果购买者有侵权行为,我们可能对该用户实施包括但不限于关闭该帐号等维权措施,并可能追究法律责任。

著    [美] 戴维·法利(David Farley)

译    赵 睿  茹炳晟

责任编辑 郭 媛

人民邮电出版社出版发行  北京市丰台区成寿寺路11号

邮编 100164  电子邮件 315@ptpress.com.cn

网址 http://www.ptpress.com.cn

读者服务热线:(010)81055410

反盗版热线:(010)81055315

读者服务:

微信扫码关注【异步社区】微信公众号,回复“e59958”获取本书配套资源以及异步社区15天VIP会员卡,近千本电子书免费畅读。

版权声明

Authorized translation from the English language edition, entitled Modern Software Engineering: Doing What Works to Build Better Software Faster 1e by David Farley, published by Pearson Education, Inc, publishing as Addison-Wesley Professional, Copyright © 2022.

All rights reserved. No part of this book may be reproduced or transmitted in any form or by any means, electronic or mechanical, including photocopying, recording or by any information storage retrieval system, without permission from Pearson Education, Inc.

CHINESE SIMPLIFIED language edition published by POSTS AND TELECOM PRESS CO., LTD. Copyright ©2023.

本书中文简体字版由Pearson Education(培生教育出版集团)授权人民邮电出版社独家出版。未经出版者书面许可,任何人或机构不得以任何方式复制或抄袭本书内容。

本书封面贴有Pearson Education激光防伪标签,无标签者不得销售。

版权所有,侵权必究。

内容提要

本书探讨了软件工程的真正含义,汇集了一些重要的软件开发基本原则,将它们紧密结合成一个一致的模型,旨在帮助读者有效、快速地构建软件。全书共4个部分:第1部分探讨软件工程的真正含义,以及如何将工程的原则和原理应用到软件开发中;第2部分讲述运用科学思想优化软件开发过程的方法,包括迭代式、增量式工作,获得并利用快速、高质量的反馈,采用实验性和经验主义的科学方法;第3部分介绍管理软件复杂性的方法,深入探讨模块化、内聚力、关注点分离、信息隐藏和抽象、管理耦合等原则;第4部分介绍支持软件工程的工具,以及一些贯穿本书的软件开发理念,包括可测试性、可部署性、速度、控制变量、持续交付等。

本书适合对软件工程和软件开发团队管理感兴趣的人士阅读,也可作为软件工程相关课程的参考教材。

关于作者

戴维·法利(David Farley)是持续交付的先驱、思想领袖,也是持续交付、DevOps、测试驱动开发和软件开发领域的专家。

从现代计算的早期开始,戴维曾担任过程序员、软件工程师、系统架构师和成功团队的领导者,他掌握了计算机和软件开发的基本原理,并形成了开创性的方法,改变了开发人员和团队的工作方式。他挑战了传统的思维方式,带领团队开发了世界级的软件。

戴维是获得Jolt大奖的《持续交付:发布可靠软件的系统方法》一书的作者之一,是一位受欢迎的会议演讲者,并在YouTube上运营着广受欢迎的“持续交付”频道,该频道的主题是软件工程。他建立了世界上速度最快的金融交易所之一,是行为驱动开发的先驱,是《反应式宣言》(The Reactive Manifesto)的作者之一,并凭借LMAX Disruptor获得了杜克开源软件奖。

戴维热衷于通过咨询、YouTube频道和培训课程分享他的专业知识,帮助世界各地的开发团队改进软件的设计,提高软件的质量和可靠性。

对本书的赞誉

我们处在信息化时代中,软件技术正在影响着我们现在的生活,对未来也会产生深远的影响,从人工智能、商业航天到我们的手机、计算机、电动汽车、智能家电等。信息化时代的开启,软件工程在其中起着不可估量的作用。软件工程又是一门理论性和实践性都很强的学科,它采用工程化的概念、理论、技术和方法来指导开发与维护计算机软件。《现代软件工程:如何高效构建软件》通过探讨软件工程的真正含义、利用科学思想优化开发过程、管理软件复杂性,汇集了软件开发中的一些基本原则,能够帮助读者快速、有效地构建现代软件。这本书可作为高等院校、继续教育院校“软件工程”课程的教材和教学参考书,也可供有一定实践经验的软件开发人员和管理人员参考。

——杨磊,国家卫星气象中心风云四号气象卫星地面系统副总设计师

近年来,随着云计算、人工智能、大数据、区块链等新一代信息技术的发展,传统软件形态发生变化,新型智能化应用和产品呈现爆发式增长。软件架构向分布式、松耦合和工程化等方向演进,快速变化的业务需求亟需高效的软件构建来支撑。

这本书从纠正人们对软件工程的传统认知误区出发,阐述生产力和创造力在软件工程中缺一不可的辩证关系,并跳出特定的工具或技术,抽象、提炼、连贯为一套具有普适性、基础性的现代软件工程思想和范式,进而以实用有效的方法为重点,讲解科学原理、工程技术如何应用于软件开发。

书中提及的现代软件工程“道法术器”,广泛适用于各类软件开发团队,无论是初创公司还是大型企业,对于改进复杂软件系统的工程实践十分有帮助,促进软件组织更加可靠、高效、高质量地构建软件,交付业务价值,激发创新活力。

——陈屹力,中国信息通信研究院云计算与大数据研究所副总工程师

经历了上百个软件项目后,在“如何高效地构建软件、保质保量地交付软件产品”方面我有了一些体会,但却感觉知识、经验零散,不成体系。于是我迫切地想找到一套工具,把这些零散的知识、经验链接起来,形成一整套理论体系。恰好此时我遇见了这本书,如同犯困的时候有人递枕头,读完仿佛睡了一个好觉,有神清气爽、酣畅淋漓之感。

——王旭东,中银保险有限公司信息科技部副总经理

这本书从软件设计的角度阐明了什么是软件工程,贯穿了实用的设计理念和开发原则,帮我们梳理了进化式地扩展我们的系统、即便在不清楚目标的前提下也可以取得进展的方法,同时整理了随着系统变得越来越复杂,管理系统复杂性的各种设计和开发思想。我们在项目中遇到的实际问题,都可以在这本书中找到借鉴之处。这本书既适合初学者学习,又适合有经验的软件开发人员和架构师作为参考用书,甚至对于管理者在组织架构方面都提出了很好的建议。

——黄海,北京邮电大学信息与通信工程学院多媒体技术教研中心主任、硕士生导师

《现代软件工程:如何高效构建软件》这本书非常好,它描述了当今有经验的从业者们实际构建软件的方式。法利介绍的技术不是死板的、规定性的或线性的,但是它们严格遵循软件构建所需要的方式:经验主义的、迭代的、反馈驱动的、经济的,并且专注于可运行的代码。

——格伦·范德堡(Glenn Vanderburg),Nubank公司的工程总监

有很多书会告诉你如何效仿一个特定的软件工程实践,但这本书不一样。戴维在书中所做的是,阐述软件工程的本质,以及它与简单工艺的区别。他解释了为什么为了掌握软件工程,你必须成为学习和管理复杂性的专家,如何用已经存在的实践支持这一结论,以及如何判断关于软件工程价值的其他观点。这本书适用于任何认真考虑把软件开发当作一门真正的工程学科的人,无论你是刚刚起步还是已经构建软件几十年了。

——戴夫·豪恩斯洛(Dave Hounslow),软件工程师

这些都是重要的话题,有一个纲要把它们汇集成一个整体太好了。

——迈克尔·尼加德(Michael Nygard),《发布!软件的设计与部署》一书的作者,专业程序员和软件架构师

我一直在看戴维·法利这本书的评阅样书,这本书正是我们需要的。任何有志成为软件工程师或想要掌握这项工艺的人都应该阅读这本书。这本书给了我们关于专业工程的务实、实用的建议。它应该成为大学和训练营的必读书。

——布赖恩·芬斯特(Bryan Finster),杰出的工程师和美国空军一号平台的价值流架构师

我在大学里学的是计算机科学,当然,我完成了几门名为“软件工程”或者名字与之类似的课程。

在我开始攻读学士学位时,我对编程其实并不陌生,并且已经为我的高中的职业图书馆实现了一个完全有效的目录管理系统。我记得自己曾经对“软件工程”极度困惑,它的存在似乎就是为了妨碍实际的代码编写和应用程序交付。

21世纪初,当我毕业的时候,我去了一家大型汽车公司的IT 部门工作。正如你所料,他们热衷于“软件工程”。就是在这里,我第一次看到(但肯定不是最后一次!)甘特图(Gantt chart),也是在这里,我体验到了瀑布式(waterfall)开发。也就是说,我看到软件开发团队在需求收集和设计阶段花费了大量的时间和精力,而在实现(编码)上花费的时间却少得多,这样当然会占用测试时间,然后测试……好吧,剩下的时间已经不多了。

这似乎是在告诉我们,“软件工程”实际上阻碍了创建对客户有用的高质量应用程序。

和许多开发者一样,我觉得一定有更好的方法。

我了解过极限编程(extreme programming,XP)和Scrum。我想在一个敏捷的(agile)团队中工作,为了找到一个这样的团队,我换了几次工作。很多人说他们是敏捷的,但是通常归总起来,他们不过都是把需求或任务写在索引卡上,贴在墙上,一周为一个冲刺(sprint),然后要求开发团队在每个冲刺内交付“x”张卡片,以满足任意的截止日期。以这样的方式来摆脱传统的“软件工程”方法似乎并不起作用。

在我从事软件开发工作10年后,我参加了位于伦敦的一家金融交易所的面试。软件负责人告诉我,他们采用极限编程,包括测试驱动开发(test-driven development,TDD)和结对编程(pair programming)。他告诉我,他们正在做一件叫作持续交付(continuous delivery)的事情,这很像持续集成(continuous integration),但是它会一直把代码部署到生产环境。

我曾在大型投资银行工作过,在那里,通常部署工作至少需要3小时,而且通过一份12页的文档来实现所谓的“自动化”,文档中包含需要手动执行的步骤和需要输入的命令。持续交付似乎是个不错的想法,但无疑是不可能的。

这位软件负责人就是戴维·法利(David Farley),我入职这家公司的时候,他正在撰写他的《持续交付:发布可靠软件的系统方法》一书。

我在这家公司和戴维·法利共事了4年,他改变了我的人生,成就了我的事业。我们确实做了结对编程、测试驱动开发和持续交付。我还学到了行为驱动开发(behavior-driven development)、自动化验收测试(automated acceptance testing)、领域驱动设计(domain-driven design)、关注点分离(separation of concerns,SOC)、防腐层(anti-corruption layer)、机械同感(mechanical sympathy)和间接层。

我学会了如何用Java创建高性能、低延迟的应用程序。我终于明白了“大O符号”的真正含义,以及它如何应用于现实的编码中。简而言之,我在大学里学到的和在书本上读到的东西都实际用到了。

这样的工作方式是合理的、有效的,同时它交付了质量和性能非常高的应用程序,提供了前所未有的东西。更重要的是,作为开发人员,我们对自己的工作很满意。我们没有加班,在发布前也没有出现过紧急情况,那几年里代码从来没有变得复杂混乱、不可维护,我们始终可以做到定期交付新功能和“商业价值”。

我们是如何做到这一点的呢?其实就是遵循戴维在这本书中概括出来的实践方法。它不是形式化的,戴维显然从许多其他组织汲取了经验,聚焦到具体概念,令其适用于更多的团队和更广泛的业务领域。

适用于一个高绩效金融交易所的两三个办公地协作团队的方法,与对一家制造公司的大型企业项目或者对一家快速发展的初创公司有效的方法,并不完全相同。

我目前的角色是开发技术推广工程师,我与来自各种公司和业务领域的数百名开发人员交谈过,我听到了他们的“痛点”(即使是现在,他们中许多人的经历也与我20年前的没有什么不同)和成功故事。戴维在这本书中介绍的概念足够通用,可以在所有这些环境中使用,也足够具体,能够提供实际帮助。

有趣的是,在我离开戴维的团队后,我开始对软件工程师这个头衔感到不舒服。我不认为我们作为开发者所做的事情是工程构建;我不认为是工程学让这个团队成功的。我认为,对我们在开发复杂的系统时所做的工作来说,工程学是一门过于结构化的学科。我喜欢它是“工艺”的观点,因为它同时包含创造力和生产力两个概念,即使它没有充分强调“团队合作”这一解决大规模软件问题所需的要素。这本书改变了我的想法。

戴维清楚地解释了为什么我们会对什么是“真正的”工程有误解。他向我们展示了工程学是一门以科学为基础的学科,但它并不一定是死板的。他讲述了科学原理和工程技术是如何应用于软件开发的,并谈到了为什么那些我们认为是工程的、基于生产的技术不适合软件开发。

我喜欢戴维在这本书中所做的事,他将一些看起来抽象且难以应用的概念,引入我们工作离不开的实际代码中,并展示了如何将它们作为工具,来解决我们的具体问题。

这本书包含开发代码的混乱现实,或者应该说是软件工程的混乱现实:没有单一的正确答案。没有什么东西是一成不变的。在某个时间点上正确的事情,有时甚至在很短的时间之后,就会变得非常错误。

这本书的前半部分为我们提供了切实可行的解决方案,我们不仅可以在这样的混乱现实中存活下来,而且可以在其中得到发展。后半部分讨论了可能被一些人认为抽象或者学术性的话题,并展示了如何应用它们来设计更好的代码(例如,更健壮、更可维护或具有其他“更好的”特性的代码)。

在这里,设计绝对不是指一页又一页地设计文档或UML(统一建模语言)图,而是简单得就像“在编写代码之前或编写过程中思考一下代码”一样。(当我和戴维结对编程时,我注意到一件事,他花在实际输入代码上的时间非常少。事实证明,在写之前先思考一下我们要写的东西,可以帮我们节省很多时间和精力。)

戴维不会回避或者试图解释共同使用这些实践时出现的任何矛盾,或可能由单个实践引起的潜在混乱。相反,因为他花时间讨论了权衡和常见的混淆领域,我发现自己第一次明白,正是这些平衡和冲突创造了“更好的”系统。这关乎于理解,这些平衡和冲突都可以作为参考,了解它们的成本和收益,把它们当作“镜头”,时不时“调调焦”,来反复检视代码/设计/架构,而绝不是简单地以二元的、非黑即白的、或对或错的逻辑来理解它们。

读了这本书,我明白了为什么在我和戴维一起工作的那段时间里,我们作为“软件工程师”是如此成功和满意。我希望你通过阅读这本书,可以从戴维的经验和建议中受益,而不必为你的团队雇用一位戴维·法利。

工程快乐!

——特丽莎·吉(Trisha Gee),开发技术推广工程师和Java拥护者

前  言

本书将工程重新引入软件工程。在书中,我将描述软件开发的一种实用方法,它使用自觉的理性、严谨的思考方式来解决问题。这些理念是过去几十年我们把从软件开发中习得的心法持续应用的结果。

我之所以执着写这本书,是要让你相信,当工程应用于软件开发时,它既适用也有效,虽然这很可能与你想的不一样。接下来我就会详细描述这种用于软件的工程方法的基本原理,以及它怎么样和为什么能奏效。

这不是关于流程或技术的最新趋势,而是经过验证的、实用的方法,我们有数据显示哪些有效、哪些无效。

以小步迭代的方式工作的效果总比不迭代的要好。将我们的工作组织成一系列小型的、非正式的实验,并收集反馈,为我们的学习提供信息,使我们能够更加有意识地继续这样做下去,在问题与解决方案之间的差距里不断探索。将我们的工作划分开来,使每个部分都目标明确、清晰易懂,这样即使我们在开始之前不了解目标,也能认真地、有意识地逐步发展我们的系统。

即使在我们并不知道答案的情况下,这种方法依然能为我们提供指导,它告诉我们应该关注哪儿、关注什么。无论我们面临什么样的挑战,它都会增加我们成功的机会。

在本书中,我定义了一个模型,用来说明我们是如何组织自己来创建优秀的软件,以及如何高效地做到的,而无论规模大小,不管是真正复杂的系统还是简单的系统。

总有一些人做了出色的工作。我们受益于创新先驱,他们向我们展示了什么是可能的。然而,近年来,我们的行业已经学会了如何更好地解释什么是真正有效的。我们现在更好地理解了哪些想法更通用,可以被更广泛地应用,我们有数据支持这一认知。

我们可以更可靠、更好、更快地构建软件,我们有数据证明这一点。我们可以解决世界级难题,我们也有许多项目和公司的成功经验来说明这一点。

这种方法汇集了一系列重要的基本思想,而且建立在之前工作的基础上。在某种程度上,就新的实践而言,其中并没有什么新东西,但是我所描述的方法会将重要的思想和实践结合成一个连贯的整体,并为我们建立软件工程行为准则提供依据。

这并不是将完全不同的思想随机结合在一起,而是将这些思想紧密地交织在一起,使之相辅相成。当将它们结合在一起,并一致地应用到我们的思考、组织、工作开展中时,它们对工作的效率和质量有着重大的影响。尽管每一个孤立的思想可能都是我们熟悉的,但是将之结合是一种从根本上完全不同的思考,思考我们究竟在做什么。当这些思想结合在一起,并被用作软件决策的指导原则时,它们代表了一种新的开发范式。

我们正在探索软件工程的真正含义,它并不总是像我们所期望的那样。工程是指采用科学的、理性的方法来解决经济约束下的实际问题,但这并不意味着这种方法是理论化的或官僚化的。从定义上看几乎可以说,工程是实用的。

过去,人们在尝试定义软件工程时犯了一个错误,即太过于局限在定义特定的工具或技术上。软件工程绝不仅仅涵盖我们编写的代码和我们使用的工具。软件工程不是任何形式的生产工程,我们的问题不是生产。如果我说到工程时,让你想到官僚制度,那么不妨读完本书后再想一想。

软件工程和计算机科学不是一回事儿,尽管我们经常把两者混淆。我们既需要软件工程师,也需要计算机科学家。本书是关于行为准则、过程和思想的,我们需要将它们应用到构建可靠的、可重复的、更好的软件中。

作为软件工程师,我们理所当然地期待一个针对软件的工程学科,能够帮助我们以更高的质量和更高的效率解决我们面临的问题。

这样的工程学科还会帮助我们解决那些我们尚未想到的问题。这样一个学科的概念必定是通用的、持久的和普遍的。

本书试图定义一个紧密相关的思想集合。我的目标是将它们组合成一个连贯的东西,我们可以将其视为一个方法,一个可以影响我们(软件开发人员和软件开发团队)所做出的几乎所有决策的方法。

软件工程作为一个概念,如果要说它有什么意义的话,那一定是为我们提供了优势,而不仅仅是采用新工具的机会。

并非所有的思想都有同等价值。有好的思想,也有坏的思想,那么我们该如何区分它们呢?什么样的原则能够帮助我们评估软件和软件开发中出现的新思想的价值,并判定它是好还是坏呢?

任何思想如果可以被合理地归类为解决软件问题的工程方法,那么它都是普遍适用的,而且是基础性的。本书就是关于这些思想的。你应该用什么标准来选择你的工具?你应该如何组织你的工作?你应该如何组织你构建的系统和你编写的代码,来增加你成功创建它们的机会?

软件工程的定义

我在本书中主张对软件工程做如下定义。

软件工程是对经验主义的、科学方法的应用,目的是为软件中的实际问题找到高效的、经济的解决方案。

我的目标是远大的。我想提出一个大纲、一个结构、一个方法,我们可以认为软件工程是用于软件的真正的工程学科。从根本上讲,这基于3个关键理念。

科学及其实际应用“工程”是技术学科取得有效发展的必要工具。

软件工程学科从根本上来说就是学习和发现的学科,所以为了有所成就,我们需要成为学习专家,而科学和工程是我们最有效的学习途径。

我们构建的系统通常是复杂的,而且会越来越复杂。这就意味着,为了应对它们的发展,我们需要成为管理复杂性的专家

本书主要内容

第1部分“什么是软件工程?”,首先看看工程在软件环境中究竟意味着什么。这是关于工程的原则和原理,以及我们如何将这些原则和原理应用到软件中。这是软件开发的技术原理。

第2部分“优化学习”,着眼于我们如何组织工作,让我们在小步骤中也能取得进展。我们如何评估我们是取得了良好的进展,还是仅仅在今天创造了明天的遗留系统?

第3部分“优化管理复杂性”,探讨管理复杂性所需要的原则和技术。本部分更深入地探讨每一条原则,以及它们对于构建高质量软件的意义和适用性,而无论软件性质如何。

第4部分“支持软件工程的工具”,描述一些思想和工作方法,这些思想和工作方法可最大限度地增加我们的学习机会,增强我们在小步骤中取得进展的能力,以及在系统增长时管理系统复杂性的能力。

本书以加灰底的形式在全书中贯穿了关于软件工程的历史和原理以及思想发展的内容。这些插入的内容为本书中的许多观点提供了有益的背景。

致  谢

写这样的一本书需要很长时间、大量的工作,以及对许多思想的探索。协助我完成这个过程的人,以各种不同的方式帮助着我。他们有时同意我的观点,强化我的信念;有时不同意我的观点,促使我加强自己的论点或者改变自己的想法。

首先,我要感谢我的妻子凯特(Kate),她在各方面帮助了我。尽管凯特不是一位软件专业人士,但她读了本书的大部分内容,帮助我纠正语法,打磨文字。

我要感谢我的姐夫伯纳德·麦卡蒂(Bernard McCarty),他在科学这个话题上反复与我探讨,让我深入思考为什么我想讨论实验法和经验主义以及许多其他的东西。

我要感谢特丽莎·吉(Trisha Gee),她不仅写了非常好的序,而且在我写作本书的时候,总能得到她充满热情的鼓励。

我要感谢马丁·汤普森(Martin Thompson),我总是可以找到他,向他寻求计算机科学的专业意见,而且他经常可以对我相当随意的想法做出迅速的反应。

我要感谢马丁·福勒(Martin Fowler),尽管他需要把很多时间和精力投入其他项目,但他还是给了我建议来优化本书。

多年来,很多朋友都间接地帮助我形成对本书内容的想法,包括但不限于这些朋友:戴夫·豪恩斯洛(Dave Hounslow)、史蒂夫·史密斯(Steve Smith)、克里斯·史密斯(Chris Smith)、马克·普赖斯(Mark Price)、安迪·斯图尔特(Andy Stewart)、马克·克劳瑟(Mark Crowther)、迈克·巴克(Mike Barker)。

我要感谢培生教育出版集团团队在本书的出版过程中提供的帮助和支持。

我还要感谢一大群人,这些人有的我可能都不认识,他们给予我支持,他们善辩论、好挑战、善思考。这些年,我在Twitter和YouTube频道上参与了一些很棒的交流,我的很多想法都是在这些交流中产生的。谢谢!

我想把这本书献给我的妻子凯特和我的儿子们:汤姆和本。

多年来,凯特一直坚定地支持着我的写作和工作,她总是能够激发我思考,

她既是我的伴侣,也是我最好的朋友。

汤姆和本是我钦佩的年轻人,作为一名父亲,我深爱着他们,

我很高兴在写这本书的同时,有幸与他们一起参与了几项合资项目。

谢谢你们的帮助和支持!

服务与支持

本书由异步社区出品,异步社区(https://www.epubit.com)为您提供后续服务。

您还可以扫码二维码, 关注【异步社区】微信公众号,回复“e59958”直接获取,同时可以获得异步社区15天VIP会员卡,近千本电子书免费畅读。

提交错误信息

作者、译者和编辑尽最大努力来确保书中内容的准确性,但难免会存在疏漏。欢迎您将发现的问题反馈给我们,帮助我们提升图书的质量。当您发现错误时,请登录异步社区,按书名搜索,进入本书页面,单击“发表勘误”,输入相关信息,单击“提交勘误”按钮即可(见下图)。本书的作者、译者和编辑会对您提交的错误信息进行审核,确认并接受后,您将获赠异步社区的100积分。积分可用于在异步社区兑换优惠券、样书或奖品。

扫码关注本书

扫描下方二维码,您将在异步社区微信服务号中看到本书信息及相关的服务提示。

与我们联系

我们的联系邮箱是contact@epubit.com.cn。

如果您对本书有任何疑问或建议,请您发邮件给我们,并请在邮件标题中注明书名,以便我们更高效地做出反馈。

如果您有兴趣出版图书、录制教学视频,或者参与图书翻译、技术审校等工作,可以发邮件给我们;有意出版图书的作者也可以到异步社区在线提交投稿(直接访问www.epubit.com/selfpublish/submission即可)。

如果您所在的学校、培训机构或企业,想批量购买本书或异步社区出版的其他图书,也可以发邮件给我们。

如果您在网上发现有针对异步社区出品图书的各种形式的盗版行为,包括对图书全部或部分内容的非授权传播,请您将怀疑有侵权行为的链接通过邮件发给我们。您的这一举动是对作者权益的保护,也是我们持续为您提供有价值的内容的动力之源。

关于异步社区和异步图书

“异步社区”是人民邮电出版社旗下 IT 专业图书社区,致力于出版精品 IT 图书和相关学习产品,为作译者提供优质出版服务。异步社区创办于2015年8月,提供大量精品IT 图书和电子书,以及高品质技术文章和视频课程。更多详情请访问异步社区官网https://www.epubit.com。

“异步图书”是由异步社区编辑团队策划出版的精品IT专业图书的品牌,依托于人民邮电出版社近40年的计算机图书出版积累和专业编辑团队,相关图书在封面上印有异步图书的Logo。异步图书的出版领域包括软件开发、大数据、人工智能、测试、前端、网络技术等。

异步社区

微信服务号

第1部分 什么是软件工程?

第1章 简单介绍

1.1 工程——科学的实际应用

软件开发是发现和探索的过程,因此,要想成功,软件工程师需要成为学习方面的专家。

人类学习的最佳途径之一是科学,因此我们需要采用科学的技术和策略来解决我们的问题。这常常被误解为,我们需要成为软件领域的物理学家,以期望过高的精度来评估事物。工程要比这务实得多。

这里说的采用科学的技术和策略,指的是我们应该应用一些相当基础但非常重要的科学思想。

维基百科(Wikipedia)把我们大多数人在学校学到的科学方法归纳如下。

描绘:观察当前的状态。

假设:给出一个描述、一个推测,来解释你的观察。

预测:根据你的假设做出预测。

实验:验证你的预测。

当我们以这种方式组织我们的思维,并开始基于许多非正式的小型实验取得进展时,我们仓促得出不恰当结论的风险就会变小,最终我们会做得更好。

如果我们开始考虑控制实验中的变量,以便在结果中实现更高的一致性和可靠性,这将引导我们获得更具确定性的系统和代码。如果我们开始对自己的想法持怀疑态度,并探索如何去证伪它们,我们就能更快地识别并消除糟糕的想法,从而推进更快速的发展。

本书将深耕于解决软件问题的实用、务实的方法,其基础是对基本科学原理的非正式运用,换句话说,就是工程

1.2 软件工程的定义

本书中软件工程的定义是:

软件工程是对经验主义的、科学方法的应用,目的是为软件中的实际问题找到高效的、经济的解决方案。

对软件开发来说,采用工程方法是很重要的,其原因有二。其一,软件开发始终是一项发现和学习的活动;其二,如果我们的目标是“高效的”和“经济的”,那么我们的学习能力必须是可持续的。

这意味着我们必须管理我们所创造的系统的复杂性,以保持我们学习新事物和适应新事物的能力。

因此,我们必须成为学习专家管理复杂性的专家

专注于学习,从根本上说,有5个原则。具体来说就是,要成为学习专家,我们需要:

迭代(iteration);

反馈(feedback);

增量主义(incrementalism);

实验(experimentation);

经验主义(empiricism)。

这是创造复杂系统的一种逐渐演进的方法。复杂的系统不是完全从我们的想象中形成并突然出现的。它们是许多小步骤的产物,在这些小步骤中,我们尝试我们的想法,并在过程中对成功和失败做出反应。这些原则是我们探索和发现的工具。

这样的工作方式会约束我们,使我们能够稳妥地前进。我们需要能够促进探索的工作方式,这是每个软件项目的核心。

因此,除了要专注于学习,我们还需要在答案不确定,甚至有时候方向都不确定的情况下,以一种能够让我们取得进展的方式工作。

为此,我们需要成为管理复杂性的专家。不管我们要解决的问题的性质是什么,或者我们用什么技术来解决这些问题,能否应对我们面对的问题的复杂性,以及用来解决这些问题的解决方案的复杂性,是区分坏系统和好系统的关键。

要成为管理复杂性的专家,我们需要:

模块化(modularity);

内聚力(cohesion);

关注点分离(separation of concerns);

抽象(abstraction);

松耦合(loose coupling)。

我们很容易因为熟悉这些概念,反而看到了却又忽略了它们。是的,你肯定熟悉几乎所有这些概念。本书的目的是将它们组织在一起,形成一个连贯的方法,用于软件系统的开发,以便帮助你最大限度地利用它们的潜能。

本书首先会讲述如何使用上述这10个概念作为工具,来指导软件开发。然后,会讲述一系列可以充当实际工具的理念,它们可以为任何软件开发提供有效的策略。这些理念包括:

可测试性(testability);

可部署性(deployability);

速度(speed);

控制变量(controlling the variable);

持续交付(continuous delivery)。

当我们把这个想法付诸实践时,结果是意义深远的。我们构建出更高质量的软件,更快速地完成工作,在采纳这些理念的团队中工作的人们说,他们更享受自己的工作,感受到的压力更小,他们的工作与生活更加平衡。[1] 

[1] 基于“DevOps状态”报告以及微软(Microsoft)和谷歌(Google)分析报告的调查结果。

这些虽然是夸张的说法,但是同样有数据支持。

1.3 重新定义“软件工程”

我为这本书的名称苦苦挣扎,不是因为不知道它该是什么,而是因为我们的行业已经重新定义了工程在软件环境中的含义,这个术语已经“贬值”。

在软件领域,通常它要么被简单地当成“代码”的同义词,要么被视作过于官僚的和程序化的东西,让人望而却步。对真正的工程来说,没有什么比这更离谱了。

在其他学科中,工程简单地意味着“有效的东西”。它是过程和实践,运用它可以增加你把事情做好的机会。

如果“软件工程”的实践不能让我们更快速地构建更好的软件,那么这些实践就不是真正的工程,我们应该改变它们!

这是本书的核心思想,其目的是描述一个认知上一致的模型,该模型把一些基本原则汇集在一起,这些基本原则就是软件开发中所有伟大的根源。

没有人能够保证一定会成功,但是采用这些思维工具和组织原则,并将它们应用到你的工作中,肯定会增加你获得成功的机会。

如何获得发展

软件开发是一项复杂、深奥的活动。在某种程度上,这是我们人类从事的比较复杂的活动之一。假设每个人甚至每个团队,每次开始一项新工作时,每个人甚至每个团队都可以、也应该从零开始发明着手处理的方法,这样的假设是荒谬的。

我们已经学过而且还在继续学习一些有用的东西和一些不怎么有用的东西。那么,如果每个人对每件事都有否决权,我们所处的行业,我们作为一个团队,如何才能像艾萨克·牛顿(Isaac Newton)说的那样,站在巨人的肩膀上取得进步和发展呢?我们需要一些一致同意的原则和一些行为准则来指导我们的活动。

这种思路的危险在于,如果应用不当,它可能会导致苛刻的、过度指令化的“权威决策”式思维。

我们将回到以前糟糕的想法,即认为就是应该由管理者和领导者来告诉其他人该做什么和该如何做。

过多“限制”或过于“教条化”的最大问题是,如果我们的一些观念是错误的或是不完整的,我们该怎么办?这必然会成为现实,那么我们该如何挑战和反驳陈旧的、已经确立的、糟糕的观念,评估新颖的、潜力巨大的、未经尝试的想法呢?

关于如何解决这些问题,我们有一个很有力的方法。它是一种承认思想自由的方法,让我们能够挑战和驳斥教条,并且能够区分是流行的还是普通的、是陈旧糟糕的还是伟大的思想,而无须关心其来源是什么。它允许我们用更好的想法取代坏观念,并在好想法的基础上进行改进。从根本上说,我们需要某种能够让我们成长的结构,来逐步发展进步的方法、战略、流程、技术和解决方案。我们称这个好方法为科学

当我们把这个方法应用到解决实际问题上时,我们称之为工程

本书将介绍如何将科学式推理应用到我们的学科中,从而获得真正的、名副其实的软件工程

1.4 软件工程的诞生

软件工程作为一个概念产生于20世纪60年代末。这个词最初是由玛格丽特·汉密尔顿(Margaret Hamilton)开始使用的,后来她成为美国麻省理工学院(MIT)仪器实验室软件工程部的主管。玛格丽特领导了阿波罗太空计划(Apollo space program)飞行控制软件的开发工作。

在同一时期,北大西洋公约组织(North Atlantic Treaty Organization,NATO,简称北约)在德国加米施-帕滕基兴(Garmisch-Partenkirchen)召开了一次会议,尝试定义这个词。这是第一次软件工程会议

最早的计算机是通过开关来编程的,甚至将硬编码作为其设计的一部分。先驱者们很快意识到,这种方法既慢又不灵活,于是“存储程序”的概念就诞生了。这是第一次明确地区分软件和硬件。

到了20世纪60年代末,计算机程序已经变得非常复杂,难以自行创建和维护。它们参与解决更复杂的问题,并迅速成为使某些问题得以解决的有利步骤。

人们认为,硬件的发展速度与软件的发展速度存在着显著的差距。这在当时被称为软件危机

北约会议的召开,部分原因是为了应对这场危机。

今天再来阅读那些会议的记录,有许多观点显然是持久的。它们经受住了时间的考验,它们在今天和在1968年一样正确。对我们来说,识别出定义我们学科的一些基本特征,这一现象应该很有趣。

几年后,回顾过去,图灵奖(Turing Award)得主弗雷德·布鲁克斯(Fred Brooks)将软件的发展与硬件的发展相比:

在10年内,无论是在技术上还是在管理技巧上,都不会有任何单一的发展,能够保证在生产力、可靠性和简洁性上获得哪怕一个数量级的提升。[2] 

布鲁克斯是在与著名的摩尔定律[3] 进行比较时说这番话的,多年来硬件开发一直遵循摩尔定律。

[2] 资料来源:弗雷德·布鲁克斯1986年的论文《没有银弹:软件工程的本质性与附属性工作》(“No Silver Bullet:Essence and Accidents of Software Engineering”)。

[3] 1965年,戈登·摩尔(Gordon Moore)预测,在接下来的10年(到1975年),晶体管密度(而非性能)将每年翻一番,后来修正为每两年翻一番。这一预测成为半导体生产商的目标,并大大超出摩尔的预期,在接下来的几十年里,这一预测一直被实现。一些观察者认为,由于当前方法和量子效应方法的局限性,我们正在接近容量爆发式增长的终点,但在我撰写本书时,高密度半导体开发仍遵循摩尔定律。

这是一个有趣的观察结果,我认为,它会让很多人感到惊讶,但本质上它一直是正确的。

布鲁克斯接着说,这并不只是软件开发的问题,这更像是对硬件性能独特而惊人的进步的观察:

我们必须注意到,反常的并不是软件发展得太慢,而是计算机硬件发展得太快。自人类文明诞生以来,没有任何一项技术在30年里性价比上涨了6个数量级。

他在1986年写下这些,今天我们认为那是计算机时代的黎明。自那以后,硬件就一直在以这样的速度发展,在布鲁克斯看来,与现代系统的容量和性能相比,那些似乎功能强大的计算机就像玩具。然而……他对软件开发改进速度的观察仍然是正确的。

1.5 范式转移

范式转移(paradigm shift)的概念是由物理学家托马斯·库恩(Thomas Kuhn)提出的。

大多数的学习都是一种积累。我们建立理解层次,每一层都以前一层为基础。

然而,并不是所有的学习都是这样的。有时候,我们要从根本上改变对某个事物的看法,这让我们能够学到新东西,但这也意味着我们必须抛弃旧东西。

在18世纪,有声望的生物学家们(当时还不这么称呼他们)认为有些动物是自然产生的。自从达尔文(Darwin)在19世纪中期描述了自然选择的过程,就完全推翻了自然发生说的观点。

这种思想上的改变,最终引领我们发展到现代遗传学,使我们有能力在更根本的层面上理解生命。

同样,开普勒(Kepler)、哥白尼(Copernicus)和伽利略(Galileo)也挑战了当时的传统智慧,即地球是宇宙的中心。他们转而提出了太阳系的日心说模型。这最终使得牛顿发现了万有引力定律,爱因斯坦(Einstein)提出了广义相对论,有了它们,我们做到了在太空中旅行,创造出像全球定位系统(GPS)这样的技术。

范式转移的概念隐含着这样一种思想,即当我们做出这样的转移时,作为这个过程的一部分,我们将抛弃一些现在已知不再正确的观点。

把软件开发视为一门真正的工程学科,根植于科学方法和科学理性主义原理,其意义是深远的。

它的意义深远之处不仅在于它的影响和作用——关于这一点在《加速:企业数字化转型的24项核心能力》一书中有十分具有说服力的描述[4] ,同时还在于抛弃这种方法所取代的观点的必要性。

[4] “DevOps状态”报告背后的DevOps研究与评估(DORA)团队,描述了他们从研究中创造出来的预测模型。资料来源:《加速:企业数字化转型的24项核心能力》,作者为妮科尔·福斯格伦(Nicole Forsgren)、耶斯·亨布尔(Jez Humble)、吉恩·金(Gene Kim)(2018年)。

这为我们提供了一个方法,使我们的学习可以更有效果,而且可以更高效地抛弃糟糕的观点。

我相信,我在本书中描述的软件开发方法可以体现这样的范式转移。它为我们提供了新的视角来了解我们所做的是什么以及如何做。

1.6 小结

将这种工程思维应用到软件领域,不需要太过沉重的或过于复杂的过程。当我们构建软件时,范式转移会让我们从不同的角度思考我们所做的是什么以及如何做,这将帮助我们全面地看问题,更简单、更可靠、更高效地解决问题。

这不是更加官僚的。相反,它将提高我们的能力,使我们能够更加可持续地、更加可靠地构建高质量的软件。

读者服务:

微信扫码关注【异步社区】微信公众号,回复“e59958”获取本书配套资源以及异步社区15天VIP会员卡,近千本电子书免费畅读。

第2章 什么是工程?

我已经和人们谈论软件工程好几年了。因此,我经常参与有关桥梁建设的对话。他们的开头通常是“是的,但软件不是桥梁建设”,好像这是某种启示似的。

当然,软件工程和桥梁建设不一样,但大多数软件开发人员认为的桥梁建设也不像真正的桥梁建设。这种对话实际上是生产工程和设计工程的一种混淆。

当涉及物理实体时,生产工程是一个复杂的问题,制造实体的东西需要达到一定的精度和质量。

你需要按照特定的时间、特定的预算等条件,将小部件交付到某个特定的空间位置。当模型和设计不足时,你需要让理论上的构思适应实际情况。

数字资产则完全不同。虽然有一些类似的问题,但对数字制品来说,这些问题要么不存在,要么可以变得十分简单。任何类型数字资产的生产成本基本上都是可以忽略的,或者至少应该是可以忽略的。

2.1 生产不是我们的问题

对大多数人来说,困难的部分是把“东西”生产出来。设计一辆汽车、一架客机或一部手机可能需要付出的是努力和智慧,但是将最初的原型设计和想法投入大规模生产,则是极其昂贵且复杂的。

如果以效率为目标,尤其如此。由于存在这些困难,我们作为工业时代和工业时代思维的产物,对于任何重大任务,都会自然而然地、几乎不假思索地担心这一方面,即生产方面。

结果,在软件领域,我们相当一致地试图将“生产式思维”应用到我们的行业中。瀑布式[1](waterfall)流程是软件的生产线,它是大规模生产的工具。它不是发现、学习和实验的工具,却是或者至少应该是我们行业的核心。

[1] 瀑布式,用于软件开发,是一种分阶段的、顺序的组织工作的方法,它将工作分解成一系列不同的阶段,每个阶段之间有明确定义的工作交接。其思想是,依次处理每个阶段,而不是迭代。

除非我们很愚蠢,否则在软件开发的选择上,对我们来说,生产是由触发构建组成的!

这种触发构建式生产是自动的、按键式的、可伸缩性极强的,而且价格便宜到可以视作免费的。我们仍然可以犯错误,但这些问题都是能够理解的,并能通过工具和技术很好地解决。

生产不是我们的问题。这使得我们的学科与众不同,但这也让它容易被误解,并受制于错误的思维和实践,因为这种生产的便利性是如此不寻常。

2.2 设计工程,而非生产工程

即使在现实世界中,如果桥梁建造者正在建造第一座新型桥梁,那么大多数人认为的“桥梁建造”也是不同的。在这种情况下,你会遇到两个问题,一个与软件开发无关,一个与软件开发有关。

首先,无关的部分——即使在建造第一座新型桥梁时,因为它是实体的,也会遇到我提到过的所有生产问题,甚至更多。从软件的角度来看,这些都可以忽略。

其次,就桥梁建设而言,除了这些生产问题,如果你正在建造第一座新型桥梁,第二个真正困难的部分是新型桥梁的设计。

这很困难,因为当你的产品是实体时,你不可能快速迭代。在构建实体时,更改它们是很难的。

因此,其他学科的工程师采用建模技术。他们可能选择建立小型的物理模型,现在可能是用计算机模拟他们的设计或各种数学模型。

在这方面,我们软件开发人员拥有巨大的优势。桥梁建造者可能会对他们提出的设计进行计算机模拟,但得出的只是真实情况的近似值。他们的模拟,他们的模型,都是不精确的。而我们作为软件创建的模型,我们对问题的计算机模拟,就是我们的产品。

我们不需要担心我们的模型是否符合现实,我们的模型就是我们系统的现实,所以我们可以验证它们。我们也不需要担心更改它们的成本。它们是软件,因此,它们非常容易更改,至少与桥梁相比是这样的。

我们的学科是一门技术学科。我们喜欢这样认定自己,我猜,大多数认为自己是专业软件开发人员的人,可能在他们的教育中多少有一些科学背景。

尽管如此,很少有软件开发是在科学理性主义的思想下进行的。在某种程度上,这是因为在历史上我们犯过一些错误。这在一定程度上是因为我们假设科学是困难的、昂贵的,并且不可能在正常的软件开发计划范围内实现。

其中部分错误是假定某种程度的理想精度,而这样的精度在任何领域都是不可能实现的,更不用说在软件开发领域了。我们曾经犯过的错误就是追求数学精度,这和工程不是一回事儿!

工程与数学

在20世纪80年代末和90年代初,很多人都在谈论编程结构思想。对软件工程意义的思考转移到了检查我们生成代码的工作方式上。具体来说就是,我们如何才能更有效地识别和消除设计和实现中的问题?

形式化方法(formal method)成为一种流行的思想。当时,大多数大学课程都会教授形式化方法。形式化方法是一种构建软件系统的方法,用这种方法构建的软件系统中内置了对所编写代码的数学验证。其思想是,证明代码是正确的。

这样做存在的一个大问题就是,为复杂系统编写代码本身就很难了,而要编写定义复杂系统行为并自证其正确的代码就更难了。

形式化方法是一个很吸引人的想法,但是从实用的角度来说,它还没有在一般的软件开发实践中得到广泛的采用,因为从生产的角度来看,它使代码的生成更难,而不是更容易。

不过,一个更具哲学意义的论点略有不同。软件是不寻常的东西,它显然对那些喜欢数学思维的人很有吸引力。所以,将数学方法应用于软件的吸引力是显而易见的,但也有一定的局限性。

来看一个现实世界的类比。一些现代工程师打算利用他们所掌握的一切工具来开发一个新系统。他们将会创建模型和模拟,并计算出数字,以便弄清楚他们的系统是否能够工作。他们的工作在很大程度上依赖于数学,但是之后他们还是要进行实际的尝试。

在其他工程学科中,数学当然是一个重要的工具,但它不能取代对测试的需要和从实际经验中学习的需要。现实世界中的差异太大,无法完全预测结果。如果单靠数学就能设计出一架飞机,那么航空航天公司完全可以这么做,因为这比制造真正的原型机要便宜,但他们没有这么做。但是,他们广泛地使用数学来指导他们的思维方式,然后他们通过测试一个真实的设备来检查他们的思维。而软件与飞机或太空火箭完全不一样。

软件是数字化的,主要运行在确定的设备上,这个设备叫作计算机。因此,对于某种有限的环境,如果问题足够简单,有足够的约束、足够的确定性,并且可变性足够低,那么形式化方法是有效的。但这里的问题在于系统作为一个整体的确定性程度。如果在系统中到处都是并发的,到处都在与“真实世界”(人)交互,或者系统只是在一个足够复杂的领域中运行,那么“可证明性”很快就会变得不切实际。

所以,我们和航空航天的同行们走了同样的路,尽可能地运用数学思维,采用数据驱动的、务实的、经验主义的、实验的方法来学习,让我们能够在系统不断增长的同时对其进行调整。

在我撰写这本书的时候,美国太空探索技术公司(SpaceX)正在一边忙着发射火箭,一边努力完善星际飞船。[2]当然,它为火箭、发动机、燃料输送系统、发射基础设施和其他几乎每个方面的设计都建立了数学模型,但是之后它还是会测试它们。

[2] 在我撰写本书时,SpaceX公司正在开发一种新的完全可重复使用的航天器。据称SpaceX公司的目的是创造一个系统,使人们能够前往火星并在火星上生活,以及探索太阳系的其他部分。它采用了一种有意的快速迭代式工程,能迅速地创建和评估一系列快速生产原型。这是工程知识极限下的极端形式的设计工程,这是一个十分迷人的例子,向我们展示了创造新事物都需要什么。

即使是看似简单的事情,比如从4毫米不锈钢换成3毫米不锈钢,看起来也是一个相当可控的更改。SpaceX公司获得了有关金属抗拉强度的详细数据,它从测试中收集经验和数据,这些数据准确地显示了4毫米不锈钢制成的压力容器的强度。

尽管如此,SpaceX公司在分析完这些数据后,还是建立了实验原型来评估差异。它将这些测试件加压直至破坏,以检验计算是否准确,并获得更深入的了解。SpaceX公司收集数据并验证它的模型,是因为这些模型很有可能会以某种“神秘”的、难以预测的方式出现错误。

与其他所有工程学科相比,我们的显著优势在于,我们以软件的形式创建的模型,是我们工作的可执行结果。所以当我们测试它们时,我们是在测试我们的产品,而不是对产品最佳现实情况的猜测。

如果我们仔细地隔离出系统中我们感兴趣的部分,就可以在与生产环境完全相同的环境中对其进行评估。因此,与其他任何学科相比,我们的实验模拟能够更准确、更精确地代表我们系统的“真实世界”。

格伦·范德堡(Glenn Vanderburg)在他精彩的演讲“真正的软件工程”(Real Software Engineering)中说,在其他学科中“工程意味着有效的东西”,而对软件来说则几乎相反。

范德堡继续探索为什么会出现这种情况。他描述了软件工程的学术方法,这种方法非常复杂,几乎没有一个实践过它的人会在未来的项目中推荐它。

这种学术方法“过于沉重”,对软件开发过程全然没有任何显著的价值。范德堡说:

“学术软件工程”之所以奏效的唯一原因是,关心此事的精明人士愿意绕过这个过程。

从任何合理的定义角度来看,这都不是工程。

范德堡所说的“工程意味着有效的东西”很重要。如果我们选择将之当作“工程”的实践,不能让我们更快地开发更好的软件,那么它们就不符合工程的条件!

与所有实体生产过程不同,软件开发完全是一项发现、学习和设计的活动。我们的问题是探索,因此我们甚至比宇宙飞船设计者更应该应用探索技术,而不是生产工程技术。软件开发是一门设计工程的学科。

所以,我们对工程的理解经常是混乱的,那么工程到底是关于什么的?

第一位软件工程师

在玛格丽特·汉密尔顿领导阿波罗太空计划飞行控制软件开发期间,没有“游戏规则”可以遵循。她说:“随着每一项新的相关发现的出现,我们都在不断完善‘软件工程’规则,而美国国家航空航天局(NASA)的高层管理规则却从‘完全自由’变成了‘官僚主义的过度使用’。”

当时,能够拿来借鉴的此类复杂项目的经验很少,所以这个团队经常开拓新领域。汉密尔顿和她的团队面临的挑战是巨大的,而且在20世纪60年代,还没有找到关于堆栈溢出(stack overflow)的答案。

汉密尔顿讲述了一些挑战:

太空任务软件必须是人工操作的。它不仅必须起作用,而且必须在第一次就起作用。不仅软件本身必须非常可靠,它还需要能够实时执行错误检测和恢复。我们的语言使我们敢于犯最细微的错误。我们自己想出了构建软件的规则。我们从错误中学到的东西总是令人惊喜的。

与此同时,与其他更“成熟”的工程相比,软件通常被视为“穷亲戚”。汉密尔顿创造软件工程这个术语的原因之一,就是为了让其他学科的人们更认真地对待软件。

汉密尔顿方法背后的驱动力之一是关注事情如何失败——我们出错的方式。

我对错误很着迷,过去我从没有停止过思考是什么导致了一个特定的错误或者一类错误的发生,以及如何防止它未来再次发生。

这一重点基于科学理性地解决问题的方法。这并非假设你能在第一时间就做好计划不出错,而是你可以带着怀疑的态度对待所有的想法、解决方案和设计,直到你想不出事情会怎样出错。有时候,现实仍然会让你大吃一惊,但这是工程经验主义在起作用。

汉密尔顿早期工作中体现出的另一个工程原则是“失效安全”(fail safe)的概念。假设我们永远不可能为每个场景都编写代码,那么我们该如何编写代码来使我们的系统可以应对意外情况,同时仍然取得进展呢?众所周知,正是汉密尔顿主动实施了这一概念,拯救了阿波罗 11 号的任务,即使在下降过程中计算机出现了过载的情况,仍然让登月舱鹰号(Lunar Module Eagle)成功登上了月球。

当尼尔·阿姆斯特朗(Neil Armstrong)和巴兹·奥尔德林(Buzz Aldrin)乘坐登月舱(Lunar Excursion Module,LEM)向月球降落时,宇航员和任务控制中心之间进行了一次交流。当登月舱接近月球表面时,计算机发出了1201和1202的警报,宇航员们问是应该继续还是中止任务。

NASA犹豫不决,直到其中一名工程师大喊“继续!”,因为他知道软件出了什么问题。

在阿波罗11号上,每次1201或1202警报出现,计算机都会重启,重新启动重要的工作,比如控制下降引擎、运行显示屏和键盘(DSKY)装置,让机组人员知道发生了什么,但不会重新启动所有被错误安排了的交会雷达的工作。NASA在任务操作控制室(MOCR)的工作人员知道——因为麻省理工学院已经大量地测试了重启的能力——这项任务可以继续进行。[3]

这种“失效安全”行为被编码到系统中,关于它何时或如何起作用,不需要任何具体的预测。

所以,汉密尔顿和她的团队提出了更加具有工程主导性的思维方式的两个关键属性,即经验主义的学习和发现,以及想象事情可能会如何出错的习惯。

[3] 资料来源:彼得·阿德勒(Peter Adler)。

2.3 工程学的初步定义

大多数词典对工程学的定义都包括一些常用的词汇:“数学的应用”“经验主义的证据”“科学推理”“在经济约束范围内”。

我提出以下初步定义:

工程学是对经验主义的、科学方法的应用,目的是为实际问题找到高效的、经济的解决方案。

这里所有的词都很重要。工程学是应用科学,它是实用的。使用“经验主义”一词意味着学习,并为了解决问题而促进理解和改善解决方案。

工程学创造的解决方案不是抽象的象牙塔,它们是实用的,适用于问题和环境。

这些解决方案是高效的,它们是基于对经济形势的理解而产生的,并受经济形势的限制。

2.4 工程不等于代码

当涉及软件开发时,关于工程意味着什么,有另一个常见的误解,即工程只是输出——代码或者代码设计。

这种解释太狭隘了。工程对SpaceX公司意味着什么?不是火箭,它们是工程的产物。工程是创造它们的过程。火箭中当然有工程,它们当然是“工程结构”,但我们不认为只有焊接金属的行为是工程,除非我们对这个话题的看法出奇地狭隘。

如果我的定义成立,那么工程就是运用科学理性主义来解决问题的。工程真正发挥作用的地方是“问题的解决”,而不仅仅是解决方案本身。它是过程、工具和技术。思想、原理和方法共同组成了工程学科。

在写这本书的过程中,我有一个不同寻常的经历:我在我的YouTube频道上发布了一个失败的游戏视频,但这个视频比我大多数的视频都要受欢迎得多。

当我说这是“软件工程的失败”时,我得到的最常见的负面反馈是,我在指责程序员,而不是他们的经理。我的意思是,这是整个软件生产方法的失败。计划很糟糕,文化很糟糕,代码很糟糕(很多bug很明显)。

因此,在这本书中,当我谈到工程时,除非我特别限定它的含义,否则我指的就是制作软件所需要的一切。过程、工具、文化——都是整体的一部分。

编程语言的进化

软件工程的早期努力主要集中在创建更好的编程语言上。第一代计算机很少或根本没有将硬件和软件分开,他们通过将电线插入接线板或拨动开关来编程。

有趣的是,这项工作通常交给“计算员”来做,计算员通常是女性,她们在计算机(作为机器)出现之前就已经在做计算(数学)的工作了。

然而,这低估了她们的作用。当时,组织中“更重要”的人在说明“程序”时,通常说,“我们想要解决这个数学问题”。工作的安排,以及随后如何将其转化为适当的机器设置,这些细节,都留给了这些计算员来完成。她们才是我们学科真正的先驱!

现在,我们使用不同的术语来描述这些活动。我们把要告知工作人员的工作说明称为需求,把制订计划来解决问题的行为称为编程,把计算员称为程序员,她们是早期电子计算机系统的第一批真正的程序员。

接下来的一大步是向“存储程序”及其编码发展。那是纸带和打孔卡片的时代,采用这种存储介质来存储程序的最初步骤仍然是“相当硬核”的。程序用机器代码编写,并存储在纸带或卡片上,然后输入机器。

能够在更高层次的抽象中捕获想法的高级语言是下一个重大进步,这使得程序员可以更快地取得进展。

到了20世纪80年代初,几乎所有语言设计中的基本概念都被涵盖了。但这并不意味着此后就没有任何发展,而是大多数重大思想都已经被涉及了。尽管如此,作为我们学科的核心观念,软件开发对语言的关注仍在继续。

当然,有几个重要的发展步骤也都影响了程序员的生产力,但是可能只有一步给出了弗雷德·布鲁克斯提出的10倍或者接近10倍的提升。这一步就是从机器语言到高级语言的进化。

在这条进化的道路上,其他步骤也都意义重大,比如过程式编程(procedural programming)、面向对象(object orientation)和函数式编程(functional programming),但所有这些概念都已经存在了很长时间。

我们行业对语言和工具的痴迷一直在损害我们的专业。这并不意味着在语言设计方面没有改进,而是大多数语言设计方面的工作似乎都集中在错误的事情上,比如句法上的改进,而不是结构上的改进。

当然,在早期,我们需要学习和探索什么是可能的、什么是有意义的。然而,自那以后,人们付出大量的努力,却只取得较小的进步。当弗雷德·布鲁克斯说没有10倍的提升时,他的论文的其余部分就集中在我们可以做什么来突破这个限制上:

人类能克服疾病的第一步,就是以细菌说淘汰了恶魔说和体液说,正是这一步,带给了人类希望,粉碎了所有奇迹式的冀望。

……首先应该让系统运行起来,即使它除了调用一组合适的伪子程序之外,没有任何用处。然后,把它一点一点地充实起来,依次将子程序开发成具体操作或者调用下一级空的桩(stub)代码。

这些想法基于更深层、更深刻的思想,而非语言实现的琐碎细节。

这些问题更多地与我们学科的原理和一些基本原则的应用有关,无论技术的性质如何,这些基本原则都是适用的。

2.5 为什么工程很重要?

思考这个问题的另一种方式是,考虑如何着手制造对我们有帮助的东西。在人类历史的绝大部分时间里,我们创造的所有东西都是手工艺的产物。手工艺是创造事物的有效方法,但是它也有它的局限性。

手工艺非常擅长创造“一次性”物品。在手工艺生产系统中,每个物品必然都是独一无二的。从最纯粹的意义上讲,这适用于任何生产系统,但是手工艺方法尤其如此,因为其生产过程的精度和可重复性通常都很低。

这意味着单独制作的工件之间的差异更大。即使是最熟练的工匠创造出的物品,也只能达到人类的精准度和容忍度,这严重影响了手工艺系统可靠地再现事物的能力。格雷丝·霍珀(Grace Hopper)说:

对我来说,编程不仅仅是一门重要的实用艺术,它也是在知识的基础上进行的一项巨大的事业。

2.6 “工艺”的极限

我们通常会对手工艺产品产生情感。作为人类,我们喜欢与众不同,我们珍爱的、手工制作的东西体现了创造它的工匠的技能、爱和关怀,我们喜欢这种感觉。

然而,从根本上说,手工艺产品一般质量都不高。一个人,无论多么有才华,都不能像机器那么精确。

我们制造的机器能够操纵单个原子甚至亚原子粒子,但是如果有人手工制造的东西能够精确到毫米的十分之一,那么他一定具有非凡的天赋。[4]

在软件中这种精度有多重要呢?让我们想想程序在执行时会发生什么。人类可以在大约13毫秒的范围内感知变化;处理一幅图像或对某件事做出反应需要数百毫秒。[5]

[4] 原子的大小各不相同,但通常用数十皮米(1皮米 = 1 × 10−12米)来度量。所以,人类最好的手工艺的精度也只有一台好机器的1000万分之一。

[5] 《实时有多快?人类感知与技术》(“How Fast is Real-time? Human Perception and Technology”),参见“PubNub”网站的“Blog”栏目。

在我撰写本书时,大多数现代消费级计算机的时钟周期约为3GHz。现代计算机是多核并行操作指令系统,因此它们通常每个周期处理一条以上的指令,但是为简单起见,让我们粗略地把这个过程想象成,在寄存器间传送值、添加值或引用缓存中的值,每一条机器指令都需要一个时钟周期。

如果我们计算一下,在人类感知外部事件的绝对最短时间内,现代计算机可以处理多少条指令,这个结果约为3900万条指令!

如果把我们工作的质量限制在人类感知的尺度和精度上,我们充其量能以1︰(3900万)的比例对正在发生的事情进行取样。那么,我们错过什么的可能性有多大?

2.7 精度和可伸缩性

手工艺和工程之间的差异突出了工程的两个方面,这两个方面在软件环境中非常重要:精度和可伸缩性。

精度是显而易见的:通过应用工程技术,我们可以用比手工高得多的细节分辨率操纵事物。可伸缩性可能不那么明显,但却更为重要。工程方法不会像手工艺方法那样受到限制。

任何依赖于人类能力的方法,最终都会受到人类能力的限制。如果我致力于实现非凡的成就,我可能会学习画一条线,锉一块金属,或将汽车真皮座椅缝到不到一毫米的地方,但是无论我多么努力,无论我多么天赋异禀,人类肌肉和感官的精确程度是有限的。

然而,工程师可以创造机器,把东西造得更小、更精确。我们可以制造机器(工具)来制造更小的机器。

这项技术既可以一直缩小到量子物理学的极限,也可以一直扩大到宇宙学的极限。至少在理论上,没有什么能阻止我们,通过对工程的应用,操纵原子和电子(就像我们已经做到的那样),或者操纵恒星和黑洞(就像我们总有一天可能做到的那样)。

更清楚地说,在软件方面,如果我们非常熟练,训练非常刻苦,我们或许可以足够快地输入文本并单击按钮,以我们可以想象的速度来测试我们的软件。这样,在几分钟内,我们就可以完成一次测试。为了便于比较,假设我们每分钟可以对软件测试一次(这个速度,我不认为我自己能够保持很长时间)。

如果我们能够每分钟运行一次测试,那么与计算机相比,它的测试速度会是我们的数十万甚至数百万倍。

我曾经构建的系统,在大概2分钟内,运行了大约30000个测试用例。我们本可以进一步地扩大规模,但没有理由这么做。谷歌公司声称每天运行约1.5亿次测试,这相当于每分钟测试约104167次。[6]

[6] 《谷歌持续集成测试现状》(“The State of Continuous Integration Testing at Google”)。

我们不仅可以用计算机以比人类快几十万倍的速度进行测试,而且只要我们的计算机有电,我们就可以保持这样的速度。这就是可伸缩性!

2.8 管理复杂性

还有另一个方面,工程可以扩大规模,而手工艺则不然。工程思维倾向于引导我们把问题划分开来。在19世纪60年代美国南北战争之前,如果你想要一把枪,你得去找造枪工。造枪工是个工匠,而且他通常是一个男人!

造枪工会为你制造一整把枪。他会了解这把枪的方方面面,而且这把枪对你来说是独一无二的。他可能会给你一个子弹的模具,因为你的子弹和别人的不一样,而且是你的枪专用的。如果你的枪有螺丝钉,那么几乎每一个螺丝钉都一定会与其他所有螺丝钉不同,因为它是手工制作的。

美国南北战争在当时是空前的,它是第一次大规模生产枪械的战争。

有一个故事,一个人想把步枪卖给美国北方各州。他是一个革新者,而且似乎也有点儿喜欢出风头。他前往美国国会,为北方各州的军队争取制造步枪的合同。

他随身带了一袋子步枪零部件。在向美国国会议员们做报告时,他把这袋零部件倒在了地板上,并请美国国会议员们从这一堆零部件中挑选。他用那些被选出的零部件组装了一支步枪,赢得了合同,并进行了大规模生产。

这是第一次有可能实现这种标准化。为了让它成为可能,需要经历许多事情。机器(工具)必须经过设计,以使其重复制造出来的组件在一定的公差范围内彼此相同。其设计必须是模块化的,以便组件能够被组装起来,等等。

结果是毁灭性的。美国南北战争实质上是“第一次现代战争”。成千上万的人因为武器的大规模生产而丧生。这些武器比以前的武器更便宜,更容易维护和修理,也更精准。

这一切都是因为武器被设计、制造得更加精确了,同时也是因为武器的数量更多了。生产过程可以降低对技能的要求,并且可以扩大规模。工厂里的机器可以让技能不高的人制造出的步枪与大师制造的步枪精度相当,反而不再需要能工巧匠来制造每一件武器。

后来,随着工具、生产技术以及对工程的理解和行为规范的增加,机器大规模生产的武器质量和生产效率甚至超过了最伟大的工匠大师,而且价格几乎是任何人都能负担得起的。

一个简单的观点可能将其解释为需要“标准化”,或者需要采用“软件的大规模生产”,但这再次混淆了我们的问题的根本性质。这与生产无关,而与设计有关。

如果我们像美国南北战争时期的武器制造商那样设计一款模块化和组件化的枪,那么我们就能够更独立地设计枪的各个部分。从设计的角度来看,而不是从生产工程或制造的角度来看,我们已经改进了对制造枪支的复杂性的管理。

在这一步之前,如果想要改变设计的某些方面,枪械大师需要考虑整把枪。通过将设计组件化,美国南北战争的制造商可以探索增量式更改,来一步一步地提高他们的产品质量。埃茨格尔·迪克斯特拉(Edsger Dijkstra)说:

编程的艺术就是组织复杂性的艺术。

2.9 测量的可重复性和准确性

工程的另一个常见的方面是可重复性,有时人们拒绝将工程思想用于软件领域,就是因为这一点。

如果我们能够造出一台机器,可靠又准确地复制螺母和螺栓,我们就能大量生产它们,生产出来的所有螺栓的复制品都能和任一螺母的复制品配合使用。

这是一个生产问题,并不真正适用于软件。然而,支持这种能力的更基本的思想适用于软件。

为了制造螺母和螺栓,或者其他需要可靠地协同工作的任何东西,我们需要能够以一定的精度来测量。在任何学科中,测量的准确性都是工程的一个有利方面。

让我们想象一下一个复杂的软件系统。它在运行了几周后,假设系统出现故障。系统重新启动,两周后又以大致相同的方式出现故障,形成了一种模式。与注重工程的团队相比,注重工艺的团队会如何应对这种情况呢?

工艺团队可能会决定,他们需要的是更彻底地测试软件。因为他们是从工艺的角度来思考的,所以他们想要的,是清楚地观察失败。

这并不愚蠢,在这种情况下,这是有道理的。但如何做到呢?对于这类问题,我见过最常见的解决方案是创建一种称为浸泡测试[7]的东西。浸泡测试的运行时间会比两次故障之间的正常运行时间长一些,比如在我们的例子中假设它的运行时间是3周。有时人们会试图缩短浸泡时间,以便在较短的时间内模拟出问题,但通常行不通。

[7] 业界也称之为烤机测试或长时间稳定性测试。—— 译者注

测试开始运行,两周后,系统出现故障,最终发现并修复bug。

除了这一策略,还有其他选择吗?有!

浸泡测试可用于检测某种形式的资源泄漏。有两种方法可以检测泄漏:你可以等待泄漏变得严重;你也可以提高测量的精度,以便在泄漏变成灾难之前及早发现。

我的厨房最近漏水了,漏水点在一根埋在混凝土里的管子上。一旦混凝土被浸透到足以让水开始在其表面形成小水洼时,我们就检测到了泄漏。这就是“显而易见”的检测策略。

我们请了一位专业人士来帮我们修补漏洞。他带来了一个工具,一个工程化的解决方案。那是一个高度敏感的麦克风,用来“监听”地下泄漏的声音。

使用这个工具,他可以探测到埋在混凝土里的管子里的水在泄漏时发出的微弱的嘶嘶声,其超人类精度足以让他在数厘米内确定位置,然后挖出一条小沟,找到有破损的管子。

所以回到我们的例子:注重工程的团队将进行准确的测量,而不是等待糟糕的事情发生。他们将测试软件的性能,在漏洞成为问题之前检测到它们。

这种方法有多重好处。这不仅意味着,生产中的灾难性故障在很大程度上是可以避免的,而且也意味着,我们可以非常快地得到问题的指示,以及关于系统健康的有价值的反馈。无须进行长达数周的长时间稳定性测试,注重工程的团队可以在系统的常规测试中检测泄漏,并在几分钟内得到结果。戴维·帕纳斯(David Parnas)说:

软件工程常被视为计算机科学的一个分支,这类似于把化学工程看作化学的一个分支。我们需要化学家和化学工程师,但他们是不同的。

2.10 工程、创造和工艺

为了从总体上考虑工程,特别是软件工程,几年来我一直在探索其中的一些思想。我曾在软件会议上关于这个话题发表过演讲,偶尔也会在博客上写一些关于这个话题的文章。

有时我会从软件工艺思想的拥护者那里得到反馈,这种反馈通常是这样的:“在放弃工艺的过程中,你正在丢失一些重要的东西。”

软件工艺的思想很重要,它代表着从之前的大动干戈的、以生产为中心的软件开发方法中迈出的重要的一步。我的观点不是说软件工艺是错误的,而是说这还不够。

在某种程度上,这些争论开始于一个不正确的前提,一个我已经提到过的前提。许多软件工匠都犯了一个常见的错误,即认为所有的工程都是为了解决生产问题。我已经讲过这个问题,如果我们的问题是“设计工程”,那么与“生产工程”相比,这是一门非常不同的、更具探索性和创造性的学科。

然而,除此之外,与我交谈的软件工匠们担心的是丢掉由软件工艺带来的好处——集中在以下几点:

技能;

创造力;

创新自由;

学徒计划。

这些要素对任何有效的、专业的软件开发方法来说都很重要。然而,它们并不局限于基于工艺的方法。软件工艺是改进软件开发的一个重要步骤,它把重点重新放在了重要的事情上,以上列出的就是一些重要的事情。

20世纪80年代和90年代,这些要素曾经消失,或者至少被替代,因为人们试图将某种以生产为中心的指挥控制方法强制应用到软件开发中。这是一个糟糕的想法,因为,虽然瀑布式流程和思维在步骤可理解、可重复和可预测的问题中占有一席之地,但是这与软件开发的现实几乎没有关系。

软件工艺更适合真正的软件开发问题。

基于工艺的解决方案,不像基于工程的解决方案那样具有可伸缩性。

工艺可以生产好东西,但是只能在一定的范围内。

几乎所有人类努力尝试过的工程学科都做到了提高质量、降低成本,而且普遍能提供更健壮、更有弹性和更灵活的解决方案。

把技能、创造力和创新等概念仅仅与工艺联系在一起,是一个很大的错误。总的来说,工程师们——当然也包括设计工程师们,在任何时候都充分展示着所有这些品质。这些属性是设计工程过程的核心。

因此,用工程方法解决问题,无论如何都不会降低技能、创造力和创新的重要性。如果有什么区别的话,那就是它增强了对这些属性的需求。

至于培训,我想知道那些拥护软件工艺的朋友们是否相信,一个刚毕业的工程师离开大学后,会有人马上给他一个任务,让他负责设计一座新桥或一架航天飞机吗?当然不会!

一个工程师在职业生涯之初,会与更有经验的工程师一起工作。他将会学习他们的学科中、他们的工艺中实际的东西,甚至可能比手艺人要学得还多。

我看不出工艺和工程之间有什么矛盾。如果你从合理的、正式的角度来看一门手艺,从行会、学徒、技工到大师工匠,工程真的就是这之后的下一步。继17和18世纪的启蒙思想之后,随着科学理性主义的兴起,工程确实在精度和测量上提升了工艺。工程是工艺的后代,它比工艺更具可伸缩性、更有效。

如果你用更通俗的定义来定义工艺——想想手工艺品集市,就没有质量或进步的真正标准。所以工程也许更像是一种飞跃。

工程,特别是工程思维在设计中的应用,是我们的高科技文明和之前的农业文明的真正区别。工程学是一门学科,它使我们能够处理极其复杂的问题,找到简明、高效的解决方案。

当我们将工程思维的原理应用到软件开发时,我们在质量、生产力和解决方案的适用性方面都看到了可测量的显著提升。[8]

[8] 《加速:企业数字化转型的24项核心能力》一书中讲述了,开发方法更加规范的团队如何比那些开发方法不规范的团队“多花44%的时间在新工作上”。

2.11 为什么我们所做的不是软件工程

2019年,埃隆·马斯克(Elon Musk)的公司SpaceX做出了一项重大决定,即致力于研制航天器,为了有朝一日可以让人类在火星上生活和工作,并探索太阳系的其他部分。2019年,该公司将建造星际飞船的材料从碳纤维改成不锈钢。碳纤维是一个非常激进的想法,他们做了很多工作,包括用这种材料建造燃料箱原型。不锈钢也是一个激进的选择,由于铝质轻而强度大,大多数火箭都是用铝制造的。

SpaceX公司选择不锈钢而不是碳纤维或铝的原因有三:每千克钢的成本明显更低;钢的高温性能优于铝,可以应对重返地球大气层的温度;钢的低温性能显著优于另外两种选择。

碳纤维和铝在极低温和极高温下性能明显比钢弱。

你上一次听到有人为一个与软件构建相关的决策做出类似的解释是什么时候?这样的解释听上去甚至含糊不清。

这就是工程决策的样子。这些决策是以理性的标准,即特定温度下的强度或经济影响为依据的。这仍然是实验性的,仍然是迭代的,仍然是经验主义的。

你根据眼前的证据和你的理论做出决策,然后测试你的想法,看看它们是否可行。这不是一个完全可以预测的过程。

SpaceX公司建造了测试结构,然后先用水再用液态氮对其加压,这样就可以测试材料(钢)及其制造工艺的低温性能。设计工程是一种深入探索获取知识的方法。

2.12 权衡

几乎所有的工程都是一场优化和权衡的游戏。我们试图解决一些问题,就不可避免地要面临选择。在建造火箭的过程中,SpaceX公司最大的权衡之一是在强度和重量之间。这是飞行器的常见问题,实际上也是大多数交通工具的常见问题。

了解我们面对的权衡,对制定工程决策来说,是一个至关重要的基本方面。

如果我们让系统更安全,它将更难以使用;如果我们让它更分布式,我们就会花更多的时间整合它收集的信息。如果我们增加更多的人员来加速开发,我们将增加通信开销、耦合和复杂性,所有这些都会让我们慢下来。

在软件生产过程中,从整个企业系统到单个功能的每个粒度上,必须考虑的关键权衡之一就是耦合。(我们将在第13章对此进行更详细的探讨。)

2.13 进步的错觉

我们这个行业的变化程度令人印象深刻,但我的论点是,这种变化中的大部分其实并不显著。

当我写这本书时,我正在参加一个以无服务器计算(serverless computing)[9]为主题的会议。向无服务器系统发展是件有趣的事情,然而,由亚马逊网络服务(Amazon Web service,AWS)、微软Azure、谷歌或其他任何云服务平台提供的工具包之间的差异并不重要。

[9] 无服务器计算是一种基于云的提供“功能即服务”(functions as a service)的方法。函数是唯一的计算单元,运行它们的代码是按需启动的。

如果决定采用无服务器方法,将对系统的设计产生一些影响。在哪里存储状态?在哪里操作它?如何划分系统功能?当设计单元是一个函数时,如何组织和导航复杂系统?

无论你努力尝试的是什么,对你的努力能否成功来说,这些问题远比如何指定一个函数、如何利用平台的存储或安全特性这样的细节有趣得多,也重要得多。然而,我在这个主题上看到的几乎所有演讲都是关于工具的,而不是关于系统设计的。

这就好比我是一名木匠,只告诉我槽螺钉和十字螺钉之间的重要区别,但是不告诉我螺钉的用途,什么时候使用它们,以及什么时候选择钉子。

无服务器计算的确代表了计算模型向前迈进的一步,我不怀疑这一点。本书中的观点会帮助我们判断哪些思想是重要的,哪些不是。

无服务器之所以重要有几个原因,但首要的是,它鼓励采用更加模块化的方法进行设计,以便更好地做到关注点分离,尤其是在数据方面。

无服务器计算将计算从“每字节成本”转变成“每CPU周期成本”,以此改变了系统的经济性。这意味着,或者说应该意味着,我们需要考虑类型大不相同的优化。

就系统优化而言,与其用规范化数据存储来实现存储最小化,我们或许应该接受一种真正的分布式计算模型,使用非规范化存储和最终一致性模式。这些东西之所以重要,是因为它们会影响到我们创建的系统的模块化。

工具的重要性只取决于它们在一些更基本的事情上“做出改变”的程度。

2.14 从工艺到工程的旅程

重要的是不要轻视工艺的价值,对细节的关心和关注是创造高质量作品的必要条件。同样重要的是,不要忽视工程的重要性,它提高了工艺产品的质量和效用。

制造出可控制的、比空气重的可控飞行器的开拓者,是莱特(Wright)兄弟。他们是优秀的工匠,也是优秀的工程师。他们的大部分工作基于经验的累积,但他们也对设计的有效性进行了真实的研究。他们不仅是建造飞行器的开拓者,也是建造风洞来测量机翼设计有效性的开拓者。

机翼有着非凡的结构,莱特兄弟的建造是巧妙的,尽管以现代标准来看非常粗糙。它由木头和铁丝制成,上面覆盖着拉紧的布,用香蕉油做防风材料。

以早期开拓者的工作为基础,机翼和风洞推进了他们对空气动力学基本理论的理解。然而,莱特兄弟的飞行器,特别是机翼,主要是经过反复尝试和犯错的过程建造出来的,而不是纯粹的理论设计。

在现代人看来,它更像是工艺而非工程的产物。这在一定程度上是正确的,但并非完全正确。许多人尝试过用工艺的方法来建造“飞行器”,但都失败了。莱特兄弟成功的一个重要原因是他们运用了工程学。他们计算,创造并使用测量和研究工具。他们控制变量,以便加深理解并完善飞行模型。接着他们创造模型、滑翔机和风洞部件来测试,然后进一步增进理解。他们的创建原理并不完美,但他们不仅在实践上有所改进,而且在理论上也有所改进。

当莱特兄弟实现了比空气重的可控飞行器时,他们对空气动力学的研究让他们制造出了滑翔比[10]为8.3︰1的飞行器。

[10] 滑翔比是衡量飞行器效率的一个标准。这个比例是行驶距离和高度损失之间的比例。例如,飞机在(无动力)滑翔中,每下降1米,它将向前移动8.3米。

与现代飞机的机翼相比,比如现代滑翔机的机翼:莱特飞行者(Wright Flyer)的机翼是低弧度(缓慢的高升力翼型)的,用现代的标准衡量,它很重,尽管在当时这还算是轻结构。它使用简单的天然材料,实现了8.3︰1的滑翔比。

通过工程学、经验性发现和实验,以及材料科学、空气动力学理论的完善、计算机建模等,一架现代滑翔机拥有碳纤维、大展弦比的机翼。这样的机翼经过优化,重量轻,强度高,在它产生升力时,你可以清楚地看到它的弯曲。它的滑翔比可以达到70︰1以上,几乎是莱特飞行者的9倍。

2.15 只有工艺还不够

工艺很重要,特别是当你所说的工艺真的意味着创造力时。我们的学科是极具创造性的,但工程也是如此。我相信,工程实际上是人类创造力的最高境界。如果我们想在软件领域创造出伟大的作品,这种思维正是我们所需要的。

2.16 是时候反思了?

软件工程作为一门学科,其发展并没有真正达到许多人的期望。软件已经改变了而且正在改变世界。虽然已经有了一些出色的作品,并构建了一些创新的、有趣的、令人兴奋的系统,但对许多团队、组织和个人开发者来说,如何成功甚至如何取得进展并不总是清晰的。

我们的行业充斥着原理、实践、流程和技术,围绕着最佳编程语言、架构方法、开发流程和工具,存在着技术信念之争。人们似乎都不太确定,我们这个专业的目标和策略是什么或者应该是什么。

现代团队正在与设计的进度压力、质量和可维护性做着斗争。他们常常难以确定用户真正感兴趣的想法,他们没有时间去了解问题领域、技术,也没有机会将优秀的东西投入生产环境。

组织通常很难从软件开发中得到他们想要的东西。他们经常抱怨开发团队的质量和效率。他们想要帮助团队克服这些困难,但他们经常误解自己所能做的事情。

与此同时,我发现专家们在一些基本观点上有着相当深的共识,我很重视他们的观点,但这些观点通常都没有表述清楚,或者至少不够清楚。

也许是时候该重新思考一下这些基本观点是什么了。我们这门学科通用的原则是什么?哪些思想将会在未来几十年里依然适用,而不仅仅对当前这一代的技术工具适用?

软件开发不是一个简单的任务,也不是一个同构任务。然而,有一些思想是通用的。有一些思考、管理、组织和实践软件开发的方法,这些方法对于工作中所有这些有问题的方面,都有着显著的甚至戏剧性的影响。

本书的其余部分将探讨这些通用的思想,并提供一个对所有软件开发都应该通用的基本原则列表,无论问题领域是什么,无论工具是什么,无论商业或质量需求是什么。

在我看来,本书中的观点代表了我们努力追求的本质上的深层次、根本性的东西。

当我们做对了这些事情,并且许多团队都做对了的时候,我们会看到团队成员的工作效率更高、压力更小、倦怠感更少、设计质量更高,我们创造的系统也更有弹性。

我们建立的系统更能取悦用户。我们发现生产环境中的bug大大减少,而采用这些思想的团队发现,随着学习的逐渐推进,在他们工作的系统中,对几乎任何一个方面的改变都明显变得更容易了。这样做的最终结果通常是,以这种方式实践的组织获得了更大的商业成功。这正是工程的标志。

工程增强了我们的创造力来制造有用的东西,并让我们带着信心和质量前进。它让我们能够探索各种想法,并最终增强我们的创造能力,因此我们可以构建越来越大、越来越复杂的系统。

我们正处于真正的软件工程学科的诞生阶段,如果我们抓住这个机会,我们就可以开始改变软件开发实践、组织和教学的方式。

这很可能需要一代人来实现,但对我们受雇的组织和整个世界都具有巨大的价值,因此我们必须尝试。如果我们可以更快速、更经济有效地构建软件,会怎么样?如果软件质量更高、更容易维护、适应性更强、更有弹性、更符合用户的需求,又会怎么样?

2.17 小结

在软件领域,我们在某种程度上重新定义了工程。当然,在某些圈子里,我们已经把工程看作一种不必要的、繁重的、妨碍“真正软件开发”的累赘。真正的工程在其他学科中不是这些东西。其他学科的工程师进展更快,而不是更慢,他们创造的是更高质量的作品,而不是更低质量的作品。

当我们开始采用一种实用的、合理的、轻量级的、科学的软件开发方法时,我们看到了类似的好处。软件工程会是软件所特有的,但它同样会帮助我们更快地构建更好的软件,而不是妨碍我们如此。

读者服务:

微信扫码关注【异步社区】微信公众号,回复“e59958”获取本书配套资源以及异步社区15天VIP会员卡,近千本电子书免费畅读。

相关图书

UML基础、案例与应用(第3版)(修订版)
UML基础、案例与应用(第3版)(修订版)
持续交付:发布可靠软件的系统方法(英文版)
持续交付:发布可靠软件的系统方法(英文版)
团队软件过程(修订版)
团队软件过程(修订版)
掌握需求过程(第3版)
掌握需求过程(第3版)
术以载道——软件过程改进实践指南
术以载道——软件过程改进实践指南
系统分析师UML项目实战
系统分析师UML项目实战

相关文章

相关课程