Photo by Annie Spratt on Unsplash
《Software Engineering at Google》 笔记 01:软件工程是什么?
author's avatar
igaozp
未来已来,只是分布不均

Software Engineering at Google

软件工程可以被认为是 「随着时间推移而整合的编程」

本书强调了三个基本原则,我们认为软件组织在设计、架构和编写代码时应该牢记这些原则:

  • 时间和变化 ​代码如何展期生命周期内进行适配。
  • 规模和增长 ​一个组织如何适应它的发展过程。
  • 权衡和成本 ​一个组织如何根据时间和变化以及规模和增长的经验教训做出决策。 编程和软件工程之间有三个关键的区别:时间、规模和权衡取舍。

在一个软件工程项目中,工程师需要更多关注时间成本和需求变更。在软件工程中,我们需要更加关注规模和效率,无论是对我们生产的软件,还是对生产软件的组织。最后,作为软件工程师,我们被要求做出更复杂的决策,其结果风险更大,而且往往是基于对时间和规模增长的不确定性的预估。

了解时间对程序的影响的一种方法是思考「代码的预期生命周期是多少?」

  • 通常,周期短的代码不受时间的影响。对于一个只需要存活一个小时的程序,你不太可能考虑其适应基础库、操作系统(OS)、硬件或语言版本的新版本。这些短期系统实际上“只是”一个编程问题,就像在一个维度中压缩得足够扁的立方体是正方形一样。随着我们扩大时间维度,允许更长的生命周期,改变显得更加重要。在十年或更长的时间里,大多数程序依赖关系,无论是隐式的还是显式的,都可能发生变化。这一认识是我们区分软件工程和编程的根本原因。
  • 如果在软件的预期生命周期内,你能够对任何有价值的变化做出反应,无论是技术还是商业原因,那么你的项目是可持续的。重要的是,我们只关注能力——你可能因为缺乏价值或其他优先事项而选择不进行特定的升级。当你基本上无法对基础技术或产品方向的变化做出反应时,你就把高风险赌注押在希望这种变化永远不会变得至关重要。对于短期项目,这可能是一个安全的赌注。几十年后,情况可能并非如此。

另一种看待软件工程的方法是考虑规模。有多少人参与?随着时间的推移,他们在开发和维护中扮演什么角色?

团队协作带来了新的问题,但也提供了比任何单个程序员更多的潜力来产生有价值的系统。

软件工程与编程的不同之处在于需要做出的决策的复杂性及其风险。在软件工程中,我们经常被迫在几个路径之间做评估和权衡,有时风险很高,而且价值指标不完善。软件工程师或软件工程负责人的工作目标是实现组织、产品和开发工作流程的可持续性和管理扩展成本为目标。考虑到这些投入,评估你的权衡并做出理性的决定。有时,我们可能会推迟维护更改,甚至接受扩展性不好的策略,因为我们知道需要重新审视这些决策。这些决策应该是明确的和清晰的递延成本。

Hyrum’s Law 海勒姆定律:「当一个 API 有足够多的用户的时候,在约定中你承诺的什么都无所谓,所有在你系统里面被观察到的行为都会被一些用户直接依赖。」

对随时间变化和维护的讨论必须了解海勒姆定律,正如对效率或热力学的讨论必须注意熵一样。仅仅因为熵从不减少并不意味着我们不应该努力提高效率。在维护软件时,海勒姆定律会适用,但这并不意味着我们不能对它进行规划或试图更好地了解它。我们可以减轻它,但我们知道,它永远不可能被根除。 海勒姆定律代表了一种实践知识,即使有最好的规划、最好的工程师和可靠的代码评审实践,我们也不能假设完全遵守已发布的契约或最佳实践。作为 API 所有者,通过明确地接口约定,你将获得一定的灵活性和自由度,但在实践中,给定更改的复杂性和难度还取决于用户对你的 API 的一些可观察行为的有用程度。如果用户不能依赖这些东西,那么你的 API 将很容易更改。如果有足够的时间和足够的用户,即使是最无害的变更也会破坏某些东西;你对变更价值的分析必须包含调查、识别和解决这些缺陷的难度。

依赖其依赖性的脆弱和未发布特性的代码可能被描述为「黑客」或「聪明」遵循最佳实践并为未来规划的代码更可能被描述为「干净」和「可维护」。两者都有其目的,但你选择哪一个关键取决于所讨论代码的预期生命周期。我们常说,「如果『聪明』是一种恭维,那就是程序,如果『聪明』是一种指责,那就是软件工程。」

最初的设计可能完全符合逻辑,并遵循合理的最佳实践。只有在向后兼容的变化演变之后,新的、更有效的选择才变得重要。虽然没有犯错误,但随着时间的推移,变化仍然是有价值的。

我们的工程师的工作量是否随着组织的规模而增长?工作是否随着代码库的大小而变多?如果这两种情况都是真实的,我们是否有机制来自动化或优化这项工作?如果没有,我们就有扩展问题。 自动化(这样一个人就可以做到更多)、整合/一致性(这样低级别的更改影响有限的问题范围)和专业知识(以便少数人就可以做得更多)。

如果安全问题是在产品投入生产后才发现的,修复的成本就非常高。如果在部署到生产之前就发现了安全问题,那也需要花费大量的工作来检测和修复问题,但成本更低些。如果你能够在最初的开发之前发现安全问题,将缺陷提交到版本控制就被发现,修复的成本更低:他们已经了解该功能;根据新的安全约束规范进行开发,要比提交代码后再让其他人分类标识并修复它更简单。

我们看到的一个普遍真理是,在开发人员的工作流程中发现的问题,通常可以降低成本。考虑开发人员工作流程的时间表,从左到右,从概念和设计开始,通过实施、评审、测试、提交、金丝雀和最终的生产部署来进行。在此时间线之前,将问题发现转移到“左侧”会使修问题解决成本更低

“成本”大致可以转化为努力的方向,可以包括以下任何或所有因素:

  • 财务成本(如金钱)
  • 资源成本(如CPU时间)
  • 人员成本(例如,工作量)
  • 交易成本(例如,采取行动的成本是多少?)
  • 机会成本(例如,不采取行动的成本是多少?)
  • 社会成本(例如,这个选择将对整个社会产生什么影响?)

工程团队的决策应该归结为几件事:我们这样做是因为我们必须这么做(法律要求、客户要求)。我们之所以这样做,是因为根据当前证据,这是我们当时能看到的最佳选择(由一些适当的决策者决策)。

杰文斯悖论(Jevons Paradox):「一种资源的消耗可能会随着使用效率的提高而增加。」

时间不仅会触发技术依赖和软件系统的变化,还会触发用于驱动决策的数据的变化。

本质上,在相关系统的生命周期内,需要不时地重新审视决策。对于长期项目而言,在做出初始决策后,有能力改变方向通常是至关重要的。更重要的是,这意味着决策者需要勇气承认错误。与人的本能相反,勇于承认错误的领导人受更多的尊重。

我们认为,区分相关但不同的术语「编程」和「软件工程」是很重要的。这种差异很大程度上源于随着时间的推移对代码的管理、时间对规模的影响以及面对这些想法的决策。编程是产生代码的直接行为。软件工程是一组策略、实践和工具,这些策略、实践和工具是使代码在需要使用的时间内发挥作用,并允许整个团队的协作。