对程序员而言,一个不容忽视的事实是:任何系统都将经历变更,最初精心设计的软件也可能因不断的修补而变得面目全非。无论设计多么完美,随着时间推移,系统难免陷入混乱,只是程度和速度有所不同。因此,优秀的初始设计旨在延缓这一进程,减轻其带来的痛苦。我们应具备前瞻性,确保代码具备高度的可扩展性和易维护性,并对未来的重构保持开放心态。
唯一不变的就是变化本身
软件本质上与物理产品有着显著的不同。一方面,软件的“易于掌握”意味着它相对容易被复制和修改,这使得人们往往低估了开发和维护软件的实际复杂度。另一方面,“不可见性”指的是软件不像硬件那样有形,它的结构、逻辑和工作原理对于非专业人士来说难以直观理解,这也增加了沟通和管理上的难度。
对于大多数项目,第一个开发的系统并不合用。它可能太慢、太大,而且难以使用,或者三者兼而有之。将原型发布给用户的代价是高昂的,对于用户,使用极度痛苦;对于重新开发的人员,分散了精力;对于产品,影响了声誉,即使最好的再设计也难以挽回名声。
开发人员交付的是用户满意程度,而不仅仅是实际的产品。用户的实际需要和用户感觉会随着程序的构建、测试和使用而变化。
目标上的一些变化无可避免,事先为它们做准备总比假设它们不会出现要好得多。不但目标上的变化不可避免,而且设计策略和技术上的变化也不可避免。
为变更计划系统
如何为软件需求的频繁变更设计系统,是一个在理论界广泛探讨的问题,其讨论的深度和广度甚至超过了实际应用中的实践。
阶段化的变更管理同样至关重要,每个软件产品都应具有明确的版本编号,每个版本应设定具体的时间表和变更冻结日期,以此来界定哪些变更是当前版本范围内的,哪些则应留待下一版本处理。这种有序的方法不仅能够提高开发效率,还能确保软件质量。
为变更计划组织架构
对于大型项目,需要有一支由顶级程序员组成的“技术轻骑兵”,能够在项目高峰期迅速解决问题。高效的团队不仅团队的成员工作多样性而且可扩展性强,团队整体的灵活性高。
随着系统的变化,管理结构也需要相应调整,以促进管理人员和技术人员之间的互换性。作者提到了社会性的障碍,比如管理层对高级人员的过度保护,以及管理职位带来的额外威信,这些都会阻碍团队的有效协作。为了解决这些问题,一些实验室采取了取消职位头衔或设立双轨晋升体系的方式,旨在消除社会障碍,实现管理人员和技术人员之间的平等。
作者重申“外科手术队伍”式的软件开发团队,这种团队结构鼓励高级人才积极参与编程和开发,消除了社会障碍,增加了创造性乐趣。同时,这样的组织架构设计也有助于最小化成员间的接口,使系统更易于修改,当组织结构需要调整时,也能更加灵活地重新分配任务。
IBM 的两条职位晋升线
前进两步,后退一步
在程序发布给客户使用之后,它不会停止变化。发布后的变更被称为“程序维护”,但是软件的维护过程不同于硬件维护。
软件维护不包括清洁、润滑和对损坏器件的修复。它主要包含对设计缺陷的修复。和硬件维护相比,这些软件变更包含了更多的新增功能,它通常是用户能察觉的。对于一个广泛使用的程序,其维护总成本通常是开发成本的 40%或更多。令人吃惊的是,该成本受用户数目的严重影响。用户越多,所发现的错误也越多。
出现的 bug 数量是发布时间的函数
程序维护中的一个基本问题是——缺陷修复总会以(20-50)%的机率引入新的 bug。所以整个过程是前进两步,后退一步。
前进一步,后退一步
Lehman 和 Belady 对大型操作系统多个版本的历史进行了研究,揭示了软件系统随时间演变的一些重要规律。他们发现,虽然模块的数量随着版本号的增加呈线性增长,但受版本更新影响的模块数量却以指数级增长。这一现象导致系统架构逐渐被破坏,系统的混乱程度不断增加。随着时间推移,修复旧设计缺陷的工作量减少,而因早期维护活动中的错误引发的新问题却越来越多。最终,系统变得极其无序,修复工作变得越来越困难,甚至失去基础。尽管理论上系统始终可用,但实际上已无法继续作为进一步发展的基础。
此外,Lehman 和 Belady 通过统计模型的研究,得出了更为普遍的结论,这些结论得到了广泛的经验支持。Pascal C. S. Lewis 尖锐地指出,这一现象不仅限于软件系统,而是历史上许多伟大成就的共同命运。无论是构建文明、成立杰出机构,还是开发复杂的软件系统,最初的成功总是伴随着潜在的问题。一些致命的缺陷最终会导致系统崩溃,如同机器启动后不久便陷入停滞。因此,随着时间的推移,系统需要经历彻底的重新设计,以适应不断变化的环境和需求。
系统软件开发是减少混乱度(减少熵)的过程,所以它本身是处于亚稳态的。软件维护是提高混乱度(增加熵)的过程,即使是最熟练的软件维护工作,也只是放缓了系统退化到非稳态的进程。