质量有许多个维度。可靠性是质量的传统定义(如,这是一个buggy吗)。一般来说,一个软件产品易用并且大部分时间都在做正确的事情就足够了。然而,对于某些应用程序——像航空、医药和金融领域的应用程序——软件错误的代价是巨大的。通常,软件不会只因为通过了测试就变得可靠;到了你能够测试软件的时候,软件已经建立了内在质量。并不是所有的软件都可以被有效地测试。为了让软件可以有效地测试,必须从开始设计时就本着高质量这个目标来对软件进行设计。
尽管小型项目很少从开始就关注可测试性设计,但是要成功地构建大型和超大型C++系统,可测试性的重要就凸显出来了。可测试性同质量本身一样,不能事后再考虑,必须从开始就关注——甚至在写第一行代码时就关注。
对于质量来说,除了可靠性外还有很多其他方面需要考虑。例如,功能性决定一个软件产品是否满足了用户的期望。有时一个软件产品不受欢迎,原因是它没有足够的特性以满足用户的期望。更糟糕的是,一个软件产品可能完全脱离原本需要的功能:如果客户想买一把螺丝刀,那么世界上最好的锤子也无法通过螺丝刀的功能性测试。在开发启动之前,拥有一个清晰的满足市场需求的功能规格说明,是确保功能正确的重要一步。不过,在本书中,我们讲述设计和构建大型系统的技术,而不是讲述设计什么样的大型系统。
可用性是衡量质量的另一个指标,使用得好的话,某些软件产品可能会非常强大。然而,仅开发者能够有效地应用软件产品还不够。如果软件产品太复杂、晦涩难懂,典型的预期用户很难学会或者使用,该软件产品将无处可用。通常我们所说的用户是指系统的终端用户。然而,在大型的、分层设计的系统中,我们的组件的客户端可能正好是其他的组件。早期来源于用户(包括其他的开发者)的反馈对于确保可用性是非常必要的。
可维护性度量的是支持一个工作系统的相对成本。支持包括追踪缺陷、向新平台移植以及为了满足用户未来需求期望(不期望)的功能扩展特性。一个用C++(或者其他的语言)编写的,设计低劣的系统维护的成本可能很高,扩展系统的成本会更高。大型的、可维护的设计不是从天上掉下来的;而是遵循着确保可维护性的规则精心策划出来的。
性能是衡量软件产品速度和规模的指标。我们都知道面向对象设计在可扩展性和重用方面拥有绝对的优势,但是面向对象范型的某些方面如果应用不得当,可能导致程序运行更慢而且需要更多的存储空间。如果代码运行太慢,或者需要比竞争者的软件产品更多的存储空间,我们的软件产品就可能销售不出去。例如,在一个文本编辑器中将每个字符建模为一个对象,这在理论上是诱人的,但是如果我们对最佳的空间/时间的性能感兴趣,这就可能是一个不合适的设计决策。试图用一个用户自定义的版本(例如BingInt类)替换一个大量使用的基本类型(例如int)将会不可避免地降低软件的性能。如果开始时不拟定性能目标,我们就可能采用无法达到性能目标的体系结构或代码实现。此时再想达到性能目标,只能重写整个系统。软件工程师区别于单纯程序员的是,知道在什么地方接受某些不完美并且知道如何进行性能折中。
质量的每一个维度对产品的成功都是重要的。这些维度的取得拥有一个共同点:我们必须在项目的最早期就考虑质量的各个方面,否则一旦设计完成,根本无法优化产品的质量。