软件开发项目中的一个常见争论是,是将时间花在提高软件质量上,还是集中在发布更有价值的功能上。通常,交付功能的压力主导了讨论,导致许多开发人员抱怨他们没有时间致力于架构和代码质量。
Betteridge的标题法则是一句谚语,它说任何标题或标题以问号结尾的文章都可以用“no”来总结。认识我的人都不会怀疑我想要颠覆这样一条法律的愿望。但这篇文章走得更远,它颠覆了问题本身。这个问题假设了质量和成本之间的共同权衡。在这篇文章中,我将解释这种权衡并不适用于软件-高质量的软件实际上生产成本更低。
虽然我的大部分写作对象都是专业软件开发人员,但在本文中,我不会假设有任何软件开发机制方面的知识。我希望这是一篇对任何参与思考软件工作的人都有价值的文章,特别是那些充当软件开发团队客户的商业领袖。
正如我在开场白中提到的,我们都习惯于在质量和成本之间权衡。当我更换智能手机时,我可以选择处理器更快、屏幕更好、内存更大的更昂贵的型号。或者我可以放弃这些品质中的一些来付更少的钱。这不是绝对的规则,有时我们可以买到物美价廉的东西。更多的时候,我们对质量有不同的价值观-有些人并没有真正注意到一个屏幕是如何比另一个更好的。但大多数情况下,这个假设是正确的,质量更高的产品通常成本更高。
如果我要谈论软件质量,我需要解释一下那是什么。这就是第一个复杂的问题--有很多东西可以算作软件的质量。我可以考虑一下用户界面:它是不是很容易引导我完成我需要做的任务,让我更有效率,并消除挫折感?我可以考虑它的可靠性:它是否包含导致错误和挫折的缺陷?另一个方面是它的架构:源代码是否被分成清晰的模块,这样程序员就可以很容易地找到并理解本周他们需要处理的代码的哪一位?
这三个质量的例子并不是一个详尽的列表,但它们足以说明一个重要的观点。如果我是该软件的客户或用户,我不欣赏我们称之为质量的某些东西。用户可以判断用户界面是否良好。高管可以判断该软件是否提高了员工的工作效率。用户和客户会注意到缺陷,特别是在损坏数据或使系统暂时无法运行的情况下。但是客户和用户无法感知软件的体系结构。
因此,我将软件质量属性分为外部(如UI和缺陷)和内部(体系结构)。区别在于,用户和客户可以看到是什么使软件产品具有高的外部质量,但不能区分内部质量的高低。
由于内部质量不是客户或用户可以看到的,这重要吗?让我们设想一下,丽贝卡和我写了一个应用程序来跟踪和预测航班延误。我们的两个应用程序都执行相同的基本功能,都有同样优雅的用户界面,而且几乎没有任何缺陷。唯一不同的是,她的内部源代码组织整齐,而我的内部源代码杂乱无章。还有一个不同之处:我的售价是6美元,而她的售价是10美元。
既然客户从来不会看到这个源代码,而且它不会影响应用程序的操作,为什么会有人多花4美元购买丽贝卡的软件呢?更广泛地说,这应该意味着不值得为更高的内部质量花更多的钱。
我的另一种说法是,用成本换取外部质量是有意义的,但用成本换取内在质量是没有意义的。用户可以判断他们是否想花更多的钱来获得更好的用户界面,因为他们可以评估用户界面是否足够好,值得花额外的钱。但是用户看不到软件的内部模块结构,更不用说判断它是否更好了。为什么要花更多的钱买一件没有效果的东西呢?既然是这样,为什么任何软件开发人员都应该把他们的时间和精力放在提高他们工作的内部质量上呢?
那么,为什么软件开发人员会对内部质量提出质疑呢?程序员将大部分时间花在修改代码上。即使在新系统中,几乎所有编程都是在现有代码库的上下文中完成的。当我想要向软件添加新功能时,我的第一个任务是找出该功能如何适应现有应用程序的流程。然后,我需要更改该流程以使我的功能适合。我经常需要使用应用程序中已有的数据,因此我需要了解这些数据代表什么,它与周围的数据如何关联,以及我可能需要为我的新功能添加哪些数据。
所有这些都是关于我理解现有代码的。但是软件很容易让人难以理解。逻辑可能会错综复杂,数据可能很难理解,用来指代事物的名字对托尼来说可能在六个月前是有意义的,但对我来说就像他离开公司的原因一样神秘。所有这些都是开发人员所称的CRUFT的形式-当前代码与理想情况之间的差异。
内部质量的主要特征之一是让我更容易弄清楚应用程序是如何工作的,这样我就可以看到如何添加内容。如果软件被很好地划分为不同的模块,我不需要阅读全部50万行代码,我可以在几个模块中快速找到几百行代码。如果我们把精力放在清晰的命名上,我就可以很快理解代码的各个部分做什么,而不必费解细节。如果数据明智地遵循基础业务的语言和结构,我就很容易理解它与我从客户服务代表那里收到的请求之间的关系。克鲁夫特增加了我理解如何做出改变的时间,也增加了我犯错的机会。如果我发现了我的错误,那么就会损失更多的时间,因为我必须了解错误是什么,以及如何修复它。如果我找不到它们,那么我们就会有生产缺陷,以后就会花更多的时间来修理东西。
我的改变也会影响到未来。我可能看到了一种快速添加此功能的方法,但这是一条与程序的模块化结构背道而驰的路线,增加了麻烦。如果我走这条路,我今天会让它对我来说更快,但在未来的几周和几个月里,会减慢其他所有必须处理这个代码的人的速度。一旦团队的其他成员做出了同样的决定,一个易于修改的应用程序可能很快就会积累到每一个微小的更改都需要数周的努力的地步。
在这里,我们看到了为什么内部质量对用户和客户很重要的线索。更好的内部质量使添加新功能更容易,因此速度更快,成本更低。丽贝卡和我现在可能有相同的应用程序,但在接下来的几个月里,丽贝卡的高内部素质让她每周都能添加新功能,而我却在苦苦挣扎,只想拿出一项新功能。我比不上丽贝卡的速度,很快她的软件就比我的更有特色了。然后,我的所有客户都会删除我的应用程序,取而代之的是丽贝卡的应用程序,尽管她可以提高价格。
内部质量的基本作用是降低未来变革的成本。但是,要编写好的软件需要付出一些额外的努力,这在短期内确实会带来一些成本。
许多人,包括软件行业的不少人,将构建软件比作建造大教堂或摩天大楼-毕竟,我们为什么要为高级程序员使用建筑师?但是,构建软件存在于一个物理世界未知的不确定世界中。软件的客户对他们需要的产品功能只有一个粗略的概念,并在软件开发过程中了解到更多--特别是在早期版本发布给他们的用户之后。软件开发的构建块-语言、库和平台-每隔几年就会发生重大变化。在现实世界中相当于,客户通常会增加新的楼层和改变平面图,一旦一半的建筑建成和占用,而混凝土的基本性质每隔一年改变一次。
考虑到这种级别的变化,软件项目总是在创造一些新奇的东西。我们几乎从来没有发现自己在研究一个以前已经解决过的众所周知的问题。当然,我们在构建解决方案的过程中了解到的问题最多,所以我经常听说团队只有在花了一年左右的时间构建了软件架构之后,才能真正最好地理解软件架构应该是什么。即使是最好的团队,他们的软件也会有缺点。
不同的是,最好的团队不仅创造了更少的麻烦,而且还消除了他们确实创造的足够多的麻烦,这样他们就可以继续快速添加功能。他们花时间创建自动化测试,以便能够快速发现问题,并花更少的时间消除错误。他们经常进行重构,这样他们就可以在它积累到足够多的障碍之前移除它。持续集成最大限度地减少了由于团队成员在不同目的下工作而造成的混乱。一个常见的比喻是,这就像清理厨房里的工作面和设备。做饭的时候你不能把东西弄脏,但是如果你不迅速清理东西,垃圾就会干涸,更难清除,而且所有的脏东西都会妨碍下一道菜的烹调。
即使是一个伟大的团队也会产生暴躁,但通过保持内部质量的高水平,就能够将其保持在可控的范围内。
高的内部质量将麻烦降至最低,使团队能够以更少的精力、时间和成本添加功能。
遗憾的是,软件开发人员通常不会很好地解释这种情况。我无数次与开发团队交谈过,他们说他们(管理层)不会让我们写出高质量的代码,因为这太耗时了。开发人员经常通过证明需要适当的专业精神来证明对质量的关注是合理的。但这种道义上的论点暗示,这种品质是以代价为代价的--注定了他们的论点。令人恼火的是,由此产生的粗糙代码既让开发人员生活更加艰难,又让客户付出了代价。当考虑内在质量时,我强调,我们应该只把它作为一个经济论点来对待。高内部质量降低了未来功能的成本,这意味着将时间投入到编写好的代码实际上降低了成本。
这就是为什么这篇文章的标题问题没有抓住要点。高内部质量软件的成本为负。通常在成本和质量之间的权衡,这是我们生活中大多数决策所习惯的,对于软件的内部质量是没有意义的。(它在外部质量方面也是如此,比如精心打造的用户体验。)。因为成本和内部质量之间的关系是一种不同寻常的、违反直觉的关系,它通常很难被吸收。但是理解它对于以最高效率开发软件至关重要。