Martin Fowler

软件开发项目中的一个常见争论是花时间提高软件质量还是专注于发布更有价值的功能。 通常,交付功能的压力主导了讨论,导致许多开发人员抱怨他们没有时间研究架构和代码质量。

贝特里奇新闻标题定律说任何文章如果标题以问号结尾,都可以用“否”来概括。了解我的人不会怀疑我想要颠覆这样的定律。但这篇文章比这更进一步——它颠覆了问题本身。 这个问题假设了质量和成本之间通常存在的权衡。在本文中,我将解释这种权衡并不适用于软件——高质量的软件实际上生产成本更低。

我们习惯于在质量和成本之间进行权衡

正如我在开场白中提到的,我们都习惯于在质量和成本之间进行权衡。当我更换智能手机时,我可以选择处理器更快、屏幕更好、内存更大的更昂贵的型号。或者我可以放弃其中一些品质来支付更少的钱。这不是一个绝对的规则,有时我们可以买到便宜的优质商品。更常见的是,我们对质量有不同的价值观——有些人并没有真正注意到一个屏幕比另一个更好。但大多数时候这个假设是正确的,更高的质量通常会花费更多。

软件质量意味诸多

如果我要谈论软件质量,我需要解释它是什么。这是第一个复杂的东西——有很多事情可以算作软件的质量。 我可以考虑用户界面:它是否可以轻松引导我完成我需要完成的任务,使我更有效率并消除挫折感?我可以考虑它的可靠性:它是否包含导致错误和让人有挫折感的缺陷?另一个方面是它的架构:源代码是否划分为清晰的模块,以便程序员可以轻松找到和理解他们本周需要处理的代码?

这三个质量的例子并不是一个详尽的清单,但它们足以说明一个重要的观点。如果我是该软件的客户或用户,我不会在意我们称之为质量的某些东西。用户可以判断用户界面是否良好。主管可以判断该软件是否使她的员工的工作效率更高。用户和客户会注意到缺陷,尤其是它们是否会损坏数据或导致系统一段时间无法运行。但是客户和用户不会觉察到软件的架构。

因此,我将软件质量属性分为外部(例如UI和缺陷)和内部(架构)。区别在于用户和客户可以看到是什么使软件产品具有较高的外部质量,但无法区分内部质量的高低。

乍一看,内部质量与客户无关

由于内部质量不是客户或用户可以看到的——重要吗?让我们想象一下 Rebecca 和我编写一个应用程序来跟踪和预测航班延误。我们的两个应用程序都执行相同的基本功能,都具有同样优雅的用户界面,并且几乎没有任何缺陷。唯一的区别是她的内部源代码组织得井井有条,而我的则是一团糟。还有另外一个区别:我的卖6美元,她的10美元。

既然客户从来没有看到过这个源代码,也不影响应用程序的运行,为什么有人会为 Rebecca 的软件多花 4 美元呢?更一般地说,这应该意味着为更高的内部质量支付更多的钱是不值得的。

我的另一种说法是,用成本换取外部质量是有意义的,但用成本换取内部质量是没有意义的。用户可以判断他们是否愿意支付更多费用来获得更好的用户界面,因为他们可以评估用户界面是否足够好以值得额外花钱。但是用户看不到软件内部的模块化结构,更谈不上判断它的好坏。为什么要为没有效果的东西付出更多? 既然如此——为什么任何软件开发人员都要花时间和精力来提高他们工作的内部质量呢?

内部质量使软件增强更容易

那么为什么软件开发人员会因为内部质量问题而提出问题呢?程序员大部分时间都花在修改代码上。即使在新系统中,几乎所有的编程都是在现有代码库的上下文中完成的。当我想向软件添加新功能时,我的首要任务是弄清楚该功能如何适应现有应用程序的流程。然后我需要修改该流程以让我的功能适应。我经常需要使用应用程序中已有的数据,因此我需要了解数据代表什么,它与周围数据的关系,以及我需要添加哪些数据来添加我的新功能。

所有这些都与我对现有代码的理解有关。但是软件很容易变得难以理解。逻辑可能会变得混乱,数据可能变得难以跟踪,用于指代事物的名称在六个月前对Tony来说可能有意义,但对我来说就像他离开公司的原因一样神秘。所有这些都是开发人员所说的坏味道的表现形式——当前代码与理想情况下的差异。

内部质量的主要功能之一是让我更容易弄清楚应用程序是如何工作的,这样我就可以知道如何添加内容。 如果将软件很好地划分为单独的模块,我不必阅读所有 500,000 行代码,我可以在几个模块中快速找到几百行。如果我们在清晰的命名上付出了努力,我可以快速了解代码的各个部分的作用,而不必费解细节。如果数据明智地遵循基础业务的语言和结构,我就可以轻松理解它与我从客户代表那里得到的需求之间的关系。坏味道增加了我思考如何进行修改所需的时间,也增加了我犯错误的机会。如果我发现了bug,那么就会浪费更多的时间,因为我必须了解错误是什么以及如何修复它。如果我没有发现它们,那么我们就会产生产品缺陷,并且以后会花更多的时间来修复它们。

我做出的修改也会对将来产生影响。我可能会有一种快速添加某个功能的方法,但这种做法与程序的结构模块化原则背道而驰,会引入坏味道。如果我这么做,我今天会做得更快,但会使在未来几周甚至几个月内必须跟这部分代码打交道的其他所有人的速度变慢。一旦团队的其他成员都这么干,一个易于修改的应用程序会迅速积累坏味道,以至于每一个小的修改都需要花费数周时间的地步。

新功能快速发布确是用户所关心的

现在我们看到了为什么内部质量对用户和客户很重要的线索。更好的内部质量使添加新功能更容易,因此更快、更便宜。Rebecca 和我现在可能有相同的应用程序,但在接下来的几个月里,由于Rebecca高的内部质量,她每周都能添加新功能,而我却被困在尝试去除代码坏味道,而只发布了一个新功能。我无法与Rebecca的速度相提并论,很快她的软件就比我的功能强大得多。然后我的客户们都卸载了我的软件,取而代之的是Rebecca的,甚至她还能够提高她的售价。

可视化内部质量的影响

内部质量的根本作用是降低未来修改的成本。但是编写高质量的软件需要一些额外的努力,这在短期内确实会带来一些成本。

可视化这一点的一种方法是使用以下伪图,其中我绘制了软件功能的累积与开发它的时间(以及成本)的关系。对于大多数软件开发工作,曲线看起来像这样。

这就是内部质量差的情况。最初进展很快,但随着时间的推移,添加新功能变得越来越困难。即使是很小的修改也需要程序员去理解大范围的代码,并且是难以理解的代码。当他们进行修改时,很容易改出问题,这又导致长时间的测试和需要修复的缺陷。

专注于高内部质量是为了减少生产力的下降。 事实上,一些产品看到了相反的效果,开发人员可以加快速度,因为可以通过利用以前的工作轻松构建新功能。这种愉快的情况很少见,因为它需要一支技术精湛、纪律严明的团队才能实现。但我们偶尔会看到它。

这里的微妙之处在于,有一段时间,低内部质量比高内部质量更有效率。在此期间,质量和成本之间存在某种权衡。自然而然地,问题就在于:在两条线交叉之前的这段时间有多长?

这里我们说明为什么这是一个伪图。没有办法衡量软件团队交付的功能。由于无法衡量产出,因此无法衡量生产力,因此无法对低内部质量(这也难以衡量)的后果给出可靠的数字。无法衡量产出在专业工作中很常见——我们如何衡量律师或医生的生产力?

我评估两条曲线交叉点的方法是征求我所知道的技艺精湛的开发人员的意见。而这个答案却出乎很多人的意料。开发人员发现低质量的代码会在几周内显著降低他们的速度。因此内部质量和成本之间的权衡适用的情况并不多。即使是小的软件工作也受益于对良好软件开发实践的关注,这确实可以从我的经验中证明。

高质量软件的生产成本更低

总结以上所说:

  • 忽视内部质量会导致坏味道快速积累
  • 坏味道会减慢功能开发的速度
  • 高内部质量将坏味道保持在最低限度,使团队能够以更少的精力、时间和成本添加功能

这就是本文标题所提出的问题没有意义的原因。高质量软件的“成本”是负的。我们在生活中的大多数决定中都习惯做出的成本和质量之间的权衡对软件的内部质量来说没有意义(它适用于外部质量,例如精心设计的用户体验)。因为成本和内部质量之间的关系是一种不寻常且违反直觉的关系,因此通常难以理解。但是理解它对于以最高效率开发软件至关重要。