程序员修炼之道——第二章 注重实效的哲学(二)

注重实效

  1. 重复的危害: 别做重复的事
  2. 正交性:
    – 按模块进行开发,每个模块负责该模块的部分,不要将其扩展到其他模块。
    – 将对代码有侵略的第三方接口统一封装成统一格式提高复用性。
  3. 可撤销性 :将对代码有侵略的第三方接口统一封装成统一格式提高复用性、不存在最终决策
  4. 曳光弹:对比原型更像一个框架,这个框架是你给客户和开发者演示的框架,你继续给框架增加新的功能,完成预留了接口的例程。但框架仍保持完整,而你也知道,系统将会继续按照你第一次的曳光代码完成时的方式工作。读者认为: 曳光弹就是把你将要实现的模块 首先分好模块,按最简单的实现的方式,组合在一起,连同最后的部署环境,测试环境,都先整体的写一个框架,能跑起来后将这个框架进行完善。
  5. 原型与便笺(jian): 原型的作用在于学到经验教训,找到用户想要的方向
  6. 领域语言: 自己看,读者没理解
  7. 估算:各个时间段估算的方法都不相同。

可撤销性

如果某个想法是你唯一的想法,再没有比这更危险的事了。
工程师喜欢简单、单一的解决方案,与论述一篇法国大革命间的模糊的文章相比, 宣称x=2的数学测试要简单的多。管理者也与工程师趣味相投:单一、简单的答案放在电子表格和项目计划中。
现实世界合作就好了,遗憾的是x今天是2 ,明天是 4 ,后天是5,没有什么永久不变——如果你严重依赖某一事实,你几乎可以确定他会发生改变。
要实现某种东西,总有不止一种方式,而且通常有不止一家供应商可以提供第三方产品。如果你参与的项目被短视的、认为只有一种实现方式的观念所羁绊,你就会遇到各种让人不悦的事情发生。许多项目团队会被迫在未来展现之时睁开眼睛:
“但你说过我们要使用XYZ数据库!我们的编码已经完成了85%的编码工作。我们现在不应该改变了!”程序员抗议道。“但是对不起我们公司决定标准化,改用PHD数据库——所有项目。这超出了我的职权范围。我们必须所有人加班,知道另行通知为止”
变动不一定如此严苛,甚至不会如此迫在眉睫。但随着时间的流逝,随着你的项目取得进展,你也许会发现,你深陷在无法立足的境地,随着每一项关键决策的做出,项目团队受到越来越小的目标约束——更加窄小的版本,更少的选择余地。
在许多关键路径做出之后,目标会变得如此之小,以至于如果它动一下,或者风改变方向,或者东京的蝴蝶翅膀发生震动,你就会错过目标。而且会偏出很远。
问题在于,关键路径不容易撤销
一旦你决定使用这家供应商的数据库,那种架构模式,或是特定的部署模式,除非付出极大的代价,否则你就限制于一个无法撤销的的动作进程。

可撤销性

DRY原则、解耦以及元数据的使用——我们不必做出许多关键的、不可逆转的决策。这是一件好事,因为我们并非总能在一开始就做出最好的决策。我们采用了某种技术,却发现我们雇不到足够的具有必需技能的人。我们刚刚选定某个第三方供应商,他们就被竞争者收购,与我们开发软件的速度相比,需求、用户以及硬件的变化得更快。
假定在项目初期,你决定使用供应商A提供的关系数据库。过了很久,在性能测试过程中,你发现数据库简直太慢了,而供应商B提供的对象数据库更快,对于大多数传统项目,你不会有什么运气。大多数的时候,对第三方产品的调用都缠绕在代码各处。但是如果你真正把数据库的概念抽象出来——抽象到数据库只是把持久作为服务提供出来的程度——你就会拥有“中流换马”的灵活性。
与此类似,假定项目最初采用的是客户——服务器模型,但随即,在开发的后期,市场部门认为服务器对于某些客户过于昂贵,他们想要单机版。对你来说,那会有多困难?因为这只是一个部署的问题,所以不应该要许多天。如果所需时间更长,那么你就没有考虑过可撤销性。另一个方向甚至更有趣。如果你需要以客户——服务器或n层方式部署你正在开发的单机产品,事情又应该是怎样?那也不应该很困难。
错误在于假定决策是浇筑在石头上的——同时还没有为可能出现的意外事件做准备。
要把决策视为写在沙滩上的,而不要把他们刻在石头上。大浪随时可能到来,把它们抹去。
不存在最终决策

灵活的架构

有许多人会设法保持代码的灵活性,而你还需要考虑维持架构、部署及供应商继承等领域的灵活性。
像CORBA这样的技术可以帮助把项目的某些部分与开发语言或者平台隔离开来。Java在该平台上的性能能不能满足要求?重新用C++编写客户代码,其他没有什么需要改变。用C++编写规则引擎不够灵活?换到Smalltalk版本。采用CORBA架构,你只需要改动替换的组件:其他组件应该不会受到影响。
你正在开发UNIX软件?哪一种?你是否处理了所有可移植性的问题?你正在为某个特定版本的Windows做开发?哪一种——3.1、95、98、NT、CE或是2000?支持其他版本有多难呢?如何让决策保持软和与柔韧,事情就完全不困难。如果在代码中有着糟糕的封装、高度耦合以及硬编码的逻辑或参数,事情也许就不可能的。
不确定市场部门想怎样部署系统?预先考虑这个问题,你可以支持单机、客户-服务器、或n层模式——只需要改变配置文件。我们就写过一些这么做的程序。
通常,你可以把第三方产品隐藏在定义良好的抽象接口后面。事实上,在我们做过的任何项目中,我们都总能够这么做。但假定你无法那么彻底地隔离它,如果你必须大量地把某些语句分散在整个代码中,该怎么办?把该需求放入元数据,并且使用某种机制——比如Aspect ——把必需的语句插入代码自身中,无论你使用的是何种机制,让它可撤销, 如果某样东西是自动添加的,它可以被自动去掉。

曳光弹

预备、开火、瞄准…
在黑暗中用机枪射击有两种方式,你可以找出目标的确切位置(射程、仰角及方位)。你可以确定环境温度状况(温度、湿度、气压、风,等等)。你可以确定你使用的弹药筒和子弹的精确规格,以及它们与你使用的机枪的交互作用。然后你可以用计算表或射击计算机计算枪管的确切方向及仰角。如果每一样东西都严格按照规定的方式工作,你的计算表正确无误,而且环境没有发生变化,你的子弹应该落在目标不远的地方。
或者,你可以使用曳光弹。
曳光弹与常规弹药交错着装在弹药带上。发射时,曳光弹中的磷点燃,在枪与它们击中的地方留下一条烟火般的踪迹,如果曳光弹击中目标,那么常规子弹也会击中目标。
并不让人惊奇的是,曳光弹比费力计算更可取,因为反馈是即时的,而且因为它们工作在与真正的弹药相同的环境中,外部影响得以降低至最低。
这个类比也许有点暴力,但它适用于新的项目,特别是当你构建从未构建过的东西时。与枪手一样,你也许设法在黑暗中击中目标。因为你的用户从未见过这样的系统,他们的需求可能会含糊不清,因为你在使用不熟悉的算法、技术语言或者是库,你面对着大量未知的事物。同时,因为完成项目需要时间,在很大程度上你能确知,你的工作环境将在你完成之前发生变化。
经典的做法是把系统定死,制作大量的文档,逐一列出每项需求、确定所有未知因素、并限定环境。根据死的计算射击。预先进行一次大量计算,然后射击并企望击中目标。
然而,注重实效性的程序员更喜欢用曳光弹。

在黑暗中发光的代码。

曳光弹行之有效,是因为它们与真正的子弹在相同的环境、相同的约束下工作,他们快速飞向目标,所以枪手可以得到即时反馈,同时,从实践的角度看,这样的解决方案也便宜。
为了在代码中获得同样的效果,我们要找到某种东西,让我们能快速、直观和可重复地从需求出发,满足最终系统的某个方面的需求。
用曳光弹找到目标
有一次,我们接受了一个复杂的客户——服务器数据库营销项目。其部分需求是要能够指定并执行临时查询。服务器是一系列专用的关系数据库。用Object Pascal 编写的客户GUI使用一组C库提供给服务器的接口。在转化为优化的sql之前,用户的类似以Lisp的表示方式存储在服务器上;转换直到执行前才进行。有许多未知因素和许多不同的环境,没有人清楚的知道GUI应该怎样的工作。
这是使用曳光代码的好机会。我们开发了前端框架、用于表示查询的库以及用于把所存储的查询转换为具体数据库的查询结构。随后我们把它们集中在一起,并检查他们是否能工作。使最初构建的系统,我们所能做的只是提交一个查询,列出某个表中的所有行,但它证明了UI能够与库交谈,库能够对查询进行序列化和解序列化,而服务器能够根据结果生成SQL。在接下来的几个月内里,我们逐渐充实这个基本结构,通过并行地扩大曳光弹代码的各个组件增加新的功能。当UI增加了新的查询类型时。库随之成长,而我们也使用SQL生成变得成熟。
曳光弹代码并非用过就扔的代码:你编写它,是为了保留它。它含有任何一段产品代码都拥有的完整的错误检查、结构、文档、以及自查。它只不过功能不全而已。但是,一旦你在系统的各组件间实现了端到端(end-to-end)的连接,你就可以检查你离目标有多远。并在必要的情况下进行调整:一旦你完全瞄准,增加功能将是一件容易的事情。
曳光开发与项目永不回结束的理念是一致的:总有改动需要完成,总有功能需要增加。这是一个渐进的过程。
另一种传统做法是一种繁重的工程方法:把代码划分为模块,在真空中对模块进行编码。把模块组合成子配件,再对子配件进行组合,直到有一天你拥有完整的应用为止。直到那时,才能把应用作为一个整体呈现给用户,并进行测试。
曳光代码方法有许多优点:
**用户能够及早看到能工作的东西。**如果你成功地就你在做的事情与用户进行了交流,用户就知道他们看到的是还未完成的东西,他们不会因为缺少功能而失望;他们将因为看到了系统的某种可见的进展而欣喜陶醉。他们还会随着项目的进展做出贡献,增加他们的“买入”。同样是这些用户,他们很可能告诉你,每一轮“射击”距离目标有多接近。
开发者构建了一个他们能在其中工作的结构。最令人畏缩的纸是什么都没有写的白纸。如果你已经找出应用的所有端到端的交互,并把它们体现在代码里,你的团队就无须再无中生有。让每个人都变得更有生产力,同时又促进了一致性。
你拥有了一个集成平台。 随着系统端到端地连接起来,你拥有了一个环境,一旦新的代码段通过了单元测试,你就可以将其加入到该环境中。你将每天进行集成(常常是一天多次),而不是尝试进行大爆炸式的集成。每一次新改动的影响都更为显而易见,而交互也更为有限,于是调试和测试变得更快、更准确。
你有了可演示的东西。项目出资人与高级官员往往会在最不方便的时候来看演示,有了曳光代码,你总有东西可以拿给他们看。
你将更能感觉到工作进展,在曳光代码中,开发者一个一个地处理用例(use case)。做完一个,再做下一个,评测性能,并向用户演示你的进展,变得容易了许多,因为每一项个别的开发都更小。你也避免了创建这样的整体代码块:一周又一周,其完成度一直是95%。

曳光弹并非总能击中目标

曳光弹告诉你击中的是什么。那不一定总是目标,于是你调整准星,直到完全击中目标为止,这正是要点所在。
曳光代码也是如此。你在不能100%确定该去往何处的情形下使用这项技术。如果最初的几次尝试错过了目标——用户说:“那不是我的意思”,你需要的数据在你需要它时不可用,或是性能好像有问题——你不应该感到惊奇。**找出怎样改变已有的东西,让其更接近目标的方法,并且为你使用一种简约的开发方法而感到高兴。**小段代码的惯性也更小——要改变它也更容易、更迅速。你能够搜集关于你的应用的反馈,而且与其他任何方法相比,你能够花费较少代价,更为迅速生成新的、更为准确的版本。同时,因为每个主要的应用组件都已表现在你的曳光代码中,用户可以确信,他们所看到的东西具有现实基础,不仅仅是纸上的规范。

曳光代码 VS. 原型制作

你也许会想,这种曳光代码制作就是原型制作,只不过有一个更富“进攻性”的名字。它们有区别。使用原型,你是要探究最终系统的某些具体的方面。使用真正的原型,在对概念进行了试验之后,你会把你捆扎在一起的东西扔掉,并根据你学到的经验教训重新适当的编码。
例如,假定你在制作一个应用,其用途是帮助运货人确定怎么把不规则的箱子装入集装箱。除了考虑其他一些问题,你还要设计直观的用户界面,而你用与确定最优集装箱方式的算法非常复杂。
你可以在GUI工具中为最终用户制作一个用户界面原型。你的代码只能让界面响应用户操作,一旦用户对界面布局表示同意,你可以把它扔掉,用目标语言重新对其进行编码,并在其后加上商业逻辑
曳光代码方法处理的是不同的问题。你需要知道应用怎样结合成一个整体。你想向用户展示。实际的交互式怎样工作的,同时你还要给出一个骨架代码,开发者可以在其上增加代码,在这样的情况下,**你可以构造一段曳光代码,其中含有一个及其简单却能工作的用户界面。**一旦你把应用中的所有组件都组合在一起,你就拥有了一个可以向你的用户和开发者演示的框架。接下来的时间里,你给这个框架增加新功能,完成预留了接口的例程。但框架仍保持完整,而你也知道,系统将会按照你第一次曳光代码完成时的方式工作。

读者认为: 就是把你将要实现的模块 首先分好模块,按最简单的实现的方式,组合在一起,连同最后的部署环境,测试环境,都先整体的写一个框架,能跑起来后将这个框架进行完善。

其间的区别很重要,足以让我们再重复一次。原型制作生成就扔的代码。曳光代码虽然简约,但却是完整的,并且构成了最终系统的骨架的一部分。你可以把原型制作视为在第一曳光弹发射之前的侦察和情报搜集工作。

原型与便笺(jian)

许多不同的行业都使用原型试验具体的想法:与完全的制作相比,制作原型要便宜的多 例如轿车制造商可以制造某种新车设计的许多不同的原型,每一种的设计目的都是要测试轿车的某个具体的方面——空气动力学、样式、结构特征,等等。也许会制造一个粘土模型,用于风洞测试,也许会为工艺部门制造一个轻木和胶带模型,等等。有些轿车公司更进一步,在计算机进行大量的建模工作,从而进一步降低了开销。以这样的方式、可以试验危险或不确定的元件,而不用实际进行真实的制造。
我们以同样的方式构建软件原型,并且原因也一样——为了分析和揭示风险,并以大大降低的代价,为修正提供机会。与轿车制造商一样,我们可以把原型用于测试项目的一个或多个具体方面。
我们以同样的方式构建软件原型,并且原因也一样——为了分析和揭示风险,并以大大降低的代价,为修正提供机会。与轿车制造商一样,我们可以把原型用于测试项目的一个或多个具体方面。
我们往往以原型要以代码为基础原型。要为像工作流和应用逻辑这样的动态事物制作原型,便笺就非常好。用户界面的原型则可以是白板上的图形、或是用绘图程序或界面构建器绘制的无功能的模型。
原型的设计目的就是回答一些问题,所以与投入使用的产品相比,它们的开发要便宜的多,快捷得多。其代码可以忽略不重要的细节——在此刻对你不重要。但对后来的用户可能非常重要。例如,你在制作GUI原型,你不会因为不正确的结果或数据而遭到指责。而另一方面,如果你只是在研究计算性能方面的问题,你也不会因为相当糟糕的GUI而遭到指责;甚至也可以完全不要GUI。
但如果你发现自己处在不能放弃细节的环境中,就需要问自己,是否真正的在构建原型。或许曳光弹开发的方式是否更适合这样的方式

应制作原型的事物

你可以选择通过原型来研究什么样的事物呢?任何带有风险的事物。以前没有试过的事物。或是对于最终系统极端关键的事物。任何未被证明、实验性的、或有疑问的事物,任何让你觉得不舒服的事物,你可以为下列事物制作原型:

  • 架构
  • 已有系统中的新功能
  • 外部数据的结构或内容
  • 第三方工具或组件
  • 性能问题
  • 用户界面设计
    原型制作是一种学习经验。其价值并不在于所产生的代码,而在于所学到的经验教训。那才是原型制作的要点所在。

怎样使用原型

在构建原型时,你可以忽略那些细节?

  • 正确性。 你也许可以在适当的地方使用虚设的数据。
  • 完整性。 原型也只能在非常有限的意义上工作,也许只有一项预先选择的输入数据和一个菜单项。
  • 健壮性。错误检查很可能不完整,或是完全没有。如果你偏离预定路径,原型就可能崩溃,并在“烟火般的灿烂显示中焚毁”。这没有关系。
  • 风格。在纸上承认这一点让人痛苦,但原型代码可能没有多少注释或文档。根据使用原型的经验,你也许会撰写大量文档,但关于原型系统自身的内容相对而言却非常少。

因为原型应该遮盖细节,并聚焦于所考虑系统的某些具体方面,你可以用非常高级的语言实现原型。

制作构架原型

许多原型被构造出来,是要为在考虑之下的整个系统建模。与曳光弹不同,在原型系统中,单个模块不需要能行使特定的功能。事实上,要制作架构原型,你甚至不一定需要进行编码——你可以用便笺或索引卡片、在白板上制作原型。你寻求的是了解系统怎样结合成一个整体,并推迟考虑细节。下面是一些你可以在架构原型中寻求解答的具体问题:

  • 主要组件的责任是否得到了良好定义?是否适当?
  • 主要组件间的协作是否得到了良好的定义?
  • 耦合是否得以最小化?
  • 你能否确定重复的潜在来源?
  • 接口定义和各项约束是否可接受?
  • 每个模块在执行过程中是否能访问到其所需要的数据?是否能在需要时进行访问?
    根据我们制作原型的经验,最后一项往往会产生最让人惊讶和最有价值的结果。

怎样不使用原型

在你着手制作任何基于代码原型之前,先确定每个人都理解你正在编写用过就扔的代码,对于不知道那只是原型的人,原型可能会具有欺骗性的吸引力。你必须非常清楚地说明,这些代码就是用过就扔,它们不完整,也不可能完整。
别人很容易被演示原型外表的完整性误导,而如果你没有设定正确的期望值,项目出资人或管理部门可能会坚持要部署原型。提醒他们,你可以用轻木和胶带制造一辆了不起的新车原型,但你却不会在高峰时间的车流中驾驶它。
如果你觉得在你所在的环境或文化中,原型代码的目的很有可能被误解,你也许最好采用曳光弹方法。你最后将会得到一个坚实的框架,为将来的开发奠定基础。
适当的使用原型,可以帮助你在开发周期的早期确定和改正潜在的问题点——在此时改正错误既便宜、又容易——从而为你节省大量时间、金钱,并大大减轻你遭受的痛苦和折磨。

领域语言

语言的界限就是一个人的世界的界限
计算机语言会影响你思考问题的方式,以及你看待交流的方式。每种语言都含有一系列特性——比如静态类型与动态类型、早期绑定与迟后绑定、继承模型(单、多或无)这样的时髦话语——所有这些特性都在提示或遮蔽特定的解决方案。头脑里想着Lisp设计的解决方案将会产生与基于C风格的思考方式而设计的解决方案不同的结果,反之亦然。与此相反——我们认为这更重要——问题领域的语言也可能提示出编程方式。

我们总是设法使用应用领域的语言来编写代码。在某些情况下,我们可以更进一层,采用领域的语汇、语法、语义——语言——实际进行编程。
当你听取某个提议中的系统的用户说明情况时,他们也许能确切地告诉你,系统应该怎样工作:
在一组X.25线路上侦听由ABC规程12.3定义的交易,把它们转译成XYZ公司的43B格式,在卫星上行链路上重新传输,并存储起来,供将来分析使用。
如果用户有一些这样做了良好限定的陈述,你可以发明一种为应用领域进行了适当剪裁的小型语言,确切地表达他们的需要。
无论是用于配置和控制应用程序的简单语言,还是用于指定规则或过程的更为复杂的语言,我们认为,你都应考虑让你的项目更靠近问题领域。通过在更高的抽象层面上编码,你获得了专心领域问题的自由,并且可以忽略琐碎的实现细节。
记住,应用有许多用户。有最终用户,他们了解商业规则和所需输出;也有次级用户:操作人员、配置与测试管理人员、支持与维护程序员,还有将来的开发者。他们都有各自的问题领域,而你可以为他们所有人生成小型环境和语言。

估算

通过56K modem 线发送《战争与和平》 需要多少时间?存储一百万个姓名与地址需要多少时间?存储一百万个姓名与地址需要多少磁盘空间?1000字节的数据块通过路由器需要多少时间?交付你的项目需要多少个月?
在某种程度上,这些都是没有意义的问题——它们都缺少信息。然而它们仍然可以得到回答,只要你习惯于进行估算。同时,在进行估算的过程中,你将会加深对你的程序所处的世界的理解。
通过学习估算,并将此技能发展到你对事物的数量级有直觉的程度,你就能展现出一种魔法般的能力,确定他们的可行性。当你习惯于进行估算。同时,在进行估算的过程中,你将会加深对你的程序所处的世界的理解。
通过学习估算,并将此技能发展到你对事物的数量级有直觉的程度,你就能展现出一种魔法般的能力,确定它们的可行性。当有人说:“我们通过ISDN线路把备份发给中央站点”时,你将能够直觉地知道那是否实际。当你编码时,你将能够知道哪些子系统需要优化,哪些可以放在一边。
估算,以避免发生意外。

多准确才足够准确

在某种程度上,所有的解答都是估算。只不过有些要比其他的更准确。所以当有人要你进行估算时,你要问自己的第一个问题就是,你解答问题的语境是什么?他们是需要高度的准确性,还是在考虑棒球场的大小?

  • 如果你奶奶问你何时到达,她也许只是想知道该给你准备午餐还是晚餐。而一个困在水下,空气就快用光的潜水员可能对精确到秒的答案更感兴趣。
  • Π 的值是多少?如果你 想知道的是买多少饰边,才能把一个花坛围起来,那么3很可能就足够好,如果你在学校里,那么“22/7”也许就是一个很好的值,如果你在NASA,那么也需要12个小数位

关于估算,一件有趣的事情是,你使用的单位会对结果的解读造成影响,如果你说,某件事需要130个工作日,那么大家会期望它在相当接近的时间里完成。但是如果你说“大概六个月”,那么大家知道它会在从现在开始的五个到七个月内完成,这两个数字表示相同的时长,但130却可能暗示了比你的感觉更高的精确程度。
推荐这样估算时间。
在这里插入图片描述
于是,在完成了所有必要的工作之后,你确定项目需要125个工作日,你可以给出大约六个月的估算。
同样的概念适合用任何的估算。

估算来自哪里

所有的估算都以问题的模型为基础,但在我们过深地卷入建模技术之前,我们必须提及一个基本的估算诀窍,它总能给出好的答案:去问已经做过这件事情的人,在你一头钻入建模之前,仔细在周围找找也曾处在类似情况下的人。

理解提问内容

任何估算练习的第一步都是建立对提问内容的理解,除了上面讨论精确度问题以外,你还需要把握问题域的范围。这常常隐含在提问中,但你需要养成在开始猜想之前先思考范围的习惯。常常,你选择的范围将形成你给出解答的一部分:”假定没有交通意外,而且车里还有汽油,我们会在20分钟内赶到那里。“

建立系统的模型

这是估算有趣的部分。根据你所提问题的理解,建立粗略、就绪的思维模型骨架。如果你是在估算响应时间,你的模型也许涉及服务器和某种到达流量。对于一个项目,模型可以是你的组织在开发过程中所用的步骤、以及系统的实现方式的非常粗略的图景。
建模既可以是创造性的,又可以是长期有用的。在建模的过程中,你常常会发现一些在表面上不明显的底层模型和过程。但好像X的变种Y只需一半时间就能完成,而你只会损失一个特性。
建模把不精确性引入了估算过程中。这是不可避免地,而且也是有益的。你是在用模型的简单性与精确性做交易。在花在模型上的努力加倍也许只能带来精确性的轻微挺高。你的经验将会告诉你何时停止提炼。

把模型分解为组件

一旦拥有了模型,你可以把它分解为组件。你须要找出描述这些组件怎样交互的数学规则。有时某个组件会提供一个值,加入到结果中。有些组件有着成倍的影响,而另一些可能会更为复杂。
你将会发现,在典型情况下,每个组件都有一些参数,会把它给整个模型带来造成影响, 在这一个阶段,只需要确定每个参数就行了。

给每个参数指定值

一旦你分解各个参数,你就可以逐一给每个参数赋值。在这个步骤你可能会引入一些错误。诀窍是找出哪些参数对结果的影响最大,并致力于让它们大致正确。

估算项目进度

在面对相当大的应用开发的各种复杂问题与反复无常的情况下,普通的估算规则可能失效。我们发现,为项目确定进度表的唯一途径常常在相同的项目上获取经验。如果你实行增量开发、重复下面的步骤,这不一定就是一个悖论:

  • 检查需求
  • 分析风险
  • 设计、实现、集成
  • 向用户确认
    一开始,你对需要多少次迭代,或是需要多少时间,也许只有模糊的概念。有些方法要求你把这个作为初始计划的一部分定下来,但除了最微不足道的项目,这是一个错误。除非你在开发之前一个应用类似的应用,拥有同样的团队和同样的技术,否则,你就只不过在猜想。
    于是你完成了初始功能的编码与测试,并将此标记为第一轮增量开发的结束。基于这样的经验,你可以提炼出你原来对迭代次数、以及在每次迭代中可以包含的内容的猜想。提炼会变得一次比一次好,对进度表的信息也随之增长。
    这也许并不会受到管理部门的欢迎,在典型情况下,他们想要的是单一的,必须遵守的数字——甚至是在项目开始之前。你必须帮助他们了解团队、团队的生产率、还有环境将决定进度,通过使其形式化**,并把进度表作为每次迭代的一部分,你将给予他们你所能给予的最精确的进度估算。**

在被要求进行估算时说什么

如果你放慢估算的速度,并花一点时间仔细检查我们在这一节描述的步骤,你几乎总能得到更好的结果。在咖啡机旁给出的估算将回来纠缠你。

发布了144 篇原创文章 · 获赞 3 · 访问量 9514

猜你喜欢

转载自blog.csdn.net/NumberOneStudent/article/details/103803880
今日推荐