程序员修炼之道——第七章 在项目开始之前

在项目开始之前

你是否曾经有过你的项目注定要失败的感觉,甚至是在项目启动之前?有时它也许会这样,除非你先建立某些基本准则。否则,也许你现在就可以建议结束它,并且给出资人省下一些钱。
在项目的最开始,你需要确定各种需求。只是听取用户的意见还不够,去阅读“需求之坑”,以了解更多的相关信息。
传统智慧和约束管理是解开不可能解开的谜题的话题。不管你是在做需求、分析、编码,还是在测试,都会遇到各种难题。大多数时候,它们其实不像最初看起来那么困难。
当你认为你已经解决了问题时,你可能仍然觉得不能启动项目。这只是在拖延,还是别有含义?“等你准备好”将告诉你,何时倾听你头脑里发出的告诫声是谨慎之举。
启动太快是一个问题,但等得太久可能会更糟。在“规范陷阱”中,我们将通过例子讨论规范的各种优点。
最后,我们将在圆圈与箭头中考察各种形式开发过程和方法学的一些缺陷。不管它经过了多么详细的考虑,也不管它包括了哪些最佳实践,没有办法能够取代思考。
在项目启动之前把这些关键问题解决好,你就能更好地避免“分析瘫痪”,并实际开始你的成功项目。

需求之坑

挖掘需求

当你在尘土里四处挖掘时,你怎样才能识别出真实的需求?答案即简单又复杂。
简单的回答是,需求是对需要完成的某件事情的陈述,以下陈述是好需求:

  • 只有指定人员才能查看员工档案。
  • 汽缸盖的温度不能超过临界值,该值因引擎而异
  • 编辑器将凸显关键词,这些关键词根据正在编辑二点文件的类型确定。

但是,极少有需求像这样明了,这也正是需求分析很复杂的原因。
用户可能会这样陈述上面列出的第一条陈述:“只有员工的上级和人事部门才可以查看员工的档案。‘这个陈述真的是需求吗?今天也许是,但它在绝对的陈述中嵌入了商业政策,政策会经常改变,所以我们可能并不想把它们硬性地写入我们的需求。我们的建议是,并把政策信息作为例子发给开发者——他们需要在支持的事务的例子。最后,政策可以成为应用中的元数据。
这是一种相对微妙的区别,但对开发者却有着深远的影响。如果需求被陈述为”只有人事部门才能查看员工档案“,开发者最后就可能会编写代码,在每次应用访问这些文件时进行明确的检查。但是,如果陈述是”只有得到授权的用户可以访问员工档案“,开发者就可能会设计并实现某种访问控制系统。当政策改变时,只有该系统的元数据需要更新。事实上,以这样的方式搜集需求会自然地让你去开发为支持元数据而进行了良好分解的系统。
在讨论用户界面时,需求、政策和实现之间的区别可能会变得非常模糊。”系统必须能让你选择贷款期限“是对需求的陈述。”我们需要一个列表框,以选择贷款期限“可能是,也可能不是。如果用户一定要有列表框,那么它就是需求。相反,如果他们是在描述选择能力,但只是用列表框做例子,这个陈述就可能不是需求。页的方框将讨论一个因为忽略用户的界面需要而生产严重问题的项目。
找出用户为何要做特定事情的原因、而不只是他们目前做这件事情的方式,这很重要。到最后,你的开发必须解决他们的商业问题,而不只是满足他们陈述的需求。用文档记载需求背后的原因将在每天进行实现决策时给你的团队带来无价的信息。
与用户一同工作,像用户一样思考。

建立需求文档

你会把它们写下来,并发布每个人都可以用作讨论基础的文档——开发者、最终用户、以及项目出资人。
听众的范围相当广泛。
把形式化的模板用作备忘录,你可以确保自己包括了用例中所需的所有信息。 比如:”哦,我们必须做YYY,除非我们能满足xxx条件“。
在这里插入图片描述

用例图

可以用UML活动图捕捉工作流,而且有时要为手边的事务建模,概念层类图很有用。
在这里插入图片描述

规定过度

制作需求文档时的一大危险时太具体。好的需求文档会保持抽象。在涉及需求的地方,最简单的,能够准确地反映商业需求的陈述是最好的。这病非意味着你可以含糊不清——你必须把底层的语义不变项当作捕捉,并把具体的或当前的工作实践当作政策计入文档。
需求不是架构。需求不是设计,也不是用户界面,需求是需要。

看远些

需求将只规定要使用日期。它也许会示意,可以对日期进行某些数学运算。它也许慧告诉你,日期将被存储在各种形式的辅助存储器上,这些陈述时关于date模块或是类的真正需求。

再抹一层薄薄的薄荷

许多项目的失败都被归咎于项目范围的增大——也称为特性膨胀,蔓延特性论、或是需求蔓延。这是”石头汤与煮青蛙“中煮青蛙综合症的一个表征。我们要做些什么。才能防止需求悄悄地蔓延到我们身上呢?
在各种文献中,你会找到对许多度量方式的描述,比如报告与修正的bug、缺陷密度、内聚、耦合、功能点、代码行数,等等。可以通过手工或软件方式追踪这些度量。
遗憾的是,积极地追踪需求的项目似乎并不是很多,这意味着,它们无法报告范围的变化——谁请求增加新特性、谁批谁的、批准的请求总数是多少,等等。
管理需求增长的关键是向项目出资人指出每项新特性对项目进度的影响。当项目已经拖后了一年,各种责难可使纷飞时,能够准确、完整地了解需求增长是怎样及时发生的,会很有帮助。
我们很容易被吸进”只是再增加一个特性“的大漩涡,完整地了解需求增长是怎样及何时发生的,会很有帮助。
只是再增加一个特性,其实已经是本月新增的第15个新特性。

维护词汇表

一旦开始讨论需求,用户和领导专家就会使用对他们有特定含义的术语。例如,他们可能会区分”客户“和”顾客“。于是,再在系统中随意使用这两个词就是不合适的
要创建并维护项目词汇表——这是定义项目中使用的专用术语和词汇的地方。项目的所有参与者,从最终用户到支持人员,都应该使用这个词汇表,以保证一致性。这就意味着,可以访问词汇表的人员范围应该很广泛——这是基于Web文档的一个有效论据。

把话说出来

在全都是写中我们将会讨论怎样把项目文档发布到内部的网站上去,以方便所有参与者的访问。这种发布的方法对于需求文档特别有用。
通过把需求制作成超文本文档,我们可以更好地满足不同听众的需要——我们可以给每个读者他们想要的东西。项目出资人可以在更高层的抽象层面上巡视,以确保商业目标得以实现。程序员可以使用超链接”钻入“越来越深的细节中。

解开不可能解开的谜题

不时地,你会发现自己与一个遇到了非常困难的”谜题“的i昂木牵连在一起:某项工程设计你就是找不到头绪,或是你发现有些代码比你想象得要难以编写得多。也许它看起来不可能解决的。但它真的有看上去那么困难吗?
考虑现实世界的谜题——那些好像是作为圣诞礼物、或是从旧货市场突然出现的形状奇特的小木块、锻铁、或是塑料。你要做的全部事件就是拿掉铁环、或是T形块放进盒子里,等等。
于是你拉动铁环,或是试着把T形块放进盒子,并且很快发现明显的解决方法没有用。你无法像以前那样解开谜题。但即使这很明显,人们也仍然会继续尝试同样的事情——一次又一次——并且认为那样肯定能行。
当然不行。解决方法在另外的地方。解开这个谜题的秘结是确定真正的(而不是想象)约束,并在其中找出解决方法。有些约束是绝对的;有些则只是先入之见。绝对的约束必须受到尊重,不管它们开上去有多讨厌或多愚蠢。另一方面,有些外表上的约束也许根本不是真正的约束。例如,有一个酒吧里的老把戏:你拿一瓶全新的、未开启的香槟酒,打赌说你可以从中喝出啤酒来。诀窍是把酒瓶倒过来,在瓶底的凹处倒一点啤酒。许多软件问题都可能具有相同的欺骗性。

自由度

流行的俗话”在盒子外面思考“鼓励我们找出可能不适用的约束,并忽略它们。但这个俗话并不能完全准确。如果”盒子”是各种约束和条件的边界,那么诀窍就在于找到盒子——它可能比你以为的要大得多。
解开谜题的关键在于确定加给你各种约束,并确定你确实拥有的自由度,因为在其中你将到你解决方案。这也是有些谜题为何如此有效的原因;你可能会太快就排除了潜在的解决方案。
在面对棘手的问题时,列出所有在面前的可能途径。不要排除任何东西,不管它听起来有多无用或愚蠢。现在,逐一检查列表中的每一项,并解释为何不能采用某个特定的途径。你确定吗?你能否证明?
想一想特洛伊木马——一个棘手问题的新奇解法。你怎样让军队潜入城池,而又不被发现呢?你可以打赌,“走前门”一开始就作为自杀行为而被排除了。
对你的各种约束进行分类,并划定优先级。木匠开始做活路时,会首先锯出最长的木料,然后再从剩下的木头中锯出较小的木料。按照同样的方式,我们想先确定最为严格的约束,然后再在其中考虑其余的约束。

一定有更容易的方法!

有时你会发现,自己在处理的问题似乎比你以为的要难得多。感觉上好像是你走错了路——一定有比这更容易地方法!或许现在你已落在了进度表后面,甚或失去了让系统工作起来的信心,因为这个特定的问题是“不可能解决的”

  • 有更容易地方法吗?
  • 你是在设法解决真正的问题,还是被外围的技术问题转移了注意力?
  • 这件事为什么是一个问题?
  • 是什么使它如此难以解决?
  • 它必须以这种方式完成吗?
  • 它真的必须完成吗?

等你准备好

了不起的表演者有一个共同的特征:他们知道何时开始,何时等待。跳水运动员站在高台上,等待完美的时刻起跳/指挥站在乐队前面,举起手臂,知道它感觉到某个瞬间适用于开始演奏。
你是一个了不起的表演者。你也需要倾听内心的低语声:“等一等”。如果你坐下来,开始敲击键盘,在你的头脑里反复出现某种疑虑,要注意它。
以前有一种网球训练方法,叫做“内在的网球”。你要花上数小时击球过网,并不特意追求准确性,而是用语言描述球击中的地方与某个目标的相对位置。其思想是反馈会训练你的下意识和反应能力,于是你的球技就会得到提高,而又无需有意识地了解怎样提高或为何能提高。
作为开发者,你在整个职业生涯中都在做同样的事情。你一直在试验各种东西,看哪些可以,哪些不可以。你一直在积累经验与智慧。当你面对一件任务时,如果你反复感觉到疑虑,或是体验到某种勉强,要注意它,你可能无法准确地指出问题所在,但给它是时间,你的疑虑很可能会结晶成为某种更坚实的东西,某种你可以处理的东西。软件开发仍然不是科学。让你的直觉为你的表演做出贡献。

是良好的判断,还是拖延

每个人都害怕空白的纸页。启动新项目(或是已有项目中的新模块)可能回事让人身心交瘁的经验。我们许多人更愿意延缓做出最初的启动承诺。那么,你怎样才能知道,你什么时候是在拖延,而不是在负责地等待所有工作准备就绪?
在这样的情形下,我们采用的一种行之有效的技术是开始构建原型。选择一个你觉得会有困难的地方,开始进行某种“概念验证”。在典型情况下,可能会发生两种情况。一种情况是,开始后不久,你可能就觉得自己是在浪费时间这种厌烦可能很好地表明,你最初的勉强只是希望推迟启动。放弃原型,回到真正的开发中。
另一种情况是,随着原型取得进展,你可能会在某个时刻得到启示,突然意识到有些基本的前提错了。不仅如此,你还将清楚地看到可以怎样纠正错误。你将会愉快地放弃原型,投入正常的项目。你的直觉是对的,你为你自己和你的团队节省了可观的,本来会浪费的努力。
当你做出决定,把构建原型当作调查你的不适的一种方法时,一定要记住你为何这样做。你最不想看到的事情是,你花了几个星期认真地进行开发,然后才想起你一开始只是要写一个原型。

规范陷阱

编写程序规范就是把需求规约到程序员能够接管的程序的过程。这是一个交流活动,旨在解释并澄清系统的需求,比如消除主要的歧义,除了最初实现的开发者交谈之外,规范还是留给未来进行维护和增强的几批程序员的记录。规范也是用户的约定——是对他们的需求的汇编,也是一份隐含的合约:最终系统将会符合该合约的要求。
编写规范是一项重要职责。
问题是许多设计者发现很难停下来。他们觉得,他们不应领取每日的薪水,除非每一处小细节都极端详细地确定下来。
这是一个错误,原因如下:首先,认为规范将捕捉系统或其需求的每一处细节和细微差别,这很幼稚。在受限的问题领域中,有一些形式方法能对系统进行描述,但他们仍然要设计者向最终用户解释该表示方法的含义——人的解释仍然会搅乱事情。即使这样的解释中的固有问题并不存在,一般用户也可能无法说出他们的所需系统。他们可能会说,他们已经理解了需求,他们可能会在你制作的200页的文档上签字,但你可以确信,一旦他们看到运行的系统,你就会被各种变更要求淹没。
其次,语言自身的表达能力存在着问题。所有的图示技术和形式方法都仍然依赖于用自然语言表达要进行的操作,而自然语言实在不能胜任这项工作,看一看任何合约的措词:为了进行精确的表达,律师不得不以最不自然的方式扭曲语言。
这里有一个挑战:写一份简短的描述,告诉别人怎样系鞋带。
对于有些事情“做”胜于“描述”
最后,还有“紧身衣效应”。没有给编码者留下任何解释余地的设计剥夺了他们发挥技巧和艺术才能的权利。
作为注重实效的程序员,你应该倾向于把需求搜集、设计、以及实现视为同一个过程——交付高质量的系统——的不同方面。不要信任这样的环境:搜集需求、编写规范、然后开始编码、所有这些步骤都是孤立进行的,相反,要设计采用无缝的方法:规范和实现不过是同一个过程——设法捕捉和编纂需求——的不同方面。每一步都应该直接流入写一步,没有人为制造的界限。你将会发现,健康的开发过程鼓励把来自实现与测试的意见反馈到规范中。

圆圈与箭头

从结构化程序设计开始,经过主程序员团队、CASE工具、瀑布开发、螺旋模型、Jackson、ER图、Booch云、OMT、Objectory、以及Coad/Yourdon,直到今天的UML,计算技术从来都不缺少意图使程序更像工程的方法。每种方法都聚集了自己的追随者,并且都享受到一段时间的流行,然后一种方法又被下种方法取代。在所有这些方法中,或许只有第一种——结构化程序设计——拥有长久的生命
还有一些开发者,在有许多已沉没项目的大大海里漂流,不断抓住最新的时尚,就像是遇到海滩的人紧紧抓住漂来的木头一样 每当有新的木头飘过时,他们都会费力地游过去,虚妄这一块会更好。但到最后,不管漂浮物有多好,这些开发者仍然漫无目的地漂流着。

我们应是否使用形式方法

绝对应该。但始终要记住,形式开发方法只是工具箱的又一种工具。如果在仔细分析之后,你觉得愮使用形式方法,那就采用它——但要记住谁是主人。不要变成方法学的奴隶:
圆圈与箭头会让你变成糟糕的主人。注重实效的程序员批判地看待方法学,并从各种方法学中提取精华,融合成每个月都在变得更好的一套工作习惯。这至关重要,你应该不断努力提炼和改善你的开发过程。绝不要把方法学的呆板限制当作你的世界的边界。

发布了142 篇原创文章 · 获赞 2 · 访问量 8924

猜你喜欢

转载自blog.csdn.net/NumberOneStudent/article/details/104076382