第3章 Measure Twice, Cut Once:Upstream Prerequisities 三思而后行:前期准备
3.1 Importance of Prerequisites 前期准备的重要性
如果你在项目的末期强调质量,那么你会强调系统测试。但是测试只是完整的质量保证策略的一部分,而且不是最有影响的部分。测试是不可能检查出诸如:“制造了一个错误的产品”,或者“使用错误的方法制造正确的产品”之类的缺陷的。这样的缺陷在测试之前解决——更确切地说是在构建活动之间。
如果你在项目中期强调质量,那么你就会强调构建实践。这些实践是本书绝大部分篇幅的关注点
如果你在项目的开始阶段强调质量,那么你就会计划、要求并且设计一个高质量的产品。
- Do Prerequisites Apply to Modern Software Projects
前期准备适用于现代软件项目吗
有些人断言,诸如架构、设计及项目规划等前期工作对于软件项目来说是毫无用处的。总体来说,没有哪项研究(无论过去还是仙子阿)支持这一断言,最近的数据也不支持这一断言。
准备工作的中心目标就是降低风险:一个好的项目规划者能够尽可能早地将主要的风险清除掉,以使大部分工作能够尽可能平稳地进行。目前,软件开发中最常见的项目风险是糟糕的需求分析和糟糕的项目计划,因此准备工作就倾向于集中改进需求分析和项目规划。
- Causes Of IncompletePreparation
准备不周全的诱因
造成准备工作不充分的一个常见的原因是,那些分配去做前期准备活动的开发人员并不具备完成这一任务的专业技能。当开发人员不知道如何进行这些前期工作的时候,建议“做更多的前期工作”就完全没有用:如果不能首先把这项工作做好,那么做再多也没有意义!
有一些程序员确实知道如何进行前期工作,但是他们并没有做,因为他们不能够抵抗“尽快开始编码”的欲望。如果你也是这样,我有两条建议:第一:阅读下一节中的争论,它也许能告诉你一些你以前没有想到的问题;第二,注意一下你经历过的问题。只需要做几个大项目,你就能体会到:事先做好计划能避免很多压力。
程序员不做准备工作的最后一个原因是,管理者们队那些“花时间进行构建活动的前期准备的程序员”的冷漠已经到了人神公愤的程度。你可以期望,管理着们应该已经开始明白:软件开发不仅仅是写代码。
- Utterly Compelling and Foolproof Argument for Doing Prerequisites Before Construction
关于开始构建之前要做前期准备的绝对有力且简明的论据
Appeal to Logic 诉诸逻辑
进行有效编程的要领之一是:准备工作很重要。在开始做一个大项目之前,应该为这个项目制定计划,这是很有意义的。从管理的角度看,做计划意味着确定项目所需要用的时间、人数以及计算机台数。从技术角度讲,做计划意味着弄清楚你想要建造的是什么,以防止浪费钱去建造错误的东西。有时候用户在一开始并不完全清楚自己想要的是什么,因此值得花费比理想情况下更多的力气,找出他们真正想要的东西。但这至少比“先做一个错误的东西出来,然后扔掉,并从头来过”的成本要低廉
在开始动手制作这个系统之前,先好好思考打算如何去做,这也非常重要。你总部希望花费很多的时间和金钱,却毫无必要地走进死胡同(尤其当这样做会增加成本的时候)
Appeal to Analogy 诉诸类比
程序员是软件食物链的最后一环。架构师吃掉需求,设计师吃掉架构,而程序员则消化设计。
Appeal to Data 诉诸数据
过去25年来的研究确凿地证明了,在一开始就把事物做好是最合算的。进行非必要的改动的代价是高昂的。
Boss-Readiness Test “老板就绪”测试
如果你的老板已经明白了“在开始构建之前进行前期准备”的重要性,那么试试以下的测试,以确保他确实明白了。
下面的句子哪些是自我实现的语言(sel-fulfilling prophecies)
- 我们最好立刻开始编码,因为将会有很多的调试工作需要去做。
- 我们并没有为测试安排太多的时间,因为将来不会发现多少缺陷
- 我们已经非常详细地研究了需求和设计,我想不出在编码和调试期间还会遇到什么大的问题
上面这些陈述都是自我实现的语言,要瞄准最后那个。
3.2 Determine the Kind of Software You‘re Working on 辨明你所从事的软件的类型
软 件 种 类 |
| 商业系统 | 使命攸关的系统 | 性命攸关的嵌入式系统 |
典型应用 |
Internet站点 Intranet站点 库存管理 游戏 游戏 管理信息系统(MIS) 工资系统 |
嵌入式软件 游戏 Internet站点 盒装软件 软件工具 Web service |
航空软件 嵌入式软件 医疗设备 操作系统 盒装软件 |
生命周期模型 |
敏捷开发(极限编程,Srum, time-box, 开发等等) 渐进原型(prototyping) |
分阶段交付 渐进交付 螺旋式开发 |
分阶段交付 螺旋式开发 渐进交付 |
计划与管理 |
增量式项目计划 随需测试与QA计划 非正式的变更控制 |
基本的预先计划 基本的测试计划 随需QA计划 正式的变更控制 |
充分的预先计划 充分的测试计划 充分的QA计划 严格的变更控制 |
需求 |
非形式化的需求规格 |
半形式化的需求 随需的需求评审 |
形式化的需求规格 形式化的需求检查 |
设计 |
设计与编码时结合的 |
架构设计 非形式化的详细设计 随需的设计评审 |
架构设计 形式化的架构检查 形式化的详细设计 形式化的详细设计检查 |
构建 |
结对编程或独立编码 非正式的check-in手续或没有check-in手续 |
结对编程或独立编码 非正式的check-in 随需代码评审 |
结对编程或独立编码 正式的check-in手续 正式的代码检查 |
测试与QA |
开发者测试自己的代码 测试先行开发 很少或没有测试(由单独的测试小组来做) |
开发者自己测试自己的代码 测试先行开发 单独的测试小组 |
开发者测试自己的代码 测试先行开发 单独的测试小组 单独的QA小组 |
部署 |
非正式的部署过程 |
正式的部署过程 |
正式的部署过程 |
- Iterative Approaches‘ Effect on Prerequisites
迭代开发对前期准备的影响
迭代方法往往能够减少“前期准备不足”造成的负面影响,但是它不能完全消除次影响。
- Choosing Between Iterative and Sequential Approaches
在序列式开发法和迭代式开发法之间做出选择
你可能因为下列原因选择一个更加序列化的方法
- 需求相当文档
- 设计直接了当,而且理解透彻
- 开发团队对于这一应用领域非常熟悉
- 项目的风险很小
- "长期可预测性"很重要
- 后期改变需求、设计和编码的代价可能较昂贵
你可能因为下列原因选择一个更加迭代(as you go,走着瞧)的方法
- 需求并没有被理解透彻,或者处于其他理由你认为它是不稳定的
- 设计很复杂,或者有挑战性,或者两者兼具
- 开发团队对于这一应用领域不熟悉
- 项目包含许多风险
- “长期可预测性”不重要
- 后期改变需求,设计和编码的代价很可能较低
事实上,在软件开发中,适用迭代开发法的情况比使用序列开发法的情况多得多。你应该首先确定哪些前期准备活动适合你的项目。有些项目在前期准备上面花的时间太少了,结果使得在构建活动中遇到大量不必要的反复修改,同时阻碍了项目的稳步前进。有些项目则预先作了太多的事情,固执地坚持原有的需求和计划,后来事实证明这些需求和计划是无效的,这同样阻止了构建活动的顺利进展。
3.3 Problem-Definition Prerequisite 问题定义的先决条件
在开始构建之前,首先要满足的一项先决条件是,对于这个系统要解决的问题作出清楚的陈述
问题定义应该用客户的语言来书写,而且应该从客户的角度来描述问题。通常不应该用计算机的专业术语叙述。这条规则也有例外,那就是解决的就是与计算机本身相关的问题:编译时间太长,或者开发工具bug太多。这种情况下使用计算机术语或程序员术语来陈述问题是恰当的。
"未能定义问题"的处罚是,你浪费了大量时间去解决错误的问题。这是双重处罚,因为你也没有解决正确的问题