跳到主要内容

瀑布模型的谬误与增量开发

瀑布模型的假设是什么?​

  • 形态: 源自类似甘特图布局的阶段化流程, 常画成逐级下落的瀑布;
  • 改进版(Royce 1970): 允许存在一些从前一阶段到前一阶段的反馈, 并把反馈限定在直接相邻的先前阶段, 以容纳成本增加和进度延迟;
  • 核心假设: 项目只经历一次过程, 体系结构出色且易用, 设计合理可靠, 编码实现可以随测试修改和调整;
  • 隐含推论: 所有错误发生在编码实现阶段, 因此修复可以顺畅地穿插在单元和系统测试中;
  • 军事化: 该模型被奉为军用标准 DOD-STD-2167, 在有见地的从业者放弃之后仍长期幸存;

瀑布模型有哪两个基本谬误?​

  • 谬误一(错误发生的位置): 假设体系结构、设计一次做对, 只有编码会出错; 实际上性能问题、笨拙功能、对用户企图的误解都可能到系统测试甚至用户测试才暴露;
  • 谬误二(一次性构建): 假设整个系统一次性被构建, 在所有设计、大部分编码、部分单元测试完成之后才为闭环的系统测试合并各个部分;
  • 代价: 只有在投入全部开发投资之后才能发现无法接受的问题;

为什么必须存在逆向移动?​

  • 规则: 开发过程"下游"的经验和想法必须跃行而上, 有时会超过一个阶段, 来影响"上游"的活动;
  • 例子一: 设计实现会发觉某些体系结构的功能定义削弱性能, 于是体系结构必须重新调整;
  • 例子二: 编码实现会发现某些功能使空间剧增, 超过要求, 于是必须更改体系结构定义和设计实现;
  • 推论: 在把任何东西实现成代码之前, 可能要往复迭代两个或更多的"体系结构-设计-实现"循环;

增量开发如何工作?​

  • 第一步: 构建实时系统的基本轮询回路, 为每个功能提供空子函数(占位符);
  • 第二步: 编译、测试, 使它可以不断运行--它不直接完成任何事情, 但至少正常运行;
  • 第三步: 添加(可能是基本的)输入模块和输出模块, 于是出现一个可运行的框架;
  • 第四步: 一个功能接一个功能地开发和增加相应模块;
  • 每一步的性质: 都拥有一个可运行的系统; 如果足够勤勉, 每个阶段都会有一个经过调试和测试的系统;
  • 回归测试: 随着系统增长, 用所有先前测试用例对每个新模块进行回归测试;
  • 后续精化: 每个功能基本可运行后, 一个接一个地精化或重写每个模块, 增量地"生长"整个系统; 有时需要修改驱动回路甚至模块接口;
  • 两个直接收益: 可以很早开始用户测试; 可以采用按预算开发的策略, 彻底保证不出现进度或预算超支(以允许的功能牺牲为代价);
  • 士气效果: 屏幕上第一幅图案、第一个可运行系统对团队士气的鼓舞效果令人震惊;

增量开发和快速原型的区别是什么?​

  • 关系: 互相关联又相互独立, 各自可以不依赖对方而存在;
  • 原型的定义(Harel): 仅仅反映概念模型准备过程中所做的设计决策的版本, 它并未反映受实现考虑所驱使的设计决策;
  • 原型可以完全不属于发布产品: 例如只做界面原型, 内部只是一个看上去履行了各步骤的有限状态机, 甚至用模拟系统响应的向导技术来原型化;
  • 另一个方向: 实现人员可以先完整实现某一部分的有限功能集合, 从而尽早发现性能上的潜在问题;
  • 差别所在: 功能--第一个里程碑产品可能不包含足够的功能使任何人对它产生兴趣; 而可发布产品在完整性上配备一系列实用功能集, 在质量上可以健壮运行;

"每晚重建"说明了什么?​

  • 做法(微软 Jim McCarthy): 从第一个里程碑开始, 每晚重建开发中的系统并运行测试用例, 该构建周期成为项目的"心跳";
  • 每日动作: 一个或多个程序员-测试员队伍提交若干具有新功能的模块, 每次重建后都获得一个可运行的系统;
  • 失败处理: 如果重建失败, 停下整个过程, 直到找到问题并修复;
  • 效果: 任何时间团队每个人都了解项目状态; 向团队提供自身的可信度, 而可信度决定士气和情绪状态;
  • 前提: 必须投入大量资源, 并且是一个规范化、可跟踪、开诚布公的流程;
  • 可扩展性: Bell 北方研究所是每周重建 1200 万行的系统;