介绍
这一切都与复杂性有关
编写计算机软件是人类历史上最纯粹的创造性活动之一。程序员不受物理定律等实际限制的约束;我们可以创造令人兴奋的虚拟世界,其行为在现实世界中是不可能存在的。编程不需要像芭蕾舞或篮球那样有很好的身体技能或协调性。编程所需要的全部,是一个创造性的头脑和组织想法的能力。如果你能想象出一个系统,你可能就能在计算机程序中实现它。
这意味着,编写软件的最大限制是我们理解自己正在创建的系统的能力。随着一个程序发展,获得更多的功能,它变得复杂,其组成部分之间存在着微妙的依赖关系。随着时间的推移,复杂性不断积累,程序员在修改系统的过程中越来越难将所有的相关因素记在脑子里。这就减慢了开发速度并导致了错误,从而使开发速度更加缓慢并增加了成本。在任何程序的生命周期中,复杂性的增加是不可避免的。程序越大,从事这项工作的人越多,管理复杂性就越困难。
好的开发工具可以帮助我们处理复杂性,在过去的几十年中人们已经创造了许多伟大的工具。但是,单靠工具我们能做的事情是有限的。如果我们想让编写软件变得更容易,以便我们能以更低的成本建立更强大的系统,我们就必须找到使软件更简单的方法。尽管在我们做出了最大的努力以后,复杂性仍然会随着时间的推移而增加,但更简单的设计可以让我们在复杂性变得难以承受之前建立更大也更强大的系统。
有两种通用的方法可以对抗复杂性,这两种方法都将在本书中被讨论。第一种方法是通过使代码更简单、更易理解来消除复杂性。例如,可以通过消除特殊情况或以一致的方式使用标识符来减少复杂性。
处理复杂性的第二种方法是将其封装起来,这样程序员就可以在一个系统上工作,而不至于一下子暴露在系统所有的复杂性中。这种方法被称为模块化设计。在模块化设计中,一个软件系统被划分为多个模块,例如面向对象语言中的类。这些模块被设计成相对独立的,这样程序员就可以在一个模块上工作而不必了解其他模块的细节。
由于软件的可塑性很强,所以软件设计是一个持续的过程,跨越了软件系统的整个生命周期;这使得软件设计不同于物理系统的设计,如建筑、船舶或桥梁。然而,软件设计并不是一直都被这样看待。在编程的大部分历史中,设计都集中在项目的开始阶段,就像其他工程学科一样。这种方法的极致被称为瀑布模型(waterfall model),在这种模型中,一个项目被划分为不连续的阶段,如需求定义、设计、编码、测试和维护。在瀑布模型中,每个阶段在下一个阶段开始之前完成;在许多情况下,每个阶段由不同的人负责。在设计阶段,整个系统是一次性设计完成的。在这个阶段结束时,设计被冻结了,随后的阶段的作用是充实和实现这个设计。
不幸的是,瀑布模型很少能很好地适用于软件。软件系统在本质上比物理系统更复杂;在建立任何东西之前,不可能将一个大型软件系统的设计可视化到足以理解其所有的影响。因此,最初的设计会有很多问题。这些问题直到实现过程中才会显现出来。然而,瀑布模型的结构并不适合在这个时候进行重大的设计变更(例如,设计者可能已经转到其他项目)。因此,开发人员试图在不改变整体设计的情况下解决问题。这就导致了复杂性的爆炸。
由于这些问题,今天的大多数软件开发项目都采用一种增量方法,如敏捷开发(agile development),在这种方法中,最初的设计侧重于整体功能的一个小的子集上。这个子集被设计、实现,然后进行评估。原始设计中的问题被发现并得到纠正,然后再设计、实现和评估一些功能。每一次迭代都会暴露出现有设计中的问题,在设计下一组功能之前,这些问题都会被解决。通过这种方式分散设计,初始设计的问题可以在系统还很小的时候得到解决;后来的功能受益于早期功能实现过程中获得的经验,所以它们的问题更少。
增量方法适用于软件,因为软件有足够的可塑性,允许在实施过程中进行重大的设计变更。相比之下,对于物理系统来说,重大的设计变更要困难得多:例如,在建设过程中改变支撑一座桥梁的塔的数量是不现实的。
增量开发意味着软件设计永远不会结束。设计在一个系统的生命周期中不断发生:开发人员应该一直在思考设计问题。增量开发也意味着不断地重新设计。一个系统或组件的最初设计几乎从来都不是最好的;经验不可避免地会显示出更好的做法。作为一个软件开发者,你应该时刻注意改进你正在开发的系统的设计的机会,并计划花一些时间来改进设计。
如果软件开发者应该一直思考设计问题,而降低复杂性是软件设计中最重要的因素,那么软件开发者就应该一直思考复杂性问题。本书是关于如何在软件的整个生命周期中使用复杂性来指导软件的设计。
本书有两个总体目标。第一个目标是描述软件复杂性的本质:“复杂性”是什么意思,为什么它很重要,以及你如何识别一个程序有不必要的复杂性?本书的第二个目标,也是更具挑战性的目标,是介绍你在软件开发过程中可以使用的技术,以尽量减少复杂性。不幸的是,并没有一个简单的诀窍可以保证出色的软件设计。相反,我将介绍一系列更高层次的概念,这些概念接近于哲学,如“类应该是深的”或“将错误定义为不存在的”。这些概念可能不会立即确定最好的设计,但你可以用它们来比较设计的备选方案,并指导你对设计空间的探索。
Last updated