qileilove

blog已经转移至github,大家请访问 http://qaseven.github.io/

TFS2010 版本控制权限设置

搞了几天的TFS2010权限的设置,学习了这些与大家分享下:

  1、TFS权限介绍

  Team Foundation Server 权限设置分为显式授权和隐式授权,显示授权是设置:“拒绝”和“允许”。 隐式授权,它既不将权限设置为“允许”,也不将权限设置为“拒绝”。 此授权是一种隐式“拒绝”设置,又称为“未设置”。

  2、权限设置要理解的4个重要概念

  2.1 拒绝

  “拒绝”不允许授权用户或组执行权限说明中提到的操作。“拒绝”是TFS中最强大的权限设置。 如果用户所属的TFS组将特定权限设置为“拒绝”,那么即使用户所属的另一个组将该权限设置为“允许”,该用户仍无法执行该功能。 此规则的唯一例外是用户属于项目的“Project Administrators (项目管理员)”组的、团队项目集合的“Project Collection Administrators”组或Team Foundation Administrators”组。 如果用户属于项目的 Project Administrators 组,则该组的权限会覆盖该用户在项目中的显式“拒绝”。 同样,如果用户属于项目的 Project Collection Administrators 组,则该组的权限会覆盖该用户在该集合中的显式“拒绝”。 如果用户属于 Team Foundation Administrators 组,则该组的权限会覆盖该用户在 Team Foundation Server 中的显式“拒绝”。

  2.2 允许

  “允许”则允许授权用户或组执行权限说明中提到的操作。 “允许”是 TFS中第二强大的权限设置,最常使用。 如果不将权限显式设置为“允许”,用户或组将不能在TFS中执行该操作。

  2.3 未设置

  默认情况下,TFS中的多数权限既没有设置为“拒绝”,也没有设置为“允许”。 权限处于“未设置”状态,它隐式拒绝授权用户和组执行权限说明中指定的操作。 但是,因为权限既没有显式设置为“拒绝”,也没有显式设置为“允许”,它可以从用户或组所属的其他组继承授权。

  ps:默认新建活新添加的用户对于权限的操作都是“未设置”。

  2.4 继承

  当用户或组的权限为“未设置”时,由于TFS中的权限是可继承的,所以用户或组可能受到其所属组权限的显式设置的影响。 例如,用户可能属于一个项目中的两个自定义组。 如果其中一个组的某个权限显式设置为“拒绝”,另一个组的同一权限未设置,则该用户将无权执行此权限所控制的操作。 该用户从两个组中继承权限,“拒绝”权限优先于未设置的权限。

  ps: 某些授权设置优先于其他授权设置。 在 TFS 中,“拒绝”权限优先于包括“允许”在内的所有其他权限设置(对于该显式结构)。 如果“拒绝”权限是从层次结构父元素(如版本控制)继承的,则不优先。 例如,用户可能属于一个项目中的两个组。 对于其中一个组,“发布测试结果”权限设置为“拒绝”;而另一个组则将该权限设置为“允许”。 “拒绝”设置优先级更高,用户无权发布测试结果。规则的唯一例外是从层次结构父元素继承显式“拒绝”或者用户属于下列组之一:

  Project Administrators
  Project Collection Administrators
  Team Foundation Administrators

  在层次结构(如版本控制和工作项跟踪)中,在特定对象上设置的显式权限会覆盖从父对象继承的显式权限

  ps:在正式授权设置之前可阅读msdn资料:Team Foundation Server 默认组、权限和角色。

  3、版本控制权限:

  默认情况下,下列各组处于版本控制级别:(多于两个单词的组名称全部简写。示例:Team Foundation 全部简写为TF,Team Foundation Server 简写为TFS,ProjectName简写为PN, Project Administrator 简写为PA,Team Foundation Administrator 简写为TFA,Team Project Collection Name 简写为TPCN以此类推为组英文名称的每个首字母大写组合)

  项目级别: PN/PA PN/Contributors PN/Readers PN/Builders

  项目集合级别:TPCN/PCA TPCN/PCSA TPCN/PCBSA

  自定义的项目集合组,或者项目可以赋予想要的版本控制权限。

  版本控制权限表

  TFS2010 团队项目集合级别权限下,新建一个组1,并为自定义的组1设置版本控制权限,和团队项目级别权限下新建一个组2,并为自定义的组2设置版本控制权限和安全性的项目级别权限,然后将组1加入组2中,那么两个不同级别组1和组2的版本控制权限谁的优先级高?

  这个问题是我提出的,我实践测试结果:

  遵循微软的权限设置策略,拒绝权限最高,下来是允许权限,最后是未设置。举例可以这样分析,为组1设置“锁定”权限为“允许”,这样组1中的所有用户都具有“锁定”的权限,将组1(团队项目集合级别的组)加入组2(团队项目级别的组),为组2设置版本控制权限,假如“锁定”权限设为“允许”,那么组一种的所有用户都具有锁定权限,假如将组2中的“锁定”权限设置为“拒绝”那么组1中的所有用户就失去了锁定的权限,假如将组2的“锁定”权限设置为“未设置”,那么组1的用户还是具有锁定的权限。(以上说明被各种管理员组的成员的权限覆盖掉了),还有一种情况是假如开始组1中的“锁定”权限就设置为“拒绝”,组1加入组2之后,组2的“锁定”权限设置为“允许”,组1中的用户还是会具有锁定权限。我理解的是一种就近原则吧!至少还没有碰见不符合这个的。如果有人打破这条麻烦告诉我一声。

  这个前提是组2的团队项目级别“安全性”里项目权限要将“查看项目级别信息”设为“允许”。

  利用vs2010与具有管理员权限的账户在客户端设置团队项目用户版本控制权限

  打开vs2010直接点击— 链接到Team Foundation Server 或者在“团队”—— 链接到Team Foundation Server

  ps:在团队菜单下可以进行多个操作。

  “链接到Team Foundation Server 服务器 ”后 ,团队资源管理器会自动打开。然后进行你想要的设置。

  ps:双击团队资源管理器下的树形菜单中的“源代码管理”,可打开“源代码资源管理器”

  团队资源管理器

  团队项目集合节点

  团队项目集合设置---组成员资格 这一栏下可添加自定义的组,并添加成员,新建的组默认属于Project Collection Valid Users

  团队项目集合设置---安全性 这一栏设置对团队项目集合的权限,默认属于Project Collection Valid Users这个组的具有访问项目集合的权限。

  团队项目节点

  团队项目设置---组成员资格 这一栏可添加自定义组,并添加成员,新建的组默认属于Project Collection Valid Users。

  团队项目设置---安全性 这一栏设置对团队项目的权限,添加自定义的组并设置对于当前团队项目的权限,然后自定义组的成员就可以依照响应权限访问到当前项目。一般仅仅赋予“查看项目级别信息”就可访问到项目。

  源代码管理资源管理器

  团队项目集合节点

  属性---安全性 这一栏可添加、设置自定义组对团队项目集合下的团队项目的项目源代码的操作权限。(这一步的设置针对的是团队项目集合设置——组成员资格下添加的自定义组的权限,对于团队项目集合下的团队项目,只要将设置好的组加入就可适用。)

  团队项目节点

  属性--安全性 这一栏可添加、设置自定义组对团队项目集合下的团队项目的项目源代码的操作权限。(这一步的设置针对项目团队项目设置——组成成员资格下添加的自定义组的权限,适用于当前项目。)

  重要:

  源代码管理中,对于团队项目集合级别的组,要适用于某一个团队项目集合下的项目,需要将这个组加入需要适用的团队项目下“团队项目设置”中添加的赋予了访问或者更高级别团队项目权限的自定义组。当然也可以不用新建将其加入默认组。

  默认属于Project Collection Valid Users组的组或者用户具有访问TFS服务器下的团队项目集合的权限。


posted @ 2011-11-24 17:41 顺其自然EVO 阅读(1119) | 评论 (0)编辑 收藏

非计算机专业的人如何进入软件测试领域

  在给学员做入学评估的时候,经常会遇到很多人对职业规划是相对迷茫的。不知道如何选择“适合”自己的职业。凡事预则立,不预则废。人在职场“混”,怎么能不职业规划!那么如何进行个人的职业规划?怎么样才能实现个人事业蓝图?下面的四个选择您可以来排一下顺序:

  其一,“择世所需”,也就是说我们选择这个时代所急需的行业?从这一点来看,软件测试行业应该是目前众多行业里面最符合这个条件的一个行业之一。因为随着人们对生活质量的高要求,对软件质量的要求也越来越高,而软件测试是软件质量保证最关键的实践之一。正是因为这样,越重要的领域,比如金融、证券、电子商务、互联网、移动、通信等领域越重视软件测试。另外从很多的数据也可以来发现这个趋势,记得51Testing论坛在08年的时候才23万会员,但到2011年今天就有近46万会员,翻了一倍多。在一定程度上说明,越来越多的人在关注这个领域。

  其二,“择己所好”,一个人的喜好往往是由一个人的性格和这个人过去工作背景所决定。根据霍兰德职业倾向测试,软件测试职业属于调查型、社会型兼有一部分艺术型活动。所以从这个意义上来看,思维方式比较发散、敏感、多样化、喜欢琢磨问题、具备怀疑精神、乐于与人沟通、喜欢钻研、追求完美的这类人适合软件测试这个职业。但是,个人认为工作谈不上喜欢与否,或者说一开始谈不上喜欢,只有当把这份工作做到一定的分量上,并且你因为这份工作得到了你应该得到的尊重、成就感、满足感、荣誉、社会地位、财富甚至是虚荣心。当你得到了想得到的物质上和精神上得满足之后,您才会爱上一份工作。就像爱上一个人一样。除了有一见钟情,还有日久生情。工作也同样如此。所以从这个意义上来看,当你感觉不受重视时、当你发现这份工作没有办法给你带来成就感、满足感、当你觉得你厌恶一份工作的时候。或许你已经知道,方向错了。如果是这样,给你一个忠告:“如果方向错了,停下来就是前进。”。正如婚姻与爱情一样。如果找不到继续下来的理由,换一个活法总比在一个坑里面等死好。趁年轻,让自己从一个圈子跳入另一个圈子。人生是一个不断突围的过程。职业发展也是一个不断实现突围的过程。在这个过程中,唯一不变的是变化。有不少非计算机专业的人通过各种方式问我,非计算机专业能不能做软件测试。先从“择己所好”的角度来分析。如果你对计算机(相关的编程、数据库、网络、操作系统等)感兴趣,或者以前选修过相关的课程。那我告诉你,没有问题,因为重要的不是你大学学的是什么专业,而是你现在懂什么。很多的案例可以在一定程度上佐证我这个观点,比如,马云不是学电子商务的,他照样搞成了阿里巴巴(但需要说明的一点是,马云不是不懂电子商务)。大学给我带来的更多的是知识,至少我现在还是这样的观点,大学带给我们的知识是我们在未来工作中再学习的前提。如果你以前对没有任何计算机的知识背景,那么就需要酌情来分析了。最关键的一点是你的学习能力和学习动力,这一点最好请专业的老师来考察下。

  其三,“择己所长”,选择自己所擅长的,一个人擅长的东西是这个人区别与其他人的核心价值,这个就是通常我们在面试的时候会被问到,你的优点是什么?缺点是什么?真正的“优点”应该是相对的,相对于具体的工作而言,也就是工作如果需要,这个才能称之为优点,或者这个优点才有用,另外优点更是相对于与你竞争同一份工作的竞争对手而言,你比你的竞争对手强的是什么?所以我经常性建议我的学生,你至少要能回答好如下三个问题,才说明你对优点真正理解,第一个,你参加了培训与没有参加培训,让你具备了什么相对的优势,起码你系统的掌握了软件测试的核心的基本的工具、流程、方法以及项目,也知道一个优秀的测试工程师应该具备哪些素质。第二个,你参加了51Testing的培训和其他的培训有什么区别,起码51Testing是专注软件测试领域,起码51Testing是唯一一家能够做就业培训、在职人员提高、企业内训三个层次的唯一的IT培训机构,另外只要是提到软件测试,行业内的人大家都知道,就好比,每个人都知道百度一样。当然51Testing只是平台,平台很重要,但是第三个问题就是,同样是参加51Testing培训,你比别人强的地方是什么?所以从“择己所长”来看,非计算机专业相对的劣势是计算机基础,这个是相对于计算机专业而言,我们不得不正视这个问题,正是因为这样,通过一个培训可以培养一定相对的优势,实际上通过扬长避短,51Testing也帮助了非常多的非计算机专业进入软件测试领域,而且大部分工作情况也非常不错,他们可以在行业知识等其他方面来凸显自身的优势,为了能更好得做好这个事情,你最好请专业的老师来帮你分析下,你自身的优势与劣势。但从我给很多人做入学评估与沟通的过程来看,很多人是不善于去发现自身的优势与劣势,所以要么不够自信,觉得自己是非计算机专业,学不好软件测试,做不好这份工作。要么是盲目的自信,觉得很容易,但是,不管是不自信还是盲目的自信都是有问题的。人真正要搞清楚的是自身的优势,搞清楚,有哪些事情是要靠自己的,哪些事情是要靠别人的。

  其四,“择己所利”,即选择对自己有利的职业,这个主要是结合自身情况看行业,比如很多学电子专业的,在企业里面做了一段时间,发现这个行业的发展有很大的瓶颈,原因是这个行业已经饱和且相关技术已经非常成熟,未来3-5年的发展可以从身边的领导身上就可以直接看到。所以从“择己所利”的角度来看,放弃眼下,展望未来是很关键。软件测试这个行业,只要你能沉下心来,潜心钻研,3-5年的前景还是看得到的。

  另外从成为一名职业的软件测试工程师来看,主要的知识结构包括如下几个方面,第一是计算机相关的基础知识(计算机相关专业的人在大学就已经学过了)。第二部分是软件测试核心技术,学习软件测试核心技术,好比学习武术,不是非得体育专业的人来学习,关键是你对武术感不感兴趣,是不是一块练武的材料。从核心技术的分类来看,可以分为三大类:第一类是软件测试工具,工具好比兵器,目前比较流行的商业工具有LoadRunner(需要懂C等编程语言),QTP(需要懂VBScript)等,除了商业的测试工具外,在一些大企业里面可能会开发自己的测试工具,这类工作叫做软件测试开发职位(这个可能是未来会火起来的一类测试职位之一),学习好测试工具,好的学习方式和老师的指导能帮助在一定程度上降低学习的难度。当然,最好还是懂点编程会更好。测试工具是测试技术领域里面需要计算机基础的一类技术。第二类是软件测试方法,方法好比武功秘籍,软件测试方法帮助解决复杂软件的测试需求分析与测试设计的问题,也就是我们所说的what与how的问题,学习软件测试方法对计算机知识几乎没有特别的要求,关键是基本的学习能力,我曾经给金蝶做过软件测试需求分析和测试用例设计方法的培训,当时金蝶也有很大一部分人是学财务、会计等非计算机领域的。所以从这个影响软件质量最关键的技术来看,能否学好软件测试方法与计算机知识没有太多的关系。第三类是软件测试流程,流程好比武术套路,是规范的软件测试和非规范的软件测试比较关键的要素,流程本身是把生产线上的流水线的方式引入到软件工程界后的一项工程实践。流程包括活动、角色、输入、输出、入口准则、出口准则、检查表等组织。所以,流程属于工程领域技术,从学习的角度来看,与计算机基础关系不大。实际上,也有不少编程能力相对薄弱的测试工程师通过关注软件测试流程进入软件测试更深的领域,如流程改进,软件测试管理和质量管理等领域。第三部分是行业知识,软件测试是一门对行业知识要求比较高的一类IT职业,即便是像金蝶这样在某一个领域非常出色的软件企业,他们也把软件测试工程师分成了几类,其中有一类是对行业知识要求高过计算机基础知识的,所以在里面也有很多非计算机专业的,比如财务、金融等专业的软件测试工程师。这类人最需要提高的是软件测试的核心技能。这个在前面有提到过。实际上每个行业都由相关的行业知识,而从学校学习的角度来看,过去在大学里面学到的相关的行业知识对于今后要从事的软件测试工作,也是有非常大的帮助。从这个行业分类上来看,软件测试目前最好的行业主要有金融证券、保险、互联网、电子商务、电信移动、通信、3G应用、大型门户网站、游戏、军工、财务等生活中关键的领域。第四部分是素质,比如逻辑思维能力,分析问题的能力,善于关注细节的能力,所以有些人是凭借这个能力进入的,比如微软都曾经招过家庭主妇来做软件测试,这个家庭主妇没有计算机背景,也没有学历,但是凭借非常强对问题的敏感而找到软件测试的工作,微软是非常重视软件测试的,芮成钢在采访比尔盖茨的时候,盖茨曾经说过“Many people maybe think we are a software develope company,but in fact, we are a software testing company!”微软几乎所有的产品都是测试工程师的比例高于开发工程师的比例。他们把测试工程师分为两大类,一大类是对编程有要求的测试开发工程师,一类是对编程要求较低的测试工程师。所以非计算机专业的人至少也可以做对编程要求相对较低的这类工作。

  综合而言,无论从“择世所需”、“择己所长”、“择己所好”、“择己所利”,还是从一个优秀的测试工程师应该具备的具体的能力与素质来看,是不是计算机专业不是进入软件测试领域唯一的条件,事实上现在有很多非计算机专业的人也在从事这个职业,而且也非常不错。只是从知识结构全面性角度来看,懂计算机知识还是非常重要的。软件测试工程好比医生,分外科和内科,好比黑盒测试与白盒测试,内科需要懂人得内部结构,而外科不一定非得懂内部结构,当然懂会更好,多一个选择。所以软件测试也不一定非得懂编程,当然懂会更好,多一个选择。另外医生也分专科,软件测试也可以分很多专项,比如有可用性测试(用户体验测试),这类测试是不需要懂编程的,也有自动化测试,这类是要懂编程的。最后给非计算机专业想进入软件测试领域一个建议与忠告,扬长避短,发挥自身已经有得优势,适当弥补自身的劣势,依赖行业背景、性格优势等专注软件测试某一个领域,这样就能成为某一个领域的测试专家。如果参加培训,在培训的过程中多关注自己与别人不一样的能力和素质。多向优秀的人学习,多发现问题,多解决问题。积累经验,把自身的优点、兴趣等跟将来要从事的职业结合起来。不要妄自菲薄也不能盲目自大。

posted @ 2011-11-24 17:39 顺其自然EVO 阅读(849) | 评论 (0)编辑 收藏

敏捷过程中的需求分析

  【摘要】 在日趋激烈的电信业竞争态势下,持续而快速地发掘和响应商机成为新的课题。作为响应机制中的关键环节,需求工程应用敏捷过程方法,以关注商业价值、快速响应、持续迭代的特征来应对变化和难测的未来,是尝试提高组织敏捷能力的核心。在这其中,作为沟通桥梁的需求分析同样可以应用敏捷的过程方法参与到生命周期的演进。敏捷需求分析将在需求时机与过程、文档要求、变更、参与者角色等方面展现其不同传统的特性。本文将结合电信业背景及企业实际情况,对敏捷需求分析作出初步的探索。

  1、敏捷需求分析:电信行业背景与敏捷过程的需要

  从中国电信行业ITSP战略推出至今,数年中我们已经看到了明显的变化,作为其信息化体系落地的CTG-MBOSS,也已初具规模和成效。大规模实施的下一个阶段,将是在商业价值引领下的重构竞争模式、市场细分,以及作为支撑的需求深入研究。在项目实施过程中,各种挑战和困难纷至沓来,项目管理者不管是做时间、成本、质量的三角平衡,还是人与技术的双向选择,始终无法绕开的一个问题跟源是:如何快速响应环境的变化,使客户在优化的体验过程中满足其商业目标,从而实现企业本身的价值?

  用失控的过程膨胀来形容近10年的许多软件公司的情形是很合适的。虽然有很多团队在工作中没有使用过程的方法,但是采用庞大、重型的过程方法的趋势却在快速增长,在大公司中尤为如此。但现实的发展确与此不相同步,竞争态势造成了更多的不确定性和快速调整的机会。从近年ERP上线的平均速度来看,项目的交付时间都比较长,这让用户产生了顾虑。但实际上软件上线仅仅是一个软件生命周期早期的阶段,软件的价值是在使用中体现出来的,其投资回报也只能在后期的运营得到完成。未来的变化如同纳西姆?塔勒布的黑天鹅一般不可预测且重要,已知和过去琐碎的重复并不足以预测未来的重大影响。以预测性度量为控制基础的过程模型,只能以经验涵盖一般性事件,所以与此同时,随机应变,保持快速集成和持续改进以应对商业环境的不确定性,延长软件的生命周期提高它的最大价值,从而为获取更多投资回报提供保障,也成为软件工程发展的必然。

  敏捷过程(Agile Process)的主要优势是能够适应系统需求的不确定性,将客户作为需求团队中密不可分的成员,而在实现过程中尽量在最短时间内实现对用户来说业务价值最大的需求;同时,敏捷开发(Agile Development)是一种面临迅速变化的需求快速开发软件的能力,它帮助处理了未来不确定性的问题;但是对于过去,应该没有不确定的事。而敏捷需求分析,是面对迅速变化的商业状况,提高其响应和组织成可理解和接受的需求说明并对敏捷开发作出能力保证的方法论。

  2、敏捷与过程改进和度量模型

  从软件工程发展起,过程改进在全球日益得到重视,ISO 9000/SW-CMM/CMMI各级的评估也在业界得以推展,这种氛围下,以RUP等为代表的过程模型也得到了广泛的应用。但与此同时,敏捷的论调却异军突起,方兴未艾。软件过程的多样性,源于过程环境和层次的不同;而过程选择的多样性和CMMI目标的通用性决定了过程改进途径的多样化。

  运用一系列重方法,将在应对商机方面造成挑战;尤其是在企业的管理考核和过程模板仍更多的是一种瀑布式体系下,软件的实现过程将在不同模型下摇摆却显得不那么灵活。一个合适的生命周期模型选择是重要的,由于惯性的教育,瀑布在我们的工作环境中随处可见。但如果不去分析CMMI等的实质,将无助于改进这一点而提高响应。

  强调结构化方法与重型的管理策略,往往在内心中拒绝变更,把变更作为被管理甚至被“管制”的对象;而为了尽可能避免变更,常常要求开发之前的需求获取、分析与定义要完整无误且精确。这是一种理论上的理想状态,尽管我们可以采取诸如CMMI的一些理念及过程改进模板对其管理,但实际上往往会出现与用户商业价值要求的脱节;而为达成此目标,使得前期的需求开发工作变得小心翼翼,最终有可能在压力与时间约束下难免简单化而草草了事,在后期又不能得到及时的修正,从而形成一个隐患。

  但实质上,重型、轻型过程方法论之间并不存在根本性的矛盾冲突,这体现于它们最终理念和出发点的一致。把这些互补方法论拼在一起,“恰好可以发现整个软件过程体系全貌的一部分”。CMM/CMMI 中不包括更为具体一点的如何写好需求,如何做好设计,如何写好测试等许多方面的软件工程技术、技能方面的指导,而这些恰好是敏捷的强项。敏捷方法整合了一套轻量的管理、过程和工程技术方法,这是它作为一种先进方法体系补充于CMMI 的地方。敏捷过程并不像业界所传的那样只适合小项目和新项目的研发,实际上它对于各种类型,包括企业所定义的A类、B类、C类在CMMI体系基础上都是可取舍适用的。这需要过程体系间的适当裁剪和调整组合。敏捷需求分析,将在全过程中扮演衔接、沟通和渗透的作用。

  3、敏捷需求分析的过程特性

  IEEE对需求的定义是用户解决问题或达到目标所需的条件或性能;系统或系统部件要满足合同、标准或其他正式规定文档的条件或性能。 需求是设计、构造产品的前提,简单地说,是必须完成的事及其所必须具备的品质。需求存在的原因要么是该类型的产品要求一定的功能和品质,要么是客户希望需求成为提交的产品的一部分[5]。

  软件需求包括三个不同的层次—业务需求、用户需求和功能需求—也包括非功能需求。业务需求(business requirement)反映了组织机构或客户对系统、产品高层次的目标要求,它们在项目视图与范围文档中予以说明。用户需求(user requirement) 文档描述了用户使用产品必须要完成的任务,这在使用用例(use case)文档或方案脚本(scenario)说明中予以说明。功能需求(functional requirement)定义了开发人员必须实现的软件功能,使得用户能完成他们的任务,从而满足了业务需求。所谓特性(feature)是指逻辑上相关的功能需求的集合,给用户提供处理能力并满足业务需求。

图1. 需求的层次及组成

  我们可以看到,不管是传统的还是敏捷的需求开发阶段,需求的层级及组成,其基本特性是一致的,这反映方法的差异并不改变需求的本身属性。一般的需求三个层次,忽略了一个问题,即每个层次所需的知识、技能、经验、背景等是不同的,不同的层次过程中,需要不同资源的整合。业界相关的论述中,只是给出了笼统的需求分析人员的统一角色,但并未对其作出区别。实际上,这很难映射到中小企业的现实操作层面。

  这引发了我们进入详细的敏捷需求分析话题中第一个问题,需求的参与者如何定义?

 3.1 需求的参与者

  敏捷需求分析过程的参与者,包括客户/用户、需求分析人员(业界一般也称之为商务分析师或业务分析师,business analyst,本文并不讨论词汇的细致差异,下文统一简称BA)、开发人员、测试人员,其他相关的角色有项目管理者等。在《敏捷宣言》(Manifesto for Agile Software Development)中,强调了客户一起现场工作的重要性。而在企业实际的实施过程中,由于限制,项目经理及实施人员,以及BA——如果有的话,在虚拟团队中,他们演绎客户的角色,从而使得“客户”也更好地“纳入”到了项目团队中。但应该清楚,这种纳入并不能真正代替真实的客户参与。

  对于客户无法全程现场参与的情况,BA的出现是一种弥补。BA最重要的职责就是与客户交谈,了解和分析需求,将其制作成用户故事(user story)并将需求传递给开发人员。同时,BA也要在某种参与度较深的情况下代替客户负责功能验收测试(Acceptance test)。而对内,BA显然扮演了客户,那么除了需求提供者的职责,如果需要的话,相应地也要有评价和验收否决的权利。当然,这项工作可以分解为另外的角色来进行。

  开发、测试人员进入需求团队,便于他们理解用户故事或者典型的RUP式的用例。一个完整描述的用例可以很方便地导出测例(test case)。而用例和测例是一致的,它描述在一个具体业务场景中可见的需求特征。我们可以根据这样的可见性写出功能测试,从而驱动这个用户故事的开发,这被称为 Acceptance Driven Development。从整个过程来说,分析和实现的过程就是场景拟合和检验,以及类似于XP中结对式的及时纠偏。各种角色的积极参与在不同角度和层次下的场景拟合,表明需求不是程序员的事情,也不是寄望于抽象出一个BA的角色甚至实例化为一个职位,就可以全能地做出需求定义。

  对于角色及其参与方式,我们可以比较如下:

角色及职责

传统的需求参与

敏捷的需求参与

用户/客户

需求的提供者

需求演进的参与者

用户的主要参与方式

陈述

遵循游戏规则的积极的交互参与

BA

需求的定义者

需求的组织者

BA的主要参与方式

前期的调查获取和整理成文档

参与全周期的迭代与演进

开发

需求的接受者和实现者

场景拟合者与改进者

开发的主要参与方式

被传导需求并使之功能化

完成完整的业务场景实现

测试

功能测试者

场景测试者(需求测试者)

测试的主要参与方式

出软件的显性的bug

找出不满足需求逻辑和不能拟合场景的缺陷

表1:需求的主要参与者

  (其他的stakeholders并未全部列出,比如PM、QA等)

  这些参与者如何工作的呢?我们引入到需求分析的工作形式。

  3.2 敏捷需求分析工作形式

  敏捷宣言强调了客户在一起工作的重要,敏捷是大家在一起高效率地工作,清楚所有沟通上的障碍,关注于增值的活动,从而使得项目更加成功。比如,敏捷联盟所推荐的现场客户工作。但多数情况下,客户都是很忙碌的,很难全力投入到过程中。这时候,我们就需要BA这个角色,来充当客户的角色。

  BA的参与使他变成了需求的组织者,需要使需求分析过程中具备资源快速聚合的能力。而工作方式,在传统之外,可以使用聚议和需求迭代计划会议的形式。

  敏捷思想的核心是人与人的交流。聚议是一种面对面的最好形式,它能促成问题从多个角度的现场核清。在前期的高层访谈之后,需求分析过程中至少要有以下的准备:(1)明确业务价值及其所推导的业务场景;(2)范围划分使得每个议题都有独立的业务价值,对于大而笼统的“需求”,则分解或置入下次迭代,而本次完成的将是一个相对完整的结果。对于需求分析中所用的各种形式,用户其实并不排斥参与——尤其是当他掌握了一定方法并能看到迅速回应带来的好处时,将极大地提升这种兴趣。在某省电信运营商的项目中,我们已经发现了这一点。用户明白积极参与的好处时,能主动从业务角度审视自己的需求,删减调整并作出易理解的文档。在一个已经实施的项目中做增量改进时,用户参与尤为重要,并且能部分地把前端人员从繁琐而低效的沟通(其实只是“传话筒”)和文档化中解脱出来。

  迭代是敏捷最显著的形式,而迭代的前提,则是对业务价值分解为用户故事的工作。这些将在下文中讨论。迭代计划会议是一种需求组织方式,在每个迭代开始的时候,由BA主持召开迭代计划会议,在会议上向开发人员解释这个迭代要完成的用户故事,然后由开发人员自由提问,知道他们能够获得足够开始实现该功能的信息。包括了用户参与的需求分析迭代会议,则可适时地作出review,避免错误的扩大和带入下次迭代。

  3.3 需求分析时机

  传统的需求分析时机集中在项目前期,总是遵循前期调研—分析—需求定义,转给开发后需求工作便就此结束,其思想里,便是一次性完整、清楚地做完所有层次的需求,并在整个过程中遵循计划。

  敏捷需求分析对这种惯例做出调整,源于其认为:需求的逐步细化过程中,变更是不可避免的;同时,为了快速的商业响应,保证能产出可见、可执行的结果也是必要的。后续的迭代和持续集成保证了需求的演进路线,简言之,需求分析贯穿于项目的整个生命周期。

  3.4 需求的划分

  开发人员总是希望能明确地知道系统分几个模板,功能是什么,但这些信息并不是需求的本身。基于模块和功能分解,专门的需求分析人员会使之流于粗放——这种情况是最多见的,功能划分使需求单位粒度较大,不足以描述其特征;而传统由开发人员来做的分析,往往会越过业务价值层面而转入底层的设计。

  敏捷需求分析中的划分,将以独立业务价值为基础,划分为一个个用户故事(可以去类比理解UP意义上的use case),它可以是很小颗粒的业务与特征集,也可能会跨越传统的子模块边界。用户故事以参与者为中心,描述了参与者“作为(系统的一个涉众),想要(做一件事),从而(达到一个业务价值)”的集合。用户故事是可见的业务价值,而不是功能描述。每个用户故事的粒度和开发工作量都相差不多,这是其与用例的区别。以此构建的测例,将指导测试与需求验证。

  3.5 敏捷需求分析与细化过程

  迭代是敏捷需求分析与细化过程中最显著的方式。迭代的特征包含如前文所述的两部分:全生命过程、小粒度的以业务价值为基础的划分。Robert C. Martin认为每一次迭代都是一个完整的项目产品[3],换言之,迭代是要产生最终产品的反复[4],也就是说你的一次一次的反复必须都能产生最终的产品,而不是中间的半成品。这也反映了需求划分的原则,以及每一次小的迭代,其结果都是可确认的。因此,迭代过程中重要的一种方法是分解,以及关注于当前价值实现的部分。如果一个需求暂时不能被理解并且与当前的商业目标的关系并不那么直接,那么它应该被分解和延后,而不是草草地做一个似是而非的大方案而囊括之。

  迭代是一种快速反应和逐步确认成果的方式。敏捷意味着快速反应、注重核心价值, 但并不是要求每件事都尽快地完成和提交。迭代计划的依据便是优先级的确定。因此,迭代的实施要求正确引导客户划分优先级,实施逐步的集成改进。必要时,项目上线也是可以逐步推行的,因为仅仅上线并不意味着价值的实现。

  传统的需求分析总是希望能一定完成所有的事情以便于直接作出功能划分和设计,但这在我们以往经历的项目实践中遇到了挑战,不得不把项目的需求分析肢解成似乎是多个不同项目的需求集合。敏捷而持续的过程,对此作出修正。

  3.6 文档与变更

  正如Martin对那种什么文档也不写就自称为敏捷的善意批评,敏捷过程对文档的态度只是一种思想的转变,而非重型的过程控制要求。敏捷方法需要两种类型的文档,它们分别是需求文档和设计文档,而其它所有类型的文档都是选择性的。对于需求文档,在敏捷方法中,往往会在某次迭代之中进行。它经常先于其他开发过程,但也要到开发过程的迭代开始的时候才在内容上达到完整。对于暂时不做的开发,就不会做细部特征的定义,以免浪费。撰写文档,其实是一件颇耗精力的事情,所以选择做什么样的文档需要有一种“投资回报”的考虑。

  传统的大量正式文档,规格严整而厚重,但在项目的中后期却往往不能保持同步(现状、文档之间以及与软件系统),难以维护和跟踪,生产和维护成本也很高。这些文档除表明需求本身外,更多地是一种管理控制的角色,比如,对于变更。

  敏捷过程并不是由文档主导、支撑和控制变更。如《敏捷宣言》中所透露的“响应变化胜过遵循计划” ,对于变更,敏捷过程是一个态度的转变。变更除过软件工程组织或者PMI等定义大部分类似于由“工作缺陷”引起的以外,在现代信息化竞争时代,它往往意味着商机。当然,对于这种商机的“欢迎”,企业需要商务模式的准备,否则将极易陷入“需求黑洞”之中。

  3.7 敏捷需求分析小结

  综合以上的陈述,对敏捷需求分析归纳如下表(角色职责的变化也是一种重要的对比,请参见表1,此处不赘言):

角度传统需求分析敏捷需求分析
需求分析时机更多地集中在项目早期近乎均匀地贯穿于项目的整个生命周期
需求划分单位基于功能分解,划分模块或子系统,一个模块或子系统的颗粒度通常较大基于能否独立业务价值,切割成一个个用户故事,一个故事有时会跨越传统的模块或子系统边界;用户故事是小粒度的,可测试的,可见的,并且是有价值
需求细化过程一步到位,可供开发人员设计开发逐步细化,仅就下一个迭代需要实现的部分进行详细分析
需求文档要求正式文档,往往有明确的格式要求。既作为设计开发人员必须严格遵守的规约,也作为向客户提交的必备产出物之一。难维护,难验证(跟踪),很多产出物最终难以被阅读。非正式文档。仅仅是辅助开发团队与客户沟通,不作为规约,也不作为必备产出物。更多强调通过自动化功能测试用例来跟踪系统需求。(对于组织过程资产管理要求,可以在此基础上形成可阅读可理解的轻型文档)。
需求文档同步项目中后期一般都处于不同步状态即时的同步
需求传递过程单向的陈述与记录,文档传导(线性的传递,误导放大,缓慢)聚议,共同参与,业务场景与用户故事,及时的非正式沟通
应对需求变更有严格的控制流程,视变更为风险视变更为必然或预期中的事情

 

表2:敏捷需求分析的特征对比

  4、应用敏捷需求分析的质量保证

  一个传统的软件实现过程,遵循计划与严格的控制来保证质量。管理手段的控制有时不能及时纠正工程领域的偏差,即使控制体系给了更多的回馈机制,实质上更多地只是增加了信息层级和复杂度。

  一个典型的缺陷放大过程如下图所示:

图2:软件实现各阶段的缺陷放大

  敏捷需求分析参与生命周期的迭代,而每一次迭代都是一个完整的过程,并产生项目交付品,而在下一个迭代之前,其交付品都是可用的。这种方法能有效地及时调整,从源头消除可能被放大的缺陷。

  敏捷过程中,需要BA、QA的全程参与(当然,在企业实践中,可能存在着职能划分的现状。从更有效的角度看,由于项目经理参与了项目全生命周期,尤其是对需求管理的全过程的跟踪,项目经理担任某一项目的BA角色,也是现实可行的,其优点是可以保证有及时的客户沟通、长期而细致的跟踪),保证需求能始终被正确地理解、传递和验证。从敏捷需求出发导出的场景拟合验收测试,能从更广阔的层级(业务价值视角)来验证需求的达成性而不仅仅是软件的可用性等指标。这对质量保证是一个提高。迭代演进中应对需求变更,是从客户视野上的更高的质量改进。

  5、总论

  敏捷过程是一种结合管理理念与工程方法的最佳实践,它关注人的价值,倡导客户合作与响应变化,是中小企业持续过程改进的最有效途径之一。敏捷过程意味着全过程的敏捷,而不仅仅只是片面理解诸如XP、Scrum等方法而局限于开发环节。这其中,敏捷需求分析构成了方法体系的重要因素,它以沟通、迭代、响应变化、独立业务价值导出的可见的用例等特征,贯穿于产品全生命周期。

  在电信业竞争态势与管理细化背景下,将出现需求迭出但保持持续演进的特征。应用敏捷过程方法论,结合CMMI体系的适度裁剪与敏捷化,化变化为商机,关注商业价值,是应对挑战的有效方法。

posted @ 2011-11-24 17:33 顺其自然EVO 阅读(583) | 评论 (0)编辑 收藏

ERP监理方法系列:编码、测试阶段的监理工作

编码监理

  软件编码监理的主要目的是为了控制软件编码阶段的工程进度,监督软件编码的编程风格和质量,使得软件编码阶段的工作能可靠、高效地实现软件设计的目标,同时符合承建单位的软件过程规范的要求。

  一、软件编码监理的目标

  1)监督承建单位定义和综合软件编码任务,并在生产软件的过程中始终如一地执行这些任务。

  2)监督使得软件工作产品彼此间保持一致性。

  3)监督使得软件编码的工作进度与计划保持一致性。

  4)监督使得软件编码的工作质量达到计划的要求。

  二、软件编码监理的活动

  1)监督承建单位将合适的软件编码工程方法和工具集成到项目定义的软件过程中。

  (1)依据项目定义的软件过程对软件编码任务进行综合。

  (2)选择软件编码可用的方法和工具,并将选择专用工具或方法的理由写成文档。对备选方法和工具进行选择的依据是:

  ● 机构标准软件过程

  ● 项目定义的软件过程

  ● 现有的技术基础

  ● 可得到的培训

  ● 合同需求

  ● 工具的能力

  ● 使用的方便性和提供的服务

  (3)选择和使用适合于软件编码的配置管理模型。配置管理模型可能是:

  ● 入库出库模型

  ● 组合模型

  ● 事务处理模型

  ● 更改处理模型

  (4)将用于软件编码的软件产品和工具置于配置管理之下。

  2)监督承建单位依据项目定义的软件过程,对软件编码进行开发、维护、建立文档和验证,以实现软件需求和软件设计。

  (1)参与软件编码的人员评审软件需求和软件设计,以确保影响编码的各种问题得到识别和解决。

  (2)使用有效的编程方法编制软件代码。编程方法可能是:

  ● 结构化编程

  ● 代码重用

  (3)根据一个计划制定代码单元的开发顺序,该计划考虑诸如关键性、难度、集成和测试问题;合适时,还要考虑客户和最终用户的需要。

  (4)每个代码单元完成编码时,通过评审和单元测试

  (5)将代码置于配置管理之下

  (6)每当软件需求或软件设计更改时,适当地更改代码。

  3)软件监理组跟踪和记录软件编码产品的功能性和质量。跟踪和记录的内容有:

  (1)跟踪、累计的软件编码产品缺陷的数量、类型和严重程度

  (2)软件编码产品工程活动的状态

  (3)有关问题严重性和持续时间的报告

  (4)用于分析每个更改建议的工作量及汇总统计量

  (5)按类别(如界面、安全性、系统配置、性能和可用性)被纳入软件基线的更改数量

  三、软件编码监理的方法

  1)定期审查软件编码的工程活动和工程进度。

  2)根据实际需要对软件编码工程活动、工作进度进行审查。

  3)对软件编码工程活动和产品进行评审和(或)审核,并报告结果。这些评审和(或)审核至少应包括:

  ● 软件编码工程任务的准备就绪和完成准则得到满足。

  ● 软件编码符合规定的标准和需求。

  ● 已完成所需的测试。

  ● 检测出的问题和缺陷已建立文档,并被跟踪和处理。

  ● 通过软件编码,对设计的跟踪得以实施。

  ● 在软件产品提交前,依据软件基线验证了用来管理和维护软件的文档。

  四、软件编码走查的监理

  程序实际上也是一种供人阅读的文章,有一个文章的风格问题。应该使程序具有良好的风格。表现在:源程序文档化,数据说明的方法,语句结构和输入/输出方法。所以在进行编码监理时重点从一下几个方面把握:

  1)源程序文档化

  (1)符号名的命名

  符号名即标识符,包括模块名、变量名、常量名、标号名、子程序名、数据区名以及缓冲区名等等。这些名字应能反映它所代表的实际东西,应有一定实际意义。例如,表示次数的量用Times,表示总量的用Total,表示平均值的用Average,表示和的量用Sum等等。

  名字不是越长越好,应当选择精炼的意义明确的名字。必要时可使用缩写名字,但这时要注意缩写规则要一致,并且要给每一个名字加注释。同时,在一个程序中,一个变量只应用于一种用途。

  (2)程序的注释

  夹在程序中的注释是程序员与日后的程序读者之间通信的重要手段。注释决不是可有可无的。一些正规的程序文本中,注释行的数量占到整个源程序的1/3到1/2,甚至更多。注释分为序言性注释和功能性注释。

  序言性注释通常置于每个程序模块的开头部分,它应当给出程序的整体说明,对于理解程序本身具有引导作用。有些软件开发部门对序言性注释做了明确而严格的规定,要求程序编制者逐项列出。有关项目包括:程序标题;有关本模块功能和目的的说明;主要算法;接口说明:包括调用形式,参数描述,子程序清单;有关数据描述:重要的变量及其用途,约束或限制条件,以及其它有关信息;模块位置:在哪一个源文件中,或隶属于哪一个软件包;开发简历:模块设计者,复审者,复审日期,修改日期及有关说明等。

  功能性注释嵌在源程序体中,用以描述其后的语句或程序段是在做什么工作,或是执行了下面的语句会怎么样。而不要解释下面怎么做。要点:描述一段程序,而不是每一个语句;用缩进和空行,使程序与注释容易区别;注释要正确

  (3)标准的书写格式

  视觉组织用空格、空行和移行来实现。恰当地利用空格,可以突出运算的优先性,减少发生编码的错误;自然的程序段之间可用空行隔开;移行也叫做向右缩格。它是指程序中的各行不必都在左端对齐,都从第一格起排列,这样做使程序完全分不清层次关系。对于选择语句和循环语句,把其中的程序段语句向右做阶梯式移行。使程序的逻辑结构更加清晰。

  2)数据说明

  在设计阶段已经确定了数据结构的组织及其复杂性。在编写程序时,则需要注意数据说明的风格。为了使程序中数据说明更易于理解和维护,必须注意以下几点。

  (1)数据说明的次序应当规范化

  数据说明次序规范化,使数据属性容易查找,也有利于测试,排错和维护。原则上,数据说明的次序与语法无关,其次序是任意的。但出于阅读、理解和维护的需要,最好使其规范化,使说明的先后次序固定。

  (2)说明语句中变量安排有序化

  当多个变量名在一个说明语句中说明时,应当对这些变量按字母的顺序排列。带标号的全程数据也应当按字母的顺序排列。

  (3)使用注释说明复杂数据结构

  如果设计了一个复杂的数据结构,应当使用注释来说明在程序实现时这个数据结构的固有特点。

  (4)语句结构

  在设计阶段确定了软件的逻辑流结构,但构造单个语句则是编码阶段的任务。语句构造力求简单、直接,不能为了片面追求效率而使语句复杂化。

  比如:在一行内只写一条语句;程序编写首先应当考虑清晰性;程序要能直截了当地说明程序员的用意;除非对效率有特殊的要求,程序编写要做到清晰第一,效率第二,不要为了追求效率而丧失了清晰性;首先要保证程序正确,然后才要求提高速度,反过来说,在使程序高速运行时,首先要保证它是正确的;避免使用临时变量而使可读性下降;让编译程序做简单的优化;尽可能使用库函数;避免不必要的转移;尽量采用基本的控制结构来编写程序;避免采用过于复杂的条件测试;尽量减少使用“否定”条件的条件语句;尽可能用通俗易懂的伪码来描述程序的流程,然后再翻译成必须使用的语言;数据结构要有利于程序的简化;程序要模块化,使模块功能尽可能单一化,模块间的耦合能够清晰可见;利用信息隐蔽,确保每一个模块的独立性;从数据出发去构造程序;不要修补不好的程序,要重新编写。

  3)输入和输出

  输入和输出信息是与用户的使用直接相关的。输入和输出的方式和格式应当尽可能方便用户的使用。一定要避免因设计不当给用户带来的麻烦。因此,在软件需求分析阶段和设计阶段,就应基本确定输入和输出的风格。系统能否被用户接受,有时就取决于输入和输出的风格。输入/输出风格还受到许多其它因素的影响。如输入/输出设备(例如终端的类型,图形设备,数字化转换设备等)、用户的熟练程度、以及通信环境等。不论是批处理的输入/输出方式,还是交互式的输入/输出方式,在设计和程序编码时都应考虑下列原则:

  (1)对所有的输入数据都要进行检验,识别错误的输入,以保证每个数据的有效性;

  (2)检查输入项的各种重要组合的合理性,必要时报告输入状态信息;

  (3)使得输入的步骤和操作尽可能简单,并保持简单的输入格式;

  (4)输入数据时,应允许使用自由格式输入;

  (5)应允许缺省值;

  (6)输入一批数据时,最好使用输入结束标志,而不要由用户指定输入数据数目;

  (7)在交互式输入时,要在屏幕上使用提示符明确提示交互输入的请求,指明可使用选择项的种类和取值范围。同时,在数据输入的过程中和输入结束时,也要在屏幕上给出状态信息;

  (8)当程序设计语言对输入/输出格式有严格要求时,应保持输入格式与输入语句的要求的一致性;

  (9)给所有的输出加注解,并设计输出报表格式。

  测试监理

  目前国内信息ERP应用系统建设过程中,在此阶段常发生未经过严格系统测试就匆忙上线试运行的情况,这往往会造成不稳定的新系统对实际工作环境的影响,在某些情况下会阻碍系统的正式上线运行。

  因此监理单位在此阶段主要检查承建单位是否按照设计中制定的规范与计划进行测试。但切忌由监理单位进行单元、集成或确认测试而取代开发方的内部测试,这种方法并不能保证工程的质量。

  如果监理单位具有丰富的测试工作资质与经验,可以考虑在此阶段由监理方在业主单位、承建单位的配合下具体进行系统测试工作。由于监理单位对工程建设启动阶段、需求分析阶段、设计阶段、实现阶段的工作有深入的了解,由监理单位进行系统测试工作往往能够得到较好的效果。

  一、软件测试监理的目标

  1)监督和控制承建单位的软件测试过程,确保软件测试按照承建单位的测试文档规范和业主的软件要求实施;

  2)软件测试反映出、记录着软件产品的真实情况;

  3)软件测试的各个阶段按计划步骤实施;

  4)对于软件测试反映出的问题能有效地按回归测试规范进行处理;

  5)最后得到符合软件任务书(或合同)要求的软件产品集;

  6)软件测试的进度与计划保持一致性。

  二、软件测试监理的活动

  1)监督承建单位将合适的软件测试工程方法和工具集成到项目定义的软件过程中。

  (1)依据项目定义的软件过程对软件测试任务进行综合。

  (2)选择软件测试可用的方法和工具,并将选择专用工具或方法的理由写成文档。对备选方法和工具进行选择的依据是:

  ● 机构标准软件过程

  ● 项目定义的软件过程

  ● 现有的技术基础

  ● 可得到的培训

  ● 合同需求

  ● 工具的能力

  ● 使用的方便性和提供的服务

  (3)选择和使用适合于软件测试的配置管理模型。配置管理模型可能是:

  ● 入库出库模型

  ● 组合模型

  ● 事务处理模型

  ● 更改处理模型

  (4)将用于测试软件产品的工具置于配置管理之下。

 2)监督承建单位依据项目定义的软件过程,对软件测试进行开发、维护、建立文档和验证,以满足软件测试计划要求。软件测试由静态测试、单元测试、集成测试、确认测试和系统测试组成。

  (1)可以客户和最终用户一同参与开发和评审测试准则。

  (2)使用有效方法测试软件。

  (3)基于下列因素确定测试的充分性:

  ● 测试级别。测试级别有:单元测试、集成测试、确认测试和系统测试。

  ● 选择的测试策略。测试策略有:功能测试(黑盒测试)、结构测试(白盒测试)和统计测试。

  ● 欲达到的测试覆盖。测试覆盖方法有:语句覆盖、路径覆盖、分支覆盖和运行剖面覆盖。

  (4)对每个级别的软件测试,建立和使用测试准备就绪准则。确定测试准备就绪准则包括:

  ● 软件单元在进入集成测试前已成功地完成了代码的静态测试和单元测试

  ● 在进入系统测试前,软件已成功地完成了确认测试

  ● 在软件进入系统测试前,已对测试准备就绪进行评审

  (5)每当被测试软件或软件环境发生变化时,则在各有关的测试级别上适当进行回归测试。

  (6)对于测试计划、测试规程和测试用例,准备使用前通过评审

  (7)管理和控制测试计划、测试说明、测试规程和测试用例。

  (8)每当软件需求、软件设计或被测试代码更改时,适当地更改测试计划、测试说明、测试规程和测试用例。

  3)监督承建单位依据项目定义的软件过程,计划和实施软件的确认测试。

  (1)基于软件开发计划,制定确认测试计划并写成文档。

  (2)负责软件需求、软件设计、系统测试及验收测试的人员,评审确认测试用例、测试说明和测试规程。

  (3)依据指定的软件需求文档和软件设计文档的指定版本,进行软件确认测试。

  4)计划和实施软件系统测试,实施系统测试以保证软件满足软件需求。

  (1)尽早分配测试软件的资源,以做好充分的测试准备。所需的测试准备活动包括:

  ● 准备测试文档

  ● 准备测试资源

  ● 开发测试程序

  ● 开发模拟程序

  (2)编制系统测试的计划文档,如果合适,该测试计划由业主单位进行评审和认可。此测试计划包括:

  ● 全面测试和验证的方法

  ● 测试职责

  ● 测试工具、测试设备和测试支持需求

  ● 验收准则

  (3)由一个独立于软件开发者的测试小组来计划和准备所需的测试用例和测试规程。

  (4)在测试开始前,对测试用例建立文档,并经评审和认可。

  (5)依据已纳入基线的软件及其软件任务书(或合同)和软件需求文档,实施软件测试。

  (6)对测试中发现的问题建立文档,并跟踪到关闭。

  (7)建立测试结果文档,并以此作为判断软件是否满足需求的基础。

  (8)管理和控制测试结果。

  5)软件监理组跟踪和记录软件测试的结果。跟踪和记录的内容有:

  (1)跟踪、累计的软件产品缺陷的数量、类型和严重程度

  (2)软件测试工程活动的状态

  (3)有关问题严重性和持续时间的报告

  (4)用于分析每个更改建议的工作量及汇总统计量

  (5)按类别(如界面、安全性、系统配置、性能和可用性)被纳入软件基线的更改数量

  三、软件测试监理的方法

  1)定期审查软件测试的工程活动和工作进度。

  2)根据实际需要对软件测试工程活动进行跟踪、审查和评估。

  3)对软件测试工程活动和产品进行评审和(或)审核,并报告结果。这些评审和(或)审核至少应包括:

  ● 软件测试工程任务的准备就绪和完成准则得到满足。

  ● 软件测试符合规定的标准和需求。

  ● 已完成所需的测试。

  ● 检测出的问题和缺陷已建立文档,并被跟踪和处理。

  ● 通过软件测试,软件产品符合软件需求的要求。

  ● 在软件产品提交前,依据软件基线验证了用来管理和维护软件的文档。

posted @ 2011-11-24 17:03 顺其自然EVO 阅读(198) | 评论 (0)编辑 收藏

我的测试

  一转眼,进入测试已经四个年头。这四年里我从一个对测试一无所知的新人,成长为一名软件测试工程师。这一路走来,有过奋斗,有过梦想,有过激情,但遗憾的是还没有成就。偶然听到《老男孩》这首歌的时候,我不得不感慨万千,“当初的愿望都实现了吗,事到如今只好祭奠吗”,入职时“曾经志在四方少年”如今也只能“羡慕南飞的燕”啦。有些悲凉了,幸好还没那么严重。现在,把我的一些成长经历分享给新入测试的同行,希望他们成为我所羡慕的“南飞的燕”,同时借此机会总结一下四年的测试生活,提升一下文字水平。

  08年因为招聘会上的与北大青鸟的一位主考的交谈,开启了我对测试的兴趣。我可能永远都不会忘记那位同行的那些问题:“水杯的质量怎么测?”。在现在看来,这个问题如同问“你知道饭有几种吃法?”这样简单,可对于当时的我而言,却有点“丈二金刚摸不着头脑”,我只能把我所想的简单说了一下,比如往地上砸一下,往桌子上碰一下之类。我当时确实没有想到后来所知道的“验收标准测试”,“装其他液体测试”等等答案。后来他又问我,“你知道哪些测试工具?”。这下我彻底懵了,虽然是软件专业出身,但对于测试还真是没有太多概念,更不用提测试工具了。当这位主考发现我对于测试一无所知的时候,他很高兴并有些得意的告诉我“同学,你该来北大青鸟培训了。相信我们,没错的!”好了,这一篇可以翻过了。因为在这之后所发生的,我相信“你懂的”。其实这一段文字,我想说的是刚毕业那会儿,我真的很单纯,准确的说是测试的新人都是很单纯的,对于职业是需要一种引导的。

  当毕业后,我拿着研究了小半年的关于性能测试LoadRunner的毕业论文来到了XX。二面的时候,同样是一些问题,让我时至今日也感觉十分汗颜。当时测试主管问的是“你知道什么是QC吗?”。我很直接的回答“   QC是一种测试工具”。然后又问“那什么是QA呢?”,“还是工具!”。后来,我才知道原来QC指的是测试执行,而QA是质量保证。有时候我不得不把这次让我羞赧的问答同那个北大青鸟的主考官联系起来,因为是他引导了我去学习测试工具,花了半年的时间研究了LoadRunner和QC,导致我满脑子里想的都是工具。好了,这一篇也可以翻过了。这一段文字,我想说的是测试新人其实就是一张白纸,需要良好并且正确的引导,而我无疑最终成了涂鸦板。

  入职后的一年里,和很多新入职的朋友一样,我对于测试技术和测试工具非常的迷恋,尤其迷恋上了自动化测试。那个时候烦是一有执行测试的机会,我就想把我所学到的工具用上。09年的时候为了测试一个项目的Webservice组件,我花了一个月的时间学习了QTP,然后用QTP录制Webservciestudio,达到了可以实现测试的效果。但最终因为测试时间有限以及测试部在其他测试组已经有了更成熟的Webservice测试框架,导致我的自动化测试方案没有能用起来。虽然当时我的这套测试方案并没有得到认同,而且被指出了很多不合适的地方,比如QTP是商业化工具不太提倡,QTP录制WebserviceStudio产生的这套脚本自身也不太稳定,要做参数化也需要测试人员具备一定的VBS使用基础,对于后期维护不利。但值得庆幸的是,当时我并没有放弃这套方案,而是把同事们给我提出的这些建议收集起来,改进到我的这套方案,并且最终在09年下半年完成了我的第一个完整的Webservice测试套件(基于VBS的Webservice自动化测试脚本)。到这里还没有结束,我并没有把这套方案应用到项目上来,因为当时大家还是迷恋于SOAPTest的那种强大功能。我悄悄的把这套方案写到了我在51testing上的博客上,并且定期的去修改它维护它,直到2010年,这套方案才最终顺利的应用到了一些项目的测试过程中,因为这个时候一些同事开始发现SOAPTest太强大了,以至于它的学习成本,使用难度,执行效率都不是很理想,对于大数据量的接口测试,他们需要一套简单而行之有效的测试方案。好了,这一篇可以翻过了。这一段文字,我想说的是在测试的路上可能会遇到各种各样的困难,但它们并不妨碍我们的成长,只要我们心中都有梦想,坚持住,总能雨后见晴天。

  2010年的时候,我负责起一个测试小组的日常工作并且指导一名新同事的成长。这一年里,我几乎忘记了以前学习的所有工具的使用,因为我发现工具用的再好,始终离不开测试理论的支持。于是我在日常的工作中,投入了很多的时间去学习测试理论和测试管理知识,而忽视了技术方面的提高和巩固。以至于当我从测试小组管理回到测试执行的岗位上时,才猛然发现自己失去的太多。因为我们是技术性的岗位,技术和理论并不是两条平行线,而是纠缠在一起,相辅相成。回到测试执行岗位之后,想再做一些自动化测试相关的探索,已经是力不从心了。一切都得从头开始学,连自己写过的脚本都很难看懂。好了,这一篇可以艰难的翻过了。这一段文字,我想说的是如果你成为了测试组长,在繁忙的管理工作中,别忘了复习一下测试执行时期学习的那些知识,哪怕是一条用例设计的方法或者一段简单的测试脚本。

  2011年,我了解到了很多的对于我来说相当“潮”的测试工作相关的名词:“Selenium”、“AIR”、“持续构建与持续集成”、“架构”(10年言必谈“框架”的时代已经过去了,现在是言必谈“架构”了。)、“渗透测试”、“缺陷分层”、“互联网云”、“Android”等等。这些词汇证明了一个伟大互联网测试时代的到来。而对于这个时代,我和除了我之外还有一些同行都已经是“奥特曼”了。当看到百度测试技术沙龙、淘宝测试技术嘉年华、互联网测试技术交会等一些国内有影响力的测试交流会上,来自各大企业的测试专家激情分享各自的测试经验的时候,我突然发现,在测试这份工作上,我是那么的短视。好了,这将是最后一篇了。我要分享我2011年的感悟了,感悟比我深刻的请直击点击文档右上方的叉按钮,感悟程度和我相同或者小于我的,那我们共勉吧。除了我以外还有很多的测试同行,可能都存在这样的一些问题。我们学习QTP、学习LoadRunner、学习SOAPUI,学习各种各样的先进的测试工具、先进的测试方法,但我们始终缺乏一种大局观,一种技术上的大局观。在移动互联网的时代,那就是一种移动互联网测试技术的大局观。举个例子来说:当听说苹果与adobe发生争执,而最终adobe决定弃移动Flash而去的时候,你是否想过苹果的手机里AIR应用将如何测试,移动浏览器的兼容性又如何进行测试,换句话说,你是否意识到这样的一个动态会造成怎么样的测试技术上的变更。那么如何去获取这种大局观呢,这就是我们部门的文化之一“改进”。那么又该从何处开始改进呢?我们需要打开我们的眼界,多去关注一些测试的动态,比如上面提到的百度测试技术沙龙、淘宝测试技术嘉年华、互联网测试技术交会等。从中了解那些测试大师们的思想,同时了解当前测试技术时代的变更。因为在这里,QTP、LoadRunner都不是测试技术,真正的测试技术是一种开放的、合适的、富于创造和激情的态度。

posted @ 2011-11-24 16:54 顺其自然EVO 阅读(187) | 评论 (0)编辑 收藏

Linux下的高级权限文件控制

  在企业内网的开发环境方面,文件服务器是一个非常重要的环节。其中,Samba服务器由于其权限控制的高度灵活性,最初学习时确实会让大家感到很迷惑,但我们可以先搭建一些简单的案例来掌握其语法。本节主要是介绍Linux下的高级权限suid、sgid、sticky三种权限的特点。

  很多人都很奇怪,为什么我们需要学习这三种权限呢?因为在实际工作中我们发现,如果不了解这些特殊权限会让我们对Linux权限的理解(尤其是加上Samba权限后)尤为困难,所以我们必须要学习并了解它们。下面试图用浅显的讲解,让大家能充分理解这三种权限的作用。理解了它们,再理解Samba的权限控制就更容易了。

  注意 Samba的权限由两方面构成:

  一是目录本身的权限;二是Samba的配置权限。最终权限的定义是两者的最小交集。

  我们接着来理解这3种权限:

  1)一个文件都有一个所有者,表示该文件是谁创建的。

  2)如果同时该文件还有一个组编号,则表示该文件所属的组一般为文件所有者所属的组。

  3)如果是一个可执行文件,那么在执行时,一般该文件只拥有调用该文件的用户所具有的权限。

  权限标志通过以下3个“位”来定义。

  setuid:设置使文件在执行阶段具有文件所有者的权限。比如/usr/bin/passwd,如果是一般用户执行该文件,则在执行过程中,用户通过该文件可以获得root权限,从而可以更改用户的密码。

  setgid:该权限只对目录有效。目录被设置该权限后,任何用户在此目录下创建的文件都具有和该目录所属的组相同的组。

  sticky:该位可以理解为防删除位。一个文件是否可以被某用户删除,主要取决于该文件所属的组是否对该用户具有写权限。如果没有写权限,则这个目录下的所有文件都不能被删除,同时也不能添加新的文件。如果希望用户能够添加文件但同时又不删除文件,则可以对文件使用sticky bit位。设置该位后,就算用户对目录具有写权限也不能删除该文件。

  下面介绍一下三种权限的特点。

  (1)sticky的特点

  sticky只能应用在目录上,并且是应用在其他人的目录上。

  只有root和文件的拥有者才能删除该文件。

  小写s表示能执行,大写S表示不能执行。

  它的其他特点大家可以参考/tmp目录。

  (2)setuid的特点

  setuid只能应用在二进制文件中。

  当一个文件应用了setuid,那么任何人在执行该命令的时候就能临时拥有该文件拥有人的权限。

  setuid只能应用在文件的拥有者上。

  小写s表示能执行,大写表示S不能执行。

  它的其他特点大家可以参考/usr/bin/passwd目录。

posted @ 2011-11-24 16:47 顺其自然EVO 阅读(246) | 评论 (0)编辑 收藏

步步学LINQ to SQL:为实体类添加关系

  本文详细为你阐述了如何在你的应用程序中实现LINQ to SQL。附件的示例程序包括了这里探讨的所有代码,还提供了一个简单的WPF图形界面程序来显示通过数据绑定返回的结果集。

  本部分描述如何实现表间的映射关系:M:1,1:M和M:M。但是这里不会讨论1:1的映射关系,你可以在M:1的关系中发现这种1:1的映射关系。因此,从这里开始,我们将使用Book作为示例为你一步一步讲述这一实现过程。

  映射M:1的关系

  Book 对象与Category 对象是多对一的关系(M:1),因为一本书仅能属于某一个类别(并且每个类别能够包涵很多本书):

  在数据库中,Book.catalog字段作为该表的外键,而在Category中作为主键。然而,在你的对象模型中,你很可能想让book.Catalog表示一个实际的Catalog对象(不仅仅是ID)。此时,你可以通过创建两个私有字段来实现这一映射关系,然后再对Category对象暴露一个公有属性。

  1、添加一个私有字段以进行其他表的关联

  添加一个私有字段,将其映射到Book.category数据库表的外键列。

  如果允许该字段为NULL,使用一个空类型即可实现(如,采用Int?的方式)。

  我将这个字段命名为categoryId(为了区别于我们后面将要创建的公有属性Category)。这意味着在Column特性上我必须得设置Name参数,因为我的字段名字和数据库表的字段名称不同:

[Column( Name="Category")]privateint?categoryId;

  2、添加一个引用其他表的私有EntityRef类型字段

  添加一个私有类型的EntityRef字段以实现对Category实例的引用。虽然这会使得公有属性Category扮演一个后台字段的角色,但是通过使用EntityRef类型,仍然能达到延迟加载的目的(意思是LINQ不会即时从数据库获取数据直到我们真正想要数据的时候)。初始化EntityRef字段实例,以阻止NullReferenceExceptions发生。万一在某个地方你需要使用该对象的实例(如,Category)而此时又没有任何实例(Book)可用。

privateEntityRef _category=newEntityRef( );

  3、使用[Association]特性添加一个公有属性进行类的关联

  最后,创建类型为public的Category属性,该属性用于接收实际的Category实例。 使用下面的参数为该属性添加Association特性:

  ● 数据库两表之间的是关系名称Name(在本例为FK_Books_BookCategories))

  ● IsForeignKey = true标记指定该类对应数据表的外键(在下面的ThisKey参数中进行了指定)。

  ● 使用刚才创建的字段为该特性设置两个参数:

  (1)ThisKey用于指定到其它表的外键:categoryId。

  (2)Storage指定EntityRef用于接收其他类的实例:_category。

  在属性内部,代码的getter/setter访问器用于使用category的Entity属性,它包涵实际的Category实例:

[Association( Name = "FK_Books_BookCategories",
IsForeignKey = true, Storage = "_category", ThisKey = "categoryId" )]
public Category Category{
get { return _category.Entity; }
set { _category.Entity = value; }
}

  从M:1的关系上访问数据

  现在你可以通过这种关系以面向对象的方式访问Category的数据。例如,book.Category.Name:

foreach( var book in bookCatalog.Books ) {
string categoryName = book.Category.Name;
}



 在关联表中的M:1关系

  现在,咱们一起看看如何在M:M关联表中实现M:1的关系。当我们遇到表之间的关系为M:M时,正如这里的BookAuthors,当然,连接表的关系仍然是由两个M:1关系构成。

  例如,BookAuthor包涵一个到Book的M:1关系和一个到Author的M:1关系来构成M:M的关系:

  不幸的是,你仍然需要创建一个类来映射这个关联表。然而,由于外键的原因,它仅仅用于映射的关系,你可以通过设置类的访问修饰符为internal来保持仅对外提供一个公共接口。

  1、使用[Table]特性创建一个内部类用于映射需要连接的表

  以BookAuthors类相同的方式创建为其他实体类,但是不要将其标记为public:

using System.Data.Linq;
using System.Data.Linq.Mapping;
namespace LINQDemo
{
[Table( Name = "BookAuthors" )]
class BookAuthor{}
}

  2、映射两表之间的M:1关系,指定它们将其作为主键

  为Book和Author创建一个M:1的关系并以相同的方式为Book:Catalog创建关系。注意数据库中BookAuthors表的关系以下面的方式命名:

  ● BookAuthor:Authors关系被命名为 FK_BookAuthors_Authors

  ● BookAuthor:Books 关系被命名为FK_BookAuthors_Books

  分别在它的两个Column特性上为其添加IsPrimaryKey = true的属性以指示BookAuthors的主键由这两个值构成:

[Table( Name = "BookAuthors" )]
class BookAuthor
{
[Column( IsPrimaryKey = true, Name = "Author" )] private int authorId;
private EntityRef _author = new EntityRef( );
[Association( Name = "FK_BookAuthors_Authors", IsForeignKey = true,
Storage = "_author", ThisKey = "authorId" )]
public Author Author {
get { return _author.Entity; }
set { _author.Entity = value; }
}
Column( IsPrimaryKey = true, Name = "Book" )] private int bookId;
private EntityRef _book = new EntityRef( );
[Association( Name = "FK_BookAuthors_Books", IsForeignKey = true,
Storage = "_book", ThisKey = "bookId" )]
public Book Book {
get { return _book.Entity; }
set { _book.Entity = value; }
}
}

  虽然我们已经探讨了M:1的关系,但不幸的是,你仍然还不能使用BookAuthor做一些有趣的事,当我们在下面讨论M:M的关系时,将继续回到表连接的探讨话题上来。但首先,通过理解如何映射1:M的关系,我们可以看看Book:Catalog的关系来完整理解M:M的关系。

  映射1:M关系

  添加一个1:M的关系使得你可以获得一个属于Category的所有书籍列表。

  1、在其它类中映射外键

  即使你正在为Category添加关联关系,它仍然需要知道如何关联到Book本身。因此,你仅需要确保你的Book类已经映射到了对应的列,该列应该是关联到Category的外键。如果你这样实现,那么你已经完成了1:M的关系,因此这时你所要做的就是指定字段名:categoryId:

 

[Table( Name = "Books" )]
public class Book
{
...
[Column( Name = "Category" )] private int? categoryId;

 

  2、映射你自己的主键

  LINQ会比较Book的外键和Category的外键,因此你需要映射Category.Id并标识其作为主键([Column (IsPrimaryKey = true)])。再次,如果你继续这个步骤,你已经在实体类中完成了该过程的创建。因此,所要做的仅仅是为该属性名Id添加一个注释:

 

[Table (Name="BookCategories")]
public class Category
{
[Column ( IsPrimaryKey = true, IsDbGenerated = true )] public int Id { get; set; }
...

 

  3、添加一个私有的EntitySet类型以实现对其他表的引用

  添加一个私有的EntitySet字段来接收属于该Category的书籍。这将让我们的公有Books属性扮演字段的角色。类似地,EntityRef,EntitySet会引起对Books的加载延迟直到我们实际访问它的时候(因此,当我们需要查看一个类别的时候,我们不必每次都返回所有书的列表)。

  初始化EntitySet字段以避免NullReferenceExceptions异常的发生,比如在你没有设置两边关系的时候(如一个类别没有书籍的时候)

 

private EntitySet _books = new EntitySet();

 

  4、为相关联的类添加属性

  最后创建公有Books属性,它用于接收在对应类别中的书籍。为该属性添加一个Association特性。并设置数据库关系的名称参数为Name (FK_Books_BookCategories),以及使用刚才创建这个字段的特性所需要的三个参数:

  ● OtherKey指定关联到其他类(Book)的字段,该字段接收所关联的外键:categoryId

  ● ThisKey指定你的主键(OtherKey所应该匹配的字段):Id

  ● Storage指定你的EntitySet类型,该类型用来存储相关联的Books集合:_books.

  在属性内部,代码getter/setter访问修饰符使用了 _books,它包涵一个实际Book实例的ICollection集合:

 

[Association( Name = "FK_Books_BookCategories",
Storage = "_books", OtherKey = "categoryId", ThisKey = "Id" )]
public ICollection Books {
get { return _books; }
set { _books.Assign( value ); }
}

 

  从1:M 关系上访问数据

  现在,你可以通过使用category.Books属性访问每个类别中的Books列表:

 

foreach( var category in bookCatalog.Categories ){
foreach( Book book in category.Books ){
string bookTitle = book.Title;
}
}



  映射M:M 关系

  最后,添加M:M关系,这可以允许你直接从Book实例中访问每个目录下下的所有作者,以及从Author实例中直接访问某个作者写的所有书籍。

  通过创建BookAuthor类,说明你已经完成了该任务的大部分工作了。并且,你也在前面部分已经了解到当你需要创建1:M时如何实现这一功能。现在,是该将它们整合起来的时候了。再次,我们将使用Book作为示例进行阐述。

  1、从类到关联的表上添加一个1:M的关系

  Book到BookAuthor 它存在一个1:M的关系,每本书都可以有多个作者,但是每本书作者仅仅属于一本书。因此,你必须得从先前已有的部分开始进行如下四个步骤:

  ● bookId. 在BookAuthor类中映射到Book的外键。你已经这样实现了,会调用它的:bookId。

  ● 为Book对象定义主键。你也已经这样实现了,会调用它的:Id。

  ● Add an EntitySet that references the other table: _bookAuthors. 添加一个引用其他表的EntitySet类型。

  ● 添加一个BookAuthors属性(将其设置为私有的,因为这里仅仅用于帮助获得作者列表),该属性添加了Association特性并为其设置前面部分设置的三个参数值。

  添加Book对象代码的第3和第4步如下:

[Table( Name = "Books" )]
public class Book
{
...
private EntitySet _bookAuthors = new EntitySet( );
[Association( Name = "FK_BookAuthors_Books",
Storage = "_bookAuthors", OtherKey = "bookId",
ThisKey = "Id" )]
private ICollection BookAuthors {
get { return _bookAuthors; }
set { _bookAuthors.Assign( value ); }
}

  虽然你可以在Author中实现相同的功能(因为每个作者都可以有多本书),但是使用authorId取代bookId:

[Table( Name = "Authors" )]
public class Author
{
...
private EntitySet _bookAuthors = new EntitySet( );
[Association( Name = "FK_BookAuthors_Authors",
Storage = "_bookAuthors",
OtherKey = "authorId", ThisKey = "Id" )]
private ICollection BookAuthors {
get { return _bookAuthors; }
set { _bookAuthors.Assign( value ); }
}

  2、添加一个公有属性,通过1:M的关系使用LINQ 来检索枚举数据。

  最后,通过创建Authors属性从该书实例的私有书作者列表中检索所有作者。例如,如果你有一本LINQ In Action的书,该书就有三个作者:Fabrice Marguerie, Steve Eichert, 和Jim Wooley,那么LINQ In Action Book实例将包涵三个BookAuthors的列表:


posted @ 2011-11-24 16:43 顺其自然EVO 阅读(288) | 评论 (0)编辑 收藏

开源工具高效分析Java应用

开源工具高效分析Java应用


 不止一次,我们都萌发过想对运行中程序的底层状况一探究竟的念头。产生这种需求的原因可能是运行缓慢的服务、Java虚拟机(JVM)崩溃、挂起、死锁、频繁的JVM暂停、突然或持续的高CPU使用率、甚至于可怕的内存溢出(OOME)。好消息是现在已有许多工具能帮你得到Java虚拟机运行过程中的不同参数,这些信息有助于你了解其内部状况,从而诊断上述的各种情况。

  在这篇文章中,我将介绍一些优秀的开源工具。其中一些是JVM自带的,另一些则是第三方工具。我将从最简单的工具开始介绍,逐渐过渡到一些比较复杂的工具。本文的目的是帮助你找到合适的调试诊断工具,这样当程序出现执行异常、缓慢或根本不能执行时,手头随时有可用的工具。

  好了,让我们出发。

  如果程序出现不正常的高内存负载、频繁无响应或内存溢出,通常最好的分析切入点是查看内存对象。幸好JVM内置了工具“jmap”,让它天生就能完成这种任务。

  Jmap(借助JPM的一点帮助)

  Oracle将jmap描述为一种“输出进程、核心文件、远程调试服务器的共享对象内存映射和堆内存细节”的程序。本文将使用jmap打印一张内存统计图。

  为了运行jmap,你需要知道被调试程序的PID(进程标识符)。得到PID的简单办法是使用JVM提供的jps,它能列出机器上每一个JVM进程及其PID。jps输出结果如下图:

图1:jps命令的终端输出

  为了打印内存统计图,我们需要打开jmap控制台程序,并输入程序的PID和“-histo:live”选项。如果不添加这个选项,jmap将完整导出该程序的堆内存,这不是我们想要的结果。所以,如果想得到上图中“eureka.Proxy”程序的内存统计图,我们应该用如下命令来运行jmap:

  jmap –histo:live 45417

  上述命令输出如下:

图2:命令jmap -histo:live的输出结果显示了堆中现有对象的个数

  结果中每行显示了当前堆中每种类类型的信息,包含被分配的实例个数及其消耗的字节数。

  本例中,我请同事有意给程序增加了一处明显的内存泄露。请特别注意位于第8行的类,CelleData。将它与下图显示的4分钟后截屏进行比较:

图3:jmap的输出表明CelleData类的对象数目增加了

  请注意CelleData类现在已经变为系统中第二多的类,短短4分钟内已经增加了631,701个额外实例。等待约一小时后,我们观察到如下结果:

图4:程序执行1小时后jmap的输出结果,显示超过2千5百万个CelleData类实例

  现在有超过2千5百万个CelleData类实例,占用了超过1GB内存!我们可以确认这是一个内存泄露。

  这类数据信息的好处是,不仅非常有用而且对于很大的JVM堆也能快速反馈结果。我曾经试过检测一个运行频繁并且占用17GB堆内存的程序,使用jmap能够在1分钟内生成程序的性能统计图。

  需要注意的是,jmap不是运行分析工具,在生成统计图时JVM可能会暂停,因此当生成统计图时需要确认这种暂停对程序是可接受的。以我的经验,通常在调试一个严重bug时需要生成这种统计图,这种情况下,这些1分钟的暂停对程序来说是可接受的。这里,我们引出了下一个话题 - 半自动的运行分析工具VisualVM。

  VisualVM

  另一个包含于JVM中的工具是VisualVM,它的开发者将它描述为“一种集成了多个JDK命令行工具的可视化工具,它能为您提供轻量级的运行分析能力”。这样看来,VisualVM是另一种你最有可能用到的事后分析工具,一般是错误已出现或性能问题已经用传统方法(客户抱怨大多属于此类)发现。

  继续之前的示例程序和它严重的内存泄露问题,在程序执行30分钟后,VisualVM帮我们绘制了如下图表:

图5:程序初始运行的VisualVM 内存图

  从这个图表,我们可以清晰地看到截止到7:00pm,运行仅仅10分钟后,程序已经消耗掉超过1GB的堆空间。又过了23分钟,JVM已经到了它启动参数–Xmx3g最大值,导致程序响应缓慢,系统响应缓慢(持续的垃圾回收)和数量惊人的内存溢出错误。

  借助jmap,我们定位了这种内存消耗攀升的原因。修复后,我们让程序重新运行于VisualVM的严格监测之下,观察到下面的情况:

图6:修复内存泄露问题后的VisualVM内存图


  如你所见,程序的内存曲线(启动参数仍然为–Xmx3g)有了明显改善。

  除了内存图像工具,VisualVM还提供了一个采样器和一个轻量级的剖析器(Profiler)。

  VisualVM采样器能周期采样程序CPU和内存的使用情况。得到的统计数据类似jmap的反馈,此外,你还可以通过采样得到方法调用对CPU的占用情况。它让你能快速了解周期采样过程中的方法执行次数:

图7:VisualVM方法执行时间表

  VisualVM剖析器无需对程序周期采样就可以提供类似采样器的反馈信息,它还可以收集程序在整个正常执行过程中的统计数据(通过操纵程序源代码的字节码)。从剖析器得到的这种统计数据比从采样器而来的更精确和实时。

图8:VisualVM剖析器的输出

  但是,你必须考虑的另一方面是该剖析器属于一种“暴力”分析工具。它的检测方法本质上是重新定义程序执行中的大多数类和方法,结果必然会明显减缓程序执行速度。例如,上述程序运行部分的常规分析,大约要35秒。开启VisualVM的内存剖析器后,导致程序完成相同分析要31分钟。

  我们需要清楚的是VisualVM并非功能齐全的剖析器。它无法在你的产品JVM上持续运行,不会保存分析数据,无法指定阈值,也不会在超过阈值时发出警报。要想更多的了解功能齐全的剖析器的目标。下面,让我们看看BTrace,这个功能齐全的开源java代理程序。

  BTrace

  想象一下,如果能收集JVM当前的任何信息,那么你感兴趣的信息有哪些?我猜想问题列表会将因人而异,因情形而异。就个人来说,我通常感兴趣的是以下的问题:

  程序对堆、非堆、永久保存区(Permanent Generation),以及JVM包含的不同内存池(新生对象区、长期对象区、存活空间等)的内存使用情况

  当前程序的线程数量,以及哪种类型线程正在被使用(单独计数)


  JVM的CUP负载

  系统平均负载/系统CPU使用总和

  对程序中的某些类和方法,我需要了解它们被调用次数,各自平均执行时间和整体平均时间

  对SQL调用的调用计数及执行次数

  对硬盘和网络操作的调用计数及执行次数

  利用BTrace可以采集到所有以上信息,你可以使用BTrace脚本定义需要采集的数据。方便的是,BTrace脚本就是普通Java类,包含一些特殊注解来定义BTrace在什么地方及如何跟踪你的程序。BTrace脚本会被BTrace编译器-btracec编译成标准的.class文件。

  BTrace脚本包含许多部分,正如下图所示。如果需要了解下图脚本的详细内容,请点击该链接或访问BTrace项目网站。

  由于BTrace仅仅是一个代理,记录结果后,它的任务就算完成了。除了文本输出,BTrace并不具备动态展现被收集信息的功能。缺省情况下,BTrace脚本输出结果将在btrace.class文件所在位置生成一个名为BTrace脚本名.class.btrace的text文件。

  我们可以通过给BTrace设置一个额外参数,让它按某时间间隔循环记录日志。切记,它最多能在100个日志文件间循环,当达到*.class.btrace.99,它将覆盖*.class.btrace.00文件。若让循环间隔在一个合理数字(如,每7.5秒)内,你就有充足时间来处理这些输出。只要在java代理的输入参数中加上fileRollMilliseconds=7500,就可以实现日志循环。

  BTrace一大缺点是它比较原始,难以定义它的输出格式。你也许非常希望有一种更好的方式来处理BTrace的输出和数据,比如可以用一种一致的图形用户界面来展示。你可能还需要比较不同时间点的数据和超出阈值能发送警告。一个新的开源工具EurekaJ,就此应运而生。

图9:激活方法分析时必需的BTrace脚本

  JVM的CUP负载

  系统平均负载/系统CPU使用总和

  对程序中的某些类和方法,我需要了解它们被调用次数,各自平均执行时间和整体平均时间

  对SQL调用的调用计数及执行次数

  对硬盘和网络操作的调用计数及执行次数

  利用BTrace可以采集到所有以上信息,你可以使用BTrace脚本定义需要采集的数据。方便的是,BTrace脚本就是普通Java类,包含一些特殊注解来定义BTrace在什么地方及如何跟踪你的程序。BTrace脚本会被BTrace编译器-btracec编译成标准的.class文件。

  BTrace脚本包含许多部分,正如下图所示。如果需要了解下图脚本的详细内容,请点击该链接或访问BTrace项目网站。

  由于BTrace仅仅是一个代理,记录结果后,它的任务就算完成了。除了文本输出,BTrace并不具备动态展现被收集信息的功能。缺省情况下,BTrace脚本输出结果将在btrace.class文件所在位置生成一个名为BTrace脚本名.class.btrace的text文件。

  我们可以通过给BTrace设置一个额外参数,让它按某时间间隔循环记录日志。切记,它最多能在100个日志文件间循环,当达到*.class.btrace.99,它将覆盖*.class.btrace.00文件。若让循环间隔在一个合理数字(如,每7.5秒)内,你就有充足时间来处理这些输出。只要在java代理的输入参数中加上fileRollMilliseconds=7500,就可以实现日志循环。

  BTrace一大缺点是它比较原始,难以定义它的输出格式。你也许非常希望有一种更好的方式来处理BTrace的输出和数据,比如可以用一种一致的图形用户界面来展示。你可能还需要比较不同时间点的数据和超出阈值能发送警告。一个新的开源工具EurekaJ,就此应运而生。

图9:激活方法分析时必需的BTrace脚本

 

posted @ 2011-11-24 11:08 顺其自然EVO 阅读(510) | 评论 (0)编辑 收藏

SQL语句技巧

 1、应用程序中,保证在实现功能的基础上,尽量减少对数据库的访问次数;通过搜索参数,尽量减少对表的访问行数,最小化结果集,从而减轻网络负担;能够分开的操作尽量分开处理,提高每次的响应速度;在数据窗口使用SQL时,尽量把使用的索引放在选择的首列;算法的结构尽量简单;在查询时,不要过多地使用通配符如SELECT * FROM T1语句,要用到几列就选择几列如:SELECT COL1,COL2 FROM T1;在可能的情况下尽量限制尽量结果集行数如:SELECT TOP 300

  COL1,COL2,COL3 FROM T1,因为某些情况下用户是不需要那么多的数据的。不要在应用中使用数据库游标,游标是非常有用的工具,但比使用常规的、面向集的SQL语句需要更大的开销;按照特定顺序提取数据的查找。

  2、避免使用不兼容的数据类型。例如float和int、char和varchar、binary和varbinary是不兼容的。数据类型的不兼容可能使优化器无法执行一些本来可以进行的优化操作。例如:

  SELECT name FROM employee WHERE salary > 60000

  在这条语句中,如salary字段是money型的,则优化器很难对其进行优化,因为60000是个整型数。我们应当在编程时将整型转化成为钱币型,而不要等到运行时转化。

  3、尽量避免在WHERE子句中对字段进行函数或表达式操作,这将导致引擎放弃使用索引而进行全表扫描。如:

  SELECT * FROM T1 WHERE F1/2=100

  应改为:

  SELECT * FROM T1 WHERE F1=100*2
  SELECT * FROM RECORD WHERE SUBSTRING(CARD_NO,1,4)=’5378’

  应改为:

  SELECT * FROM RECORD WHERE CARD_NO LIKE ‘5378%’
  SELECT member_number, first_name, last_name FROM members
  WHERE DATEDIFF(yy,datofbirth,GETDATE()) > 21

  应改为:

  SELECT member_number, first_name, last_name FROM members
  WHERE dateofbirth < DATEADD(yy,-21,GETDATE())

  即:任何对列的操作都将导致表扫描,它包括数据库函数、计算表达式等等,查询时要尽可能将操作移至等号右边。

  4、避免使用!=或<>、IS NULL或IS NOT NULL、IN ,NOT IN等这样的操作符,因为这会使系统无法使用索引,而只能直接搜索表中的数据。例如:

  SELECT id FROM employee WHERE id != 'B%'

  优化器将无法通过索引来确定将要命中的行数,因此需要搜索该表的所有行。

  5、尽量使用数字型字段,一部分开发人员和数据库管理人员喜欢把包含数值信息的字段设计为字符型,这会降低查询和连接的性能,并会增加存储开销。这是因为引擎在处理查询和连接回逐个比较字符串中每一个字符,而对于数字型而言只需要比较一次就够了。

  6、合理使用EXISTS,NOT EXISTS子句。如下所示:

  1)SELECT SUM(T1.C1)FROM T1 WHERE(
  (SELECT COUNT(*)FROM T2 WHERE T2.C2=T1.C2>0)

  2)SELECT SUM(T1.C1) FROM T1WHERE EXISTS(
  SELECT * FROM T2 WHERE T2.C2=T1.C2)

  两者产生相同的结果,但是后者的效率显然要高于前者。因为后者不会产生大量锁定的表扫描或是索引扫描。

  如果你想校验表里是否存在某条纪录,不要用count(*)那样效率很低,而且浪费服务器资源。可以用EXISTS代替。如:

  IF (SELECT COUNT(*) FROM table_name WHERE column_name = 'xxx')

  可以写成:

  IF EXISTS (SELECT * FROM table_name WHERE column_name = 'xxx')

 经常需要写一个T_SQL语句比较一个父结果集和子结果集,从而找到是否存在在父结果集中有而在子结果集中没有的记录,如:

  (1)SELECT a.hdr_key FROM hdr_tbl a---- tbl a 表示tbl用别名a代替
  WHERE NOT EXISTS (SELECT * FROM dtl_tbl b WHERE a.hdr_key = b.hdr_key)

  (2)SELECT a.hdr_key FROM hdr_tbl a
  LEFT JOIN dtl_tbl b ON a.hdr_key = b.hdr_key WHERE b.hdr_key IS NULL

  (3)SELECT hdr_key FROM hdr_tbl
  WHERE hdr_key NOT IN (SELECT hdr_key FROM dtl_tbl)

  三种写法都可以得到同样正确的结果,但是效率依次降低。

  7、尽量避免在索引过的字符数据中,使用非打头字母搜索。这也使得引擎无法利用索引。

  见如下例子:

  SELECT * FROM T1 WHERE NAME LIKE ‘%L%’
  SELECT * FROM T1 WHERE SUBSTING(NAME,2,1)=’L’
  SELECT * FROM T1 WHERE NAME LIKE ‘L%’

  即使NAME字段建有索引,前两个查询依然无法利用索引完成加快操作,引擎不得不对全表所有数据逐条操作来完成任务。而第三个查询能够使用索引来加快操作。

  8、分利用连接条件,在某种情况下,两个表之间可能不只一个的连接条件,这时在 WHERE 子句中将连接条件完整的写上,有可能大大提高查询速度。

  例:

  SELECT SUM(A.AMOUNT) FROM ACCOUNT A,CARD B WHERE A.CARD_NO = B.CARD_NO
  SELECT SUM(A.AMOUNT) FROM ACCOUNT A,CARD B WHERE A.CARD_NO = B.CARD_NO
  AND A.ACCOUNT_NO=B.ACCOUNT_NO

  第二句将比第一句执行快得多。

  9、消除对大型表行数据的顺序存取尽管在所有的检查列上都有索引,但某些形式的WHERE子句强迫优化器使用顺序存取。如:

  SELECT * FROM orders WHERE (customer_num=104 AND order_num>1001) OR
  order_num=1008

  解决办法可以使用并集来避免顺序存取:

  SELECT * FROM orders WHERE customer_num=104 AND order_num>1001
  UNION
  SELECT * FROM orders WHERE order_num=1008

  这样就能利用索引路径处理查询。

  10、避免困难的正规表达式

  LIKE关键字支持通配符匹配,技术上叫正规表达式。但这种匹配特别耗费时间。例如:SELECT * FROM customer WHERE zipcode LIKE “98_ _ _”

  即使在zipcode字段上建立了索引,在这种情况下也还是采用顺序扫描的方式。如果把语句改为SELECT * FROM customer WHERE zipcode >“98000”,在执行查询时就会利用索引来查询,显然会大大提高速度。

 11、使用视图加速查询

  把表的一个子集进行排序并创建视图,有时能加速查询。它有助于避免多重排序操作,而且在其他方面还能简化优化器的工作。例如:

  SELECT cust.name,rcvbles.balance,……other columns
  FROM cust,rcvbles
  WHERE cust.customer_id = rcvlbes.customer_id
  AND rcvblls.balance>0
  AND cust.postcode>“98000”
  ORDER BY cust.name

  如果这个查询要被执行多次而不止一次,可以把所有未付款的客户找出来放在一个视图中,并按客户的名字进行排序:

  CREATE VIEW DBO.V_CUST_RCVLBES
  AS
  SELECT cust.name,rcvbles.balance,……other columns
  FROM cust,rcvbles
  WHERE cust.customer_id = rcvlbes.customer_id
  AND rcvblls.balance>0
  ORDER BY cust.name

  然后以下面的方式在视图中查询:

  SELECT * FROM V_CUST_RCVLBES
  WHERE postcode>“98000”

  视图中的行要比主表中的行少,而且物理顺序就是所要求的顺序,减少了磁盘I/O,所以查询工作量可以得到大幅减少。

  12、能够用BETWEEN的就不要用IN

  SELECT * FROM T1 WHERE ID IN (10,11,12,13,14)

  改成:

  SELECT * FROM T1 WHERE ID BETWEEN 10 AND 14

  因为IN会使系统无法使用索引,而只能直接搜索表中的数据。

  13、DISTINCT的就不用GROUP BY

  SELECT OrderID FROM Details WHERE UnitPrice > 10 GROUP BY OrderID

  可改为:

  SELECT DISTINCT OrderID FROM Details WHERE UnitPrice > 10

  14、部分利用索引

  1)SELECT employeeID, firstname, lastname
  FROM names
  WHERE dept = 'prod' or city = 'Orlando' or division = 'food'

  2)SELECT employeeID, firstname, lastname FROM names WHERE dept =
  'prod'
  UNION ALL
  SELECT employeeID, firstname, lastname FROM names WHERE city = 'Orlando'
  UNION ALL
  SELECT employeeID, firstname, lastname FROM names WHERE division =
  'food'

  如果dept 列建有索引则查询2可以部分利用索引,查询1则不能。

 15、能用UNION ALL就不要用UNION

  UNION ALL不执行SELECT DISTINCT函数,这样就会减少很多不必要的资源

  16、不要写一些不做任何事的查询

  如:SELECT COL1 FROM T1 WHERE 1=0
  SELECT COL1 FROM T1 WHERE COL1=1 AND COL1=2

  这类死码不会返回任何结果集,但是会消耗系统资源。

  17、尽量不要用SELECT INTO语句。

  SELECT INTO 语句会导致表锁定,阻止其他用户访问该表。

  18、必要时强制查询优化器使用某个索引

  SELECT * FROM T1 WHERE nextprocess = 1 AND processid IN (8,32,45)

  改成:

  SELECT * FROM T1 (INDEX = IX_ProcessID) WHERE nextprocess = 1 AND
  processid IN (8,32,45)

  则查询优化器将会强行利用索引IX_ProcessID 执行查询。

  19、虽然UPDATE、DELETE语句的写法基本固定,但是还是对UPDATE语句给点建议:

  a)尽量不要修改主键字段。

  b)当修改VARCHAR型字段时,尽量使用相同长度内容的值代替。

  c)尽量最小化对于含有UPDATE触发器的表的UPDATE操作。

  d)避免UPDATE将要复制到其他数据库的列。

  e)避免UPDATE建有很多索引的列。

  f)避免UPDATE在WHERE子句条件中的列。

  上面我们提到的是一些基本的提高查询速度的注意事项,但是在更多的情况下,往往需要反复试验比较不同的语句以得到最佳方案。最好的方法当然是测试,看实现相同功能的SQL语句哪个执行时间最少,但是数据库中如果数据量很少,是比较不出来的,这时可以用查看执行计划,即:把实现相同功能的多条SQL语句考到查询分析器,按CTRL+L看查所利用的索引,表扫描次数(这两个对性能影响最大),总体上看询成本百分比即可。

  简单的存储过程可以用向导自动生成:在企业管理器工具栏点击运行向导图标,点击”数据库”、”创建存储过程向导”。复杂存储过程的调试:在查询分析器左边的对象浏览器(没有?按F8)选择要调试的存储过程,点右键,点调试,输入参数执行,出现一个浮动工具条,上面有单步执行,断点设置等。


posted @ 2011-11-23 17:49 顺其自然EVO 阅读(152) | 评论 (0)编辑 收藏

我眼中的敏捷设计

 2001年,许多公司的软件团队陷入不断增长的流程困境,为了解决这个问题,这个领域中最优秀的experts一起概括出了一些全新的价值观和原则,从而可以让软件开发团队具有快速工作、响应变化能力,他们自称为敏捷联盟。敏捷开发过程的方法很多,包括Scrum, eXtreme Programming, Feature Driven Development, Adaptive Software Development等等。目前,我所在的公司内部也有很多团队开始启用Scrum的开发流程,力图改变瀑布式开发模型的诸多弊端。作为Run了3年该流程的team,我们团队在不断学习和总结中得到了进步,我也希望可以从设计的角度来分享一些敏捷开发流程中快速迭代设计的心得。

  Process 流程

  这是一个高速变化的时代,无论是产品的更新还是技术的进化,同时变幻莫测的需求对传统软件开发模式造成了极大的冲击。当用户需求不断变化造成软件开发目标的不断更换,传统的设计方式会举步维艰,从而造成了软件的滞后,总是无法贴近用户的实时需求。快速迭代设计的特点是:先设计出稿,再不断改进。白鸦在 2011中国交互设计体验日上分享到:“怎么做都是错的。唯有迭代的速度,才能取胜。” 可见,快速迭代的要求,无论是对研发还是设计,都已迫在眉睫。

  整个快速迭代设计流程分为5个阶段:

  Iteration-1

  前期准备阶段,团队很容易就各类需求该放哪些进入Sprint backlog发生讨论,设计师主要参与PO(Product Owner)/PM组织的用户需求讨论,对需求优先级排序,解读一些用户潜在需求并转化成为产品功能需求,毕竟相比他们,设计师更加懂得产品细节。 同时,设计师可以同步展开用户研究的工作,了解Persona的主要工作流和Goal。

  Iteration 0

  与每个项目开始之前设定Sprint 0相同,Sprint里也有一个叫Iteration 0的阶段,包括设计开工之前的验证与出具设计方案。通过与开发团队的沟通来验证设计方向与设计方案的可行性,可以创建一些信息流图与内容结构,做好坚实的设计架构。同时,在用户需求被解读成为功能列表后,利用纸片、PPT、Balsamiq等工具创建快速原型,最好在这个阶段让研发团队介入,对设计原型进行评估。然后设计师根据快速原型,负责设计其实现方式,通常会有几个解决方案。在Scrum团队内部与开发测试人员反复讨论权衡后,选出最优方案。这个阶段设计师的交付物为交互线框图、低保真模型等简单设计文档。

  Iterations

  设计不断迭代的阶段,因为我们假设改阶段用户需求已经确定,所以主要是基于设计方案的迭代,协同开发实现的进度,将设计不断修正至最优。正是这种快速的模式让设计师能在一个可以体验的原型上验证设计,从而改进设计。与流行的测试驱动开发(TDD)类似,我们也可以采用测试驱动设计的方式。QA要对用户的背景和工作模式比较熟悉,协同设计师一起敲定User Story,撰写Real User Test Scenarios,并根据测试结果优化设计。设计师与开发团队成员一并进行Usability Testing,以便在早期消除可用性缺陷,减轻后期维护成本。

  Release

  作为design release的阶段,前面的工作主要内容是确定功能的主要逻辑与工作流,这个时期,我们可以在优使性(Usability)上有所提升,做好Final Usability Testing,确认没太大疏漏,再将其发布出去。不同于QA的最终验收测试,这里的可用性测试需要从用户的角度去“使用”产品,不是去找功能的缺陷,而是从优使性方面看是否顺手,是否符合用户心智模型,是否高效完成用户目标。

  Production

  设计发布过后,为了适应不断更新和快速迭代的需要,设计师在这个时期的工作重心从偏用研设计转移到偏运营维护的方面来,一方面收集一些用户反馈和wishlist,改进之前的不足;另外一方面为了产品的下一个迭代更新做好规划,方便产品的发展和扩充。

整个流程有两个迭代循环:

  1、Requirements Iteration

  这个迭代循环贯穿于整个敏捷设计流程。用户需求随着时间推移不断更新,整个设计流程的迭代。根据以用户为中心的设计思想,当用户的需求发生变化时,在设计流程中要及时响应,做出调整变化。

  2、Solution Iteration

  这个迭代循环主要指Iterations阶段,用户需求相对确定,设计方案的不断优化更新。当需求基本确定后,设计师需要配合开发团队不断优化设计思路,提供更优的设计解决方案。

  特别需要注意的是,前面两个阶段(Iteration -1, Iteration 0),应该早于当前研发的Sprint N一个周期(Sprint N-1)进行。进入当前的Sprint工作周期,完成第一个迭代设计后,研发团队可以开始该部分内容的开发测试,与设计师不断互动推动迭代。在Sprint N的末期,设计师完成当前Sprint的基本设计工作后,开始收集前面Sprints release内容的反馈。团队不需要提前太多进行设计,要保持需求的最新update,主要依赖测试结果作为支撑,不断持续改进优化设计,以便每次迭代结束后产出物都最适合当前迭代的需求。

  Rules 原则

  快速迭代设计的一些原则:

  验证可行性的必要

  完美的敏捷思想是团队中的每个人都是全才,大家都可以design,coding,testing。不过这样的团队不多,全才的混合有时候更容易造成管理混乱,相反,专才的合理搭配能产生更好的效果。所以,如果你不会写代码,一定要在设计早期拉上开发人员,坐在一起慢慢探讨设计可行性,用代码验证原型之后,再确定方案。

  测试用例验证设计的重要性

  根据测试驱动设计的理念,设计师与QA协同合作,利用早期测试结果驱动设计更新,比设计师长期独自酝酿出的详细设计文档更有用。行不行,利用草图或者低保真原型让QA去测测看就知道。Scrum鼓励充分沟通与互动,这个时候QA的测试用例能发现很多设计缺陷和遗漏。TDD如下图所示:





注重团队设计

  与瀑布模型的单打独斗不同,快速迭代设计更推崇团队设计,由设计师主导,把握设计框架,整个团队给出解决方案。一些design scenario和workflow的归纳,即使经验丰富的设计师,也不如团队智慧来的全面,当然,除非你是乔帮主,使用导演中心论的设计流程。另外,团队设计的好处还可以减轻设计师的负担与压力,一起承担产品兴亡的重任比一个人承担要安全可靠的多。

  设计不多不少,恰好就行

  兵贵神速,指的就是以快为王。特别是在快速迭代设计中,你不必在你的原型或草图中事无巨细的列出所有可能,完美的概念在这里是不适用的,甚至你不需要完成设计的整个部分,只要把关键模块讲清楚了,开发与测试理解了,就足够。想想那些精美的设计文档中无数看上去perfect的图片和排版,最后真的有人在乎吗?只要你在迭代开发流程中能于脑海中攫取所有细节并传递给团队,不要文档都可以。无需太具体,思考那些真正有价值的地方。

  写好User Story

  User Story是在Agile开发流程中从用户角度对系统的某个功能模块进行的简短描述,它包含了目标用户(不同角色)、功能需要(可以做什么)以及其创造的价值(实现目的)。它可以是:

  1、一个用户需求

  2、产品功能的描述

  3、用来计划和追踪任务的工具

  4、团队沟通的桥梁

  通常我们把一个User Story按照以下格式写在即时贴上:

  以第一个句型为例:

  As a _ I would like _ so that _
  作为(某个角色),我希望可以(做什么),以达到(什么目的)

  User Story照理应该是由PO写,不过有些团队(比如我们:D)是由设计师来完成,同时在即时贴上标注预估完成时间(我们团队采用了Story Point这样一种估算方法,这里不赘述)和优先级别,以便开发团队根据它们来形成Sprint Backlog。

任务量

  不同的功能模块其工作量也不尽相同,我们可以按以下三种类型划分:

  1、Large

  一般来说每个User Story都需要在一个Sprint内完成,避免太大而跨越几个Sprint。如果出现太大的User Story导致一个Sprint塞不下,则需要将User Story分解,这个Sprint完成一部分,但是不release,只是demo给PO/PM, 余下的在接下来的Sprint里完成。

  2、Normal

  按正常流程进行快速迭代设计。

  3、Mini

  JDI (Just Do It), 一些小功能的实现无需文档,任何沟通方式都可以用来传达你的设计思路,然后交由开发去实现。

  关于文档

  原本瀑布开发模式下设计师的唯一交付物Specification,在快速迭代设计中已经不是那么重要,因为快速变化的用户需求让设计节奏加速,不断更新维护Specification成本太高。用户是为你设计出的产品或者功能付款,而不是你的设计文档,所以传递设计思想才是主要目的,PPT、Visio等Wireframe或者email、meeting notes等记录都可以作为设计参照。

  对于文档,我们一般遵循如下原则:

  尽可能在文档中简单的描述需求、分析结果、信息架构和设计细节,只要它们恰好满足PO的要求即可。

  如果该Scenario的逻辑足够复杂,那么请毫不犹豫的用文档详细的描述,以开发团队恰好能充分理解为宜。

  文档的简繁程度需要经过几个Sprint的迭代,才能找到最合适的level。

  保持一直设计

  设计对产品来说如此重要,特别是在敏捷开发流程中,没有一个专门的设计阶段(There is no design phase),整个流程都伴随的设计。从前期纸片概念,白板框架,用户场景测试,到具体细节代码实现,终极用户测试,都离不开设计的跟随。这不再是那个只需要在早期完成设计就弃之不管的模式,他要求你每天都不停的参加讨论参入迭代参与设计。

  Epilogue 后记

  我们团队面对的是一款由公司早期元老打造的工程领域软件,它的用户基数庞大,它的地位曾经显赫。然而它的功能逐渐老化,模块架构也相对固化,开发团队很难对整个系统进行改动,因为整个软件架构已经固定,任何大的改动都是牵一发而动全身,不但会造成许多与改动处无关的环节出现问题,莫名其妙的regression defect也让QA措手不及。一些设计改进都必须得在之前设计的基础上进行调整,力求一致性,很难加入全新的交互模式和UI风格。同时,正是由于产品功能没有大幅度的更新,瀑布模式比较擅长的低风险复杂功能开发已经无法满足用户需求的小快灵。 因此,我们目前所使用的敏捷设计流程尽管无法跟全新开发的产品一样自由,只是在大框架的制约下进行功能的迭代更新,但也取得了不错的效果,3年做下来完成了许多小功能的快速成功发布,提升了大家对于Scrum流程继续使用的信心,致力于建立一个持续的可改进的快速响应团队。本文所提及的流程并不适用所有情况,希望大家各取所需,保留对自己有价值的部分,摒弃不适合的。

posted @ 2011-11-23 17:47 顺其自然EVO 阅读(167) | 评论 (0)编辑 收藏

仅列出标题
共394页: First 上一页 358 359 360 361 362 363 364 365 366 下一页 Last 
<2024年11月>
272829303112
3456789
10111213141516
17181920212223
24252627282930
1234567

导航

统计

常用链接

留言簿(55)

随笔分类

随笔档案

文章分类

文章档案

搜索

最新评论

阅读排行榜

评论排行榜