高质量的软件是否值得付出代价?-Martin Flower
软件开发项目中的一个常见争论是花时间提高软件质量还是专注于发布更有价值的功能。通常,交付功能的压力在讨论中占主导地位,导致许多开发人员抱怨他们没有时间研究架构和代码质量。
"贝特里奇的标题定律"是一句格言,它说任何标题或标题以问号结尾的文章都可以用“否”来概括。认识我的人不会怀疑我想要颠覆这样的法律。但这篇文章比这更进一步——它颠覆了问题本身。这个问题假设了质量和成本之间的共同权衡。在本文中,我将解释这种权衡并不适用于软件——高质量的软件实际上生产成本更低。
尽管我的大部分文章都是针对专业软件开发人员的,但在本文中,我不会假设您了解软件开发的机制。我希望这篇文章对任何参与思考软件工作的人都很有价值,尤其是那些作为软件开发团队客户的商业领袖。
我们习惯于在质量和成本之间进行权衡
正如我在开头提到的,我们都习惯于在质量和成本之间进行权衡。当我更换智能手机时,我可以选择处理器更快、屏幕更好、内存更大的更昂贵的型号。或者我可以放弃其中一些品质来支付更少的钱。这不是绝对的规则,有时我们可以买到便宜的优质商品。更常见的是,我们对质量有不同的价值观——有些人并没有真正注意到一个屏幕比另一个更好。但大多数时候这个假设是正确的,更高的质量通常会花费更多。
软件质量意味着很多事情
如果我要谈论软件质量,我需要解释它是什么。这是第一个复杂性 - 有很多事情可以算作软件的质量。我可以考虑用户界面:它是否可以轻松引导我完成我需要完成的任务,使我更有效率并消除挫折感?我可以考虑它的可靠性:它是否包含导致错误和挫折的缺陷?另一个方面是它的架构:源代码是否划分为清晰的模块,以便程序员可以轻松找到和理解他们本周需要处理的代码?
这三个质量的例子并不是一个详尽的清单,但它们足以说明一个重要的观点。如果我是该软件的客户或用户,我不会欣赏我们称之为质量的某些东西。用户可以判断用户界面是否良好。主管可以判断该软件是否使她的员工的工作效率更高。用户和客户会注意到缺陷,尤其是当它们损坏数据或使系统无法运行一段时间时。但是客户和用户无法感知软件的架构。
因此,我将软件质量属性分为外部 (例如 UI 和缺陷)和内部(架构)。区别在于用户和客户可以看到是什么使软件产品具有较高的外部质量,但无法区分内部质量的高低。
乍一看,内部质量对客户来说并不重要
由于内部质量不是客户或用户可以看到的 - 重要吗?让我们想象一下 Rebecca 和我编写一个应用程序来跟踪和预测航班延误。我们的两个应用程序都执行相同的基本功能,都具有同样优雅的用户界面,并且几乎没有任何缺陷。唯一的区别是她的内部源代码组织得井井有条,而我的则是一团乱麻。还有一个区别:我的卖我的卖 6 美元,她的卖 10 美元。
既然客户从来没有看到过这个源代码,也不影响应用程序的运行,为什么有人会为 Rebecca 的软件多付 4 美元呢?更一般地说,这应该意味着不值得为更高的内部质量支付更多的钱。
我的另一种说法是,用成本换取外部质量是有意义的,但用成本换取内部质量是没有意义的。用户可以判断他们是否愿意支付更多费用来获得更好的用户界面,因为他们可以评估用户界面是否足够好以值得额外花钱。但是用户看不到软件内部的模块化结构,更谈不上判断它的好坏。为什么要为没有效果的东西付出更多?既然是这样——为什么任何软件开发人员都要花时间和精力来提高他们工作的内部质量呢?
内部质量使软件增强更容易
那么,为什么软件开发人员会因为内部质量而提出问题呢?程序员大部分时间都花在修改代码上。即使在新系统中,几乎所有的编程都是在现有代码库的上下文中完成的。当我想向软件添加新功能时,我的首要任务是弄清楚该功能如何适应现有应用程序的流程。然后我需要更改该流程以让我的功能适应。我经常需要使用应用程序中已有的数据,因此我需要了解数据代表什么,它与周围数据的关系,以及我可以使用哪些数据需要为我的新功能添加。
所有这些都是关于我对现有代码的理解。但是软件很容易让人难以理解。逻辑可能会变得混乱,数据可能难以理解,用于指代事物的名称在六个月前对托尼来说可能有意义,但对我来说就像他离开公司的原因一样神秘。所有这些都是开发人员所说的cruft 的形式——当前代码与理想情况下的差异。
cruft 的一个常见比喻是技术债务。添加功能的额外成本就像支付利息。清理垃圾就像支付本金一样。虽然这是一个有用的比喻,但它确实鼓励许多人相信 cruft 比在实践中更容易测量和控制。
内部质量的主要功能之一是让我更容易弄清楚应用程序的工作原理,以便我可以了解如何添加内容。如果将软件很好地划分为单独的模块,我不必阅读所有 500,000 行代码,我可以在几个模块中快速找到几百行。如果我们努力进行清晰的命名,我可以快速了解代码的各个部分的作用,而不必费解细节。如果数据明智地遵循基础业务的语言和结构,我就可以轻松理解它与我从客户服务代表那里得到的请求之间的关系。Cruft 增加了我理解如何进行更改所需的时间,也增加了我犯错误的机会。如果我发现了我的错误,那么就会损失更多的时间,因为我必须了解错误是什么以及如何解决它。如果我没有发现它们,那么我们就会出现生产缺陷,并且以后会花更多的时间来修复问题。
我的改变也会影响未来。我可能会看到一种快速添加此功能的方法,但它与程序的模块化结构背道而驰,增加了 cruft。如果我走这条路,我今天会做得更快,但会减慢在未来几周和几个月内必须处理此代码的其他所有人的速度。一旦团队的其他成员做出同样的决定,一个易于修改的应用程序会迅速积累到每一个小的变化都需要数周的努力的地步。
客户确实关心新功能很快就会出现
在这里,我们看到了为什么内部质量对用户和客户很重要的线索。更好的内部质量使添加新功能更容易,因此更快、更便宜。Rebecca 和我现在可能有相同的应用程序,但在接下来的几个月里,Rebecca 的高内在质量使她每周都能添加新功能,而我却被困在尝试剔除繁琐程序,只推出一个新功能。我无法与 Rebecca 的速度相提并论,很快她的软件就比我的功能强大多了。然后我所有的客户都删除了我的应用程序,取而代之的是 Rebecca,即使她能够提高价格。
可视化内部质量的影响
内部质量的根本作用是降低未来变革的成本。但是编写好的软件需要一些额外的努力,这在短期内确实会带来一些成本。
将这一点可视化的一种方法是使用以下伪图,其中我绘制了软件的累积功能与生成它的时间(以及成本)的关系。对于大多数软件工作,曲线看起来像这样。
这就是内部质量差的情况。最初进展很快,但随着时间的推移,添加新功能变得越来越困难。即使是很小的改动也需要程序员理解大范围的代码,那些难以理解的代码。当他们进行更改时,会发生意外损坏,导致测试时间过长和需要修复的缺陷。
专注于高内部质量是为了减少生产力的下降。事实上,一些产品看到了相反的效果,开发人员可以加快速度,因为可以通过利用以前的工作轻松构建新功能。这种愉快的情况很少见,因为它需要一支技术娴熟、纪律严明的团队才能实现。但我们偶尔会看到。
这里的微妙之处在于,有一段时间,低内在质量比高轨道更有效率。在此期间,质量和成本之间存在某种权衡。当然,问题是:在两条线交叉之前的这段时间有多长?
在这一点上,我们遇到了为什么这是一个伪图。没有办法衡量软件团队交付的功能。由于无法衡量产出,因此无法衡量生产力,因此无法对低内部质量(这也难以衡量)的后果给出可靠的数字。无法衡量产出在专业工作中很常见——我们如何衡量律师或医生的生产力?
我评估线路交叉点的方法是征求我所知道的熟练开发人员的意见。而答案却出乎很多人的意料。开发人员发现低质量的代码会在几周内显着降低他们的速度。因此,内部质量和成本之间的权衡适用的跑道并不多。即使是小的软件工作也受益于对良好软件实践的关注,这当然可以从我的经验中证明。
即使是最好的团队也会创造出cruft
许多非开发人员倾向于认为 cruft 仅在开发团队粗心并犯错误时才会发生,但即使是最优秀的团队在工作时也不可避免地会产生一些 cruft。
我喜欢用我与我们最好的技术团队负责人之一聊天的故事来说明这一点。他刚刚完成了一个被广泛认为取得巨大成功的项目。客户对交付的系统感到满意,无论是在功能还是构建时间和成本方面。我们的员工对项目的工作经验持积极态度。技术负责人大体上很高兴,但承认系统的架构并不是那么好。我的反应是“这怎么可能——你是我们最好的建筑师之一?” 他的回答是任何有经验的软件架构师都熟悉的:“我们做出了很好的决定,但直到现在我们才明白我们应该如何构建它”。
许多人,包括软件行业的不少人,将构建软件比作建造大教堂或摩天大楼——毕竟我们为什么要对高级程序员使用“架构师”?但是构建软件存在于物理世界未知的不确定性世界中。软件的客户对他们需要产品中的哪些功能只有一个粗略的想法,并在软件构建过程中了解更多信息——尤其是在向用户发布早期版本之后。软件开发的构建块——语言、库和平台——每隔几年就会发生很大的变化。现实世界中的等价物是客户通常会在建造和占用一半的建筑物后添加新楼层并更改平面图,
多拉精英团队研究
质量和速度之间的选择并不是软件开发中唯一具有直观意义的选择,而是错误的。还有一种强烈的想法表明,在快速开发、频繁更新系统和可靠的系统之间存在双模式选择,不会在生产中中断。开发运营状况报告中的细致科学工作证明这是一个错误的选择。
几年来,他们使用调查的统计分析来梳理高绩效软件团队的实践。他们的工作表明,精英软件团队每天多次更新生产代码,在不到一个小时的时间内将代码更改从开发推向生产。当他们这样做时,他们的变更失败率明显低于速度较慢的组织,因此他们可以更快地从错误中恢复。此外,这样的精英软件交付组织与更高的组织绩效相关。
鉴于这种程度的变化,软件项目总是在创造一些新颖的东西。我们几乎从来没有发现自己在处理一个以前已经解决的很好理解的问题。自然地,我们在构建解决方案时对问题的了解最多,所以我经常听到团队只有在他们花了一年左右的时间构建软件之后才真正最了解他们的软件架构应该是什么。即使是最好的团队在他们的软件中也会有缺陷。
不同之处在于,最好的团队不仅创建的垃圾要少得多,而且还删除了他们创建的足够多的垃圾,以便他们可以继续快速添加功能。他们花时间创建自动化测试,以便他们可以快速发现问题并花更少的时间来消除错误。他们经常重构,这样他们就可以在多余的东西堆积到足以妨碍他们之前去除它。持续集成最大限度地减少了由于团队成员在不同目的下工作而造成的麻烦。一个常见的比喻是,这就像清理厨房的工作台面和设备。做饭时不能不弄脏东西,但如果不快速清洁东西,污垢就会变干,更难去除,所有脏东西都会妨碍下一道菜的烹饪。
高质量软件的生产成本更低
总结所有这些:
- 忽视内部质量会导致垃圾快速堆积
- 这种垃圾会减慢功能开发的速度
- 即使是一个伟大的团队也会产生垃圾,但通过保持内部质量的高,能够控制它
- 高内部质量将杂物保持在最低限度,使团队能够以更少的精力、时间和成本添加功能。
遗憾的是,软件开发人员通常不会很好地解释这种情况。我无数次与开发团队交谈,他们说“他们(管理层)不会让我们编写高质量的代码,因为这需要太长时间”。开发人员通常通过证明对适当专业精神的需求来证明对质量的关注是合理的。但是这种道德论点意味着这种品质是有代价的——注定了他们的论点。令人讨厌的是,由此产生的粗糙代码既使开发人员的生活变得更加艰难,又使客户付出了代价。在考虑内部质量时,我强调我们应该只将其作为经济论证来处理。高内在质量降低了未来功能的成本,
这就是本文开头的问题没有抓住要点的原因。高质量软件的“成本”是负的。成本和质量之间的通常权衡,我们在生活中的大多数决定中都习惯了这种权衡,但对软件的内部质量没有意义。(它适用于外部质量,例如精心设计的用户体验。)因为成本和内部质量之间的关系是一种不寻常且违反直觉的关系,因此通常难以理解。但是理解它对于以最高效率开发软件至关重要。