中文User Stories Applied For Agile Software Development
更新时间:2024-04-20 12:07:01 阅读量: 综合文库 文档下载
- 中文user是什么意思推荐度:
- 相关推荐
来源:http://space.flash8.net/space/?610884/
敏捷开发已经越来越受到人们的关注,User Story作为敏捷需求分析的一 种重要工具和方法,也越来越受到敏捷开发团队的重视,但是市面上关于User Story的资料目前较少,而且 多为英文资料,所以将我自己读的这本《User Stories Applied: For Agile Software Development》翻译如下。
User Story 在敏捷开发过程中的应用
By Mike Cohn
Publisher:Addison Wesley Pub Date: March 01,2004 ISBN: 0-321-20568-5 Pages:
Translator:Yan Su,Peng Zhou
敏捷开发团队的彻底审查和努力实践证实了User Stories 应用提供了一种节省时间、减少重复工作、并且能够做出更好的软件需求过程。
构造满足客户需求的软件的最好方法就是从简短的、清晰的、扼要的并且对最终用户有价值的User Stories开始。,在这本书中,Mike Cohn提供了一种如何编写User Stories以及如何在软件开发生命周期中运用它们的详尽蓝图。
你将会学习到,怎样编写一个好的User Story ,而怎样又会导致一个坏的User Story产生呢?你还将会学习 即使在你无法和客户交谈的情况下,仍能获取到User Stories 的实用方法。如果你已经编写完User Stories 了,Cohn 将会指导你怎样去组织他们,怎样来划分优先级,以及怎样运用他们来进行计 划、管理和测试。
? 用户角色模型:理解用户 的共同和不同之处
? 获取stories:用户访谈、调查问卷、观察和讨论会(译者注:此处作
者使用了workshop,但是翻译成工作场所,此处不合适,难道他的本意是到客户工厂 去工作几天,这确实是个好方法)
? 同客户中的管理者、培训 人员、销售人员和其他代理商等一起工作 ? 编写可测试的User Stories。
? 根据User Stories 来划分优先级,制定计划,估算成本
? 章尾问题和练习
User Stories 应用对于使用任何敏捷 开发方法的软件开发人员、测试人员、分析人员和管理者都是极其有价值的。
序
90年代中期,大多数时间我 都觉得很有罪过感。我所在的公司每年都会并购一家新公司。每次并购以后,我都被指派去运作那个公司的开发团队。每一个并购的开发团队都会带来一些很壮观的、漂亮的、很长的需求文档。我不可避免的会因为我的团队没有生产出如此漂亮的需求详细说明而感到罪过。然而,我的团队的软件开发一直都比他们成功的多。
我知道我们当时做的有了成效。然后我仍然觉得头疼的是,如果我们当时做了这些很详细的需求文档,我们应该会做得更成功。毕竟,我当时读的书和文章中都是这么写的。如果一个成功的软件开发团队写了这些壮观的需求文档,似乎我们也该那么做,但是,我们从来都没有这个时间。我们的项目通常都是非常重要和非常急迫的,以至于我们不能在开始的时候有任何延迟。
因为我们没有时间去写一个漂亮、很长的需求文档,我们采用和我们的客户讨论这种工作方式,而不是把他们写下来,自前而后互相传递,然后讨论,我们只交谈。我们在纸上画一些界面,有时候我们会做些原型,还经常编写一小段代码,并把我们编写的东西展示给目标用户。我们去经常找一些有代表性的客户,并把我们真正编写的东西给他们看,通常至少每月一次。通过和我们的客户呆在一起并给他们看我们每一小块的工作进程。我们找到了一种不需要写那些漂亮的需求文档也能成功的方法。
但是,我仍然有罪恶感,我们没有按照我们应该按照的那种方式去做。 1999年,Kent Beck发表了一本具有革命意义的小书“Extreme Programming Explained: Embrace Change”,一夜之间,我所有的罪恶感消失了,书中有一种说法,说开发人员和客户交谈而不是写、讨论然后再写是可以的。Kent阐述了很多东西也给我提供了更多的工作方法。但是,最重要的是,他证实了我自己学到的一些经验是有道理的。
前期的那个大的需求收集和文档很多情况下都会扼杀一个项目,最常见的就是当我们把需求文档本身当成一个目标的时候。 其实需求文档只有在他引导软件达到最终目标的时候才应该被写下来。
第二种需求文档会扼杀一个项目的情况就是不准确的书面描述语言。我想起来很多年前听过的一个关于小孩洗澡的故事,爸 爸倒好了洗澡水,帮助他的小孩儿洗澡,这个两三岁的孩子,刚把脚趾头放到水里,就迅速的收了回来,然后跟他的爸爸说“再暖和点(make it warmer)”。爸爸把手放到水 里,惊奇的发现,水不但不冷,而且已经比她女儿洗澡用的热多了。
当他想了一会儿他儿子 的要求以后,他意识到他们缺乏交流,他们使用同一个词错误的表达了不同的意思,小孩所说的“再暖和点儿”通常被大人们理解为“提高水的温度”。但是,对小孩儿来说,“更暖和点儿”的意思是“把水温调到更接近于他所认为的暖和”(译者注:水温应该更低一点儿)。
词,尤其是书面词语,当他来表示像软件这么复杂的需求的时候是非常单薄的。为了避免对书面词语的曲解,我们需要用开发人员和客户之间频繁的交谈来替代书面词语。User Stories提供了一种方法,仅仅写下我们记得的,能指导我们进行估算和计划的就够了,同时鼓励更多的交谈。
到现在为止,你已经读完了本书的第一章节,你将开始一种转变,远离传统的记录下每一个需求细节。当你读完这本书的时 候,你会学到怎样在你的环境中运用user story驱动整个过程。本书包括四部分和两个附录。
第一部分:从这里开始—对于你开始编写story之前所要了解的所有事情做了一个描述。User Stories 的一个目的就是让人们去谈而不是写,第一部分的目的就是让你尽快去谈。第一节概述了什么是User Stories和你如何去使用User Stories,接下来的章节阐述了更多编写Stories的细节,通过用户模型来收集Stories,当你无法接触到真正用户的时候怎样编写Stories。第一部分以一些能改善你的User Stories的指导结束。
第二部分:估算和计划—当我们具备了一些Stories的时候,我们最常问的就是“我们需要多长时间来开发”?第二部 分揭示了如何通过故事点来评估Story,如何计划一个跨度3~6个月的发布计划,如何更细节的计划接下来的迭代计划,最后,如何去衡量进度 以及衡量这个项目是否按你的预期进行。
第三部分:经常讨论的主题—第三部分通过描述User Stories和一些其他的需求分析方法的区别,例如User Case、软件需求规格说明书和交互设计场景的区别开始,接下来的一节 阐述了User Stories在发现错误和适应敏捷开发方面的优势,最后一章来讨论一些小问题,例如:Stories应该写在纸上还是记录 在软件系统里,怎样处理没用的需求等等。
第四部分:举例—一个包含了前面所讲述的所有内容的例子。如果我们要求开发人员能够通过story最好的理解用户需求,那么在这本书中增加一个展示user stories所有方面的例子是很重要的。
第五部分:附录—User stories由极限编程产生。虽然阅读这本书之前,你不需要对极限编程很熟悉,但是附录A仍然为你提供了极限编程的简要描述。附录B为你提供了本书所有章节的习题答案。
1 从这里开始
第一部分我们将快速浏览什么是user stories以及如何使用,然后将阐述如何编写User Stories;如何通过系统用户模型来定义Stories;当客户自己本身无法前来的时候,如何同那些能够充当客户角色的人一起工作;如何来编写测试用例,来证明你的Stories已经被成功编写的细节,最后将阐述几条编写好的Story的指导建议。
当你学完这部分之后,你就可以定义、编写、测试你的Stories,同时你应该准备去看 如何通过User Stories去进行评估和计划,也 就是第二部分的内容。
1.1 概述
软件需求是一个沟通的问题,想得到(或者使用,或者出售)新软件的人,必须和软件的生产者进行沟通。项目的成功与否,依赖于从不同的人那里得到的信息:一方面是客户、用户、分析人员、领域专家以及其他从业务或者组织角度来看待软件的人;另一方面则是技术团队。
如果任何一方控制了沟通,那么项目注定会失败。如果业务一方控制,则会要求功能和日期,而不太担心开发人员是否能全 部完成或者开发人员是否明白他们的真正要求;如果开发人员控制了沟通,技术术语会代替业务语言,开发人员也失去了通过倾听来了解客户真正需求的机会。
我们需要一种方法让大家一起合作,以至于沟通不会被单方控制,并且资源分配中的感情因素和原则问题就变成了双方共同的问题。.当资源分配完全倾向一方 的时候,项目就会失败。如果开发人员全权负责(无论怎样都必须在7月份之前全部做完), 他们可能会因为一些附加的功能而牺牲质量,或者只实现部分功能,或者独自制定本该客户或用户参与制定的大量的决定。当客户和用户方全权负责,项目前期就会 出现一个漫长的讨论过程,在这个过程中越来越多的功能被从项目中删除,当软件被交付的时候,甚至实现的功能比删掉的功能少。
我们已经知道了我们不能够完美的预言一个软件开发项目。当用户看到软件的初版时,他们会产生一些新的想法,改变一些 他们原有的想法,由于软件的不可把握性,开发人员进行时间估算变得非常困难。由于种种原因,我们无法罗列一个完整的PERT图表来显示我们在项目里所必须完成的全部工作。
那么,怎么办?
我们经常通过手头已经掌握的资料来做决定,会好过在项目初期就做出所有的决定。我们把做决定分散到整个项目过程中。 为了做到这一点,我们要确认已经有一个尽早尽多获得相关的资料的程序。User Stories 由此而生。
1.1.1 User Story 是什么?
User story是对软件的用户或买主有价值的功能点的描述。User stories 由以下三点组成:
? 用来制定计划和作为提醒的一段书面描述 ? 用来充实story的细节的谈话
? 测试用例,用来表达和记录细节并且能够在story实现的时候对其进行
验证
因为User Story的描述是通过传统的手写记录在卡片上,所以Ron Jeffies给这三个方面起了很好 的名字,Card(卡片),Conversation(会话),和Confirmation(确认)。卡片是story最可见的表现形式,但是他不是最重要的。Rachel Davies 已经说过,卡片“重现客户需求场景好于记录它们”。思考User Stories的完美方法是:card 包含story的正文,通过会话得出细节,并记录在测试用例中。
User story 的例子,请参见Story Card 1.1
Story Card 1.1 是一个写在卡片上的初期的User Story
(用户可以在网站上发布简历)
为了保持一致,贯穿剩下的这本书的例子大多都是为BigMoneyJobs 网站而设计的。其他的例子故事可能包括:
? A user can search for jobs(用 户可以查找职位)
? A company can post new job openings(公司可以发布新的职位) ? A user can limit who can see her resume(用户可以限制那些人可以
查看他的简历)
因为user stories 描述了对客户来说有价值的功能点,所以对这个系统来说下边的例子就不是好的user stories。
? The software will be written in C++.(软件应该用
C++来编写)
? The program will connect to the database through a connection pool
(软件应该通过连接池来连接到数据库).
第一个例子对BigMoneyJobs来说不是个好的user story是因为用户根本就不关心使用哪种编程语言。但是,如果这是一个应用程序接口,用户(他本身就是个程序员)写下“The software will be written in C++(软件应该用C++来编写)”就会很好。
第二个story在这种情况下也不是个 好的user story ,因为系统的使用者并不关心应用程序如何连接到数据库的技术 细节。
也许,你已经读了这些stories 并且很惊讶地说,“等 等,使用一个连接池是我这个系统的一个需求” 如果这样的话,请一定要清楚,编写stories的关键点在于让客户认可他们的价值, 我们将在第二部分“编写story”里看到一些关于编写Story方面的例子。
1.1.2 细节在哪呢?
说 “A user can search for jobs(用户可以查找职 位)”是一件事情,而能否只靠这个作为指导就开始编码和测试却是另外一件事情。因为,细节在哪里呢?类似于下边的这些问题怎么办呢?
? What values can users search on? State? City? Job title? Keywords?(用户查
询的条件是什么?州?城市?职位?关键字?)
? Does the user have to be a member of the site?(用户必须是网站的注册用
户吗?)
? Can search parameters be saved?(可以保存查询条件么?)
? What information is displayed for matching jobs?(查询页面上应该显示
哪些信息呢?)
许多类似的细节可以当作另外的stories来描述。实际上,多做 几个stories 比做一个很大的stories要好。例如整个的BigMoneyJobs 网站可以用这两个stories来描述:
? A user can search for a job(用户可以找工作)
? A company can post job openings(公司可以发布职位空缺 (好机会)) 很明显,这两个stories太大了,大到没有太大用处.,在第二章“编写故事”中,完整的阐述了故事大小的问题。从一、两个开发人员花费半天或者两个星期来编写和测试一个story开始,是一个不错的起 点。 公平一些来讲(Liberally interpreted),上边的两个stories简单的概括了BigMoneyJobs网站的大部分功能,,每一个大概要花费程序员多于一周的时 间。
当一个故事太大的时候,他通常会被作为一个Epic(译者注:此词本意为史诗级的,我没有找到合适的汉语词汇表达,就是大的故事集的意思)提出.Epics可以被分割成两个或更多个小故事。例如,这个Epic“A user can search for a job(用户可以找工作)”就可以被分割成这些Stories。
? A user can search for jobs by attributes like location, salary range, job title,
company name, and the date the job was posted.(用户可以通过地区, 薪水, 职位, 单位名称, 和职位发布日期 来搜索)
? A user can view information about each job that is matched by a search.(用
户可以查看搜索出来的每个职位的详细信息)
? A user can view detailed information about a company that has posted a job.
(用户可以查看发布职位空缺信息公司的详细信息)
但是,当我们的story能够涵盖所有的细节 时,我们就不再去分割story了。例如,故事“A user can view information about each job that is matched by a search”是非常适度和实用 的。我们不需要再去把它进一步的像这样去拆分:
? A user can view a job descrīption.(用户可以查看职位描 述) ? A user can view a job's salary range.(用户可以查看职位薪 水) ? A user can view the location of a job.(用户可以查看工作地 点) 总的来说,user story 不需要用专业的需求文档格式夸张的描述成下面这个样子。
4.6) A user can view information about each job that is matched by a
search.
4.6.1) 4.6.2) 4.6.3)
A user can view the job descrīption. A user can view a job's salary range. A user can view the location of a job.
比坐在这里把这些细节写成stories更好的方法就是开发团队和客户来一起讨论这些细节。就是说,当这些细节比较重要的时候,就把他拿出来讨论。讨论后,在卡片上添加一些注释是没有错的,就像Story Card 1.2.一样。可是,重点是会话,而不是story card上的笔迹。不管是开发人员还是客户都能够在3个月后还指着卡片说 “看,我那时候是这么说的”。Stories并不承担法律责任。我们将看到,协议通过可以证明某个story被正确实现的测试用例来 记录。 Story Card 1.2. A story card with a note.
1.1.3 故事应该有多长呢?
当我上中学文化课时候,每当我们被指定去写一篇论文,我总是问 “论文必须写多长呢?”老师是不喜欢这个问题的,但是我仍然认为这个问题是必要的,因为它告诉我老师期望的是什么。这个问题同样也是了解项目用户需求很重要的一点。这些要求最好以可测试的形式被捕获。
如果你使用的是纸质的笔记卡片,你可以把卡片翻过来,把需求写到背面。这些记录下来的要求提醒怎样测试这个story,就像Story Card 1.3所显示的那样。如果你使用的是电子系统,它应该有一个地方可以让你加进一些可测试性的提醒。
Story Card 1.3. The back of a story card holds reminders about how to test the story.
测试描述是简短和不完备的,测试用例可以随时添加或者删除。目的是涵盖Story的附加信息,以便开发人员知道Story什么时候就算完成了。就像老师的要求对我来说很有用,我可以知道什么时候我 写的关于Moby Dick的东西算完成了。它对于开发人员来了解什么时候完成了客户需求一样有用。
1.1.4 客户团队
对于一个理想的项目来说,我们会有一个专门的系统最终用户,他为开发人员区分工作的优先级,并回答他们的问题,编写 所有的Stories。这个是太理想的情况,所以,我们创建一个客户团队,这个团队 里包括那些可以保证软件达到最终用户需求的那些人。这就意味着这个客户团队包括测试人员、管理人员、用户和交互设计人员。
1.1.5过程是怎样的?
使用Stories的项目会和你原来习惯的那种项目有不一样的感受和节奏。传统的瀑布模型会导致一个需求、需求分析、设计、编码以及最后的测试这样的循环。在瀑布流过程中,
客户和用户只跟最开始的需求编写及最后的软件验收有关,但是在需求和测试中间,客户和用户几乎完全消失。但是现在,我们已经知道这样不行。
对于 一个story驱动的项目来说,我们首先应该注意到的,就是客户和用户应该参与到整个项目过程。我们绝对不希望或者不允许客户在项目中途消失,这一点是肯定的,不论你是使用极限编程、敏捷的统一过程、像Scrum一样的敏捷过程还是自己的Story驱动的敏捷过程。
客户和软件的最终用户应该在编写story 的过程中扮演一个很积极的角色,尤其是应用极限编程的时 候。最好从考虑系统的用户类型入手来开始story 编写。例如你要构造一个旅游预订网站,你应该有这些类型的用户,例如飞行常客、度假计划者等等。客户团队应该包括尽可能多的每一种客户的代表。如果没办法这样的话,用户角色模型会很有帮助(关于这一点,第三章“User Role Modeling”提 供了更多的信息)。 为 什么客户要写story呢? 为什么客户团队比开发人员更适合来写user story呢?主要有两个原 因。第一,story必须拿业务语言来写,而不是技术术语,以便客户团队可以划分将要包含到迭代和发布中story的优先级。第二、作为项目最主要的预见家,客户团队处在描述产品行为的最好位置 一个 项目最初的story通常是在专门的story编写讨论会上编写,但是story可以在项目过程中的任何时间来编写。在story编写讨论会上,每个人都会绞尽脑汁尽量的多写story。有了一系列的story作为开头,开发人员可以对每一个story的大小进行估算。
客户 团队和开发人员以协作的方式选择一个迭代长度,可能是一周、二周、三周或者四周。整个项目过程中会使用相同的迭代长度。在每一个迭代结束的时候,开发人员有责任提供一段完整可用的代码,这段代码实现应用的某个模块。客户团队要高度参与迭代的整个过程,和开发人员讨论迭代过程中正在开发的story。在迭代过程中,客户团队应该定义测试用例,并且和开发人员 一起执行,包括自动执行或手工执行。另外,客户团队要保证工程一直朝着为客户提交满意的产品的方向努力。
迭代的长度一旦确定,那么开发人员就会估算他在每一个迭代中能做多少工作,我们称之为速率。团队的第一个估算的速率通常是错误的,因为没有办法预先知道速率。 但是,我们可以使用初始的估算作为一个草图,或者一个发布计划,来规划每一个迭代过程中包含哪些工作,一共需要多少个迭代过程。
为了计划发布,我们来把story分成很多堆,每堆表示一个迭代。每一堆里面包括一定数量的story。在不超过估算速率的情况下,估算哪些可以添加进来。最高级别的story放到第一堆,第一堆塞满以后,将次要的story塞到第二堆。直到堆太多以至于超过了工程时间,或者你当前的堆足以发布一个令人满意的新系统(关于这部分更多信息请参见第九章,“计划一个发布”和第十章“计划一个迭代”)。
在开始每一个迭代之前,客户团队可以对计划进行小的校正。当迭代完成的时候,我们可以掌握开发团队实际的速率,然后就可以用它来替换估算的速率。这也就意味着每一堆story都需要通过添加或删除story来调整。同时,会有一些story被证明比预期的简单,这就意味着可以在迭代中增加一些story。但是有些story又会比预期的难,这就意味着有些工作必须转移到后面的迭代 中,或者完全从整个发布中删除。
1.1.6 计划发布和迭代
一次(版本)发布由一个或多个迭代组成。发布计划取决于项目时间和希望完成的功能点之间的平衡。迭代计划取决于为这次迭代选择的story。客户团队和开发人员都要参与发布和迭代计 划的制定。
客户团队的工作从划分story的优先级开始,计划一次(版本)发布,划分优先级的时候,
他们希望考虑:
1、用户和客户中大多数人的业务需求 2、用户和客户中少数重要角色的业务需求
3、story之间的耦合性。例如,一个“放大”的story本身也许不是高级别的,但是它会
被像对待高级别的story一样来对待,因为,他是高级别story“缩小”的补充。
开发人员对很多优先级的划分和客户不同。他们也许会基于story的技术风险或者因为它对其
他story的补充来进行story优先级的设置。客户团队听取他们的意见,然后按能够交付给组织最大价值的方式来划分story的优先级。
Story划分的时候不可能不考虑它的成本。就像在我考虑夏天去塔希提岛度假的花费之前,我一直把他当作假期旅游的优先选择。直到我考虑了花费,其他地点的优先级才变高了。story的成本是划分优先级的一个因素。通常这个成本是由程序员估算的。Story通过故事点来确定估算,故事点指明story的大小和与其它story交互的复杂程度。所以,一个包含4个故 事点的story的成本是一个包含2个故事 点的story的2倍
根据分配到发布过程中的迭代中的story来建立发布计划。开发人员说明他们 所预期的速率,也就是他们认为在每个迭代内所能完成的故事点。然后客户把story分配到迭代中,保证分配到每一个迭代中的故事点不会超出预期的速率。
Table1.1列出了示例工程中所有的故事,并且把他们按优先级降序排列。团队估算了一下速率是每个迭代完成13个故事点,这些故事将按照Table1.2被分配到迭代中。
Table 1.1. 简单的story和他们的成本
Story Story A Story B Story C Story D Story E Story F Story G Story H Story I Story J Story Points 3 5 5 3 1 8 5 5 5 2 因为团队表明,“13个故事点/每个迭代”这样的一个速率,没有哪个迭代可以多计划几个故事点。这也就意味着第二和第三个迭代只能包含12个故事点。不要担心——对于这些不同的问题,很少能估算的足够精确,并且如果开发人员开发的比计划快 的话,他们会再做一、两个小一点的story。注意第三个迭代选择了故事J而没有选择比他优先级高的I,这是因为storyI有5个故事点,这个太大了以至于不能包括进迭代3。
Table 1.2. 为Table 1.1中的story制定的发布计划 Iteration Iteration 1 Iteration 2 Iteration 3 Iteration 4 Stories A, B, C D, E, F G, H, J I Story Points 13 12 12 5 另一个可供选择的,跳过一个大的story而把一个较小的story放到迭代中的方法是把大的story分割成两个story。假如我把包含5个 故事点的storyI分割成storyY(3个 故事点)和StoryZ
(2个故事点)。StoryY包含了原story中大部分重要的 功能点,可以将它填进第三个迭代,像Table1.3所展示的 那样。
什么时候分割以及如何分割story的建议请参见第二章“Writing Stories(编写story)”和第七章“Guidelines for Good Stories”(编写好的story的指导)。
Table 1.3. 分解story,创建更好的发布计划 Iteration Iteration 1 Iteration 2 Iteration 3 Iteration 4 Stories A, B, C D, E, F G, H, Y J, Z Story Points 13 12 13 4
1.1.8 为什么改变?
到这里,你可能正在问,为什么要改变?为什么要编写story 卡片并记录所有的沟通交流?为什么不直接写需求文档或者用例?User story 相对于其他方法而言,有更多好处.下面列出了一些原因,第13章“为什么用user stories”阐述了更多 细节:
? User story更强调口头的沟通
? User story对于你和开发人员来说都是可理解的 ? User story拿来制定计划,大小合适 ? User story为迭代开发工作
? User story 鼓励推迟细节,直到你已经清楚地理解你真正需要什么
因为user story把重点从书写转移到了对话,重要的决定不再在不易阅读的文档里捕获。相反, story的重要方面在自动运行的验收测试用例中捕获。另外,我们避免愚钝的用下面陈述的方法编写文档:
系统必须存储一个地址和工作电话或者移动电话。 意味着什么?它可能意味着系统必须存储其中之一: (地址和工作电话)或者移动电话 地址和(工作电话或者移动电话)
因为user story是不考虑技术的(记住,是客户团队编写的他们), 所以他们对开发人员和客户团队来说都是可理解的。
每一个user story 都展示了一个离散的功能碎片;那就是,用户可以按照一个单一的设置来做。这使user story 适合作为一个计划工具。你去评估在发布之间转移story的价值要比评估漏掉需求描述中一个或多个“The system shall?”所带来的影响要好的多。
迭代是一个通过重复的提炼,慢慢取得进步的过程,开发团队在第一次对系统进行切割的时候,他知道他在某些区域(也许很多区域)是不完善的或者脆弱的。然后他们不断的精炼这些区域,直到产品令人满意。每一次迭代,软件都会通过大量细节的增加而被改进。Story对迭代开发来说是很好用的,在story上进行迭代是有可能的。对于一个你最终想要,但是目前又不是很重要的功能,你可以首先写一个大story(an epic)。当你准备要把这个story添加到系统中的时候,你可以通过拆分epic来精炼他,用更小的story来 代替,这样工作会变得容易很多。
以story为基础进行迭代的另一个好处是,story鼓励延缓细节。因为我们今天可以只写一个占位用的epic, 当系统的某部分快要被开发的时候才去写这部分的story。延缓细节是很重要的,因为我们不需要花 费太多的时间在一个新的功能点上,直到我们确定它是必要的。Story不鼓励我们去假设自己可以知道和编写将来的任何事情,相反的,它鼓励软件在客户团队和开发人员讨论的基础上进行迭代提炼的过程。 1.1.9 摘要
? 每个故事卡片是对用户或者客户有价值的某个功能点的简短描述。
? 故事卡片只是这个故事的可见部分,重要的是客户和开发人员关于这
个story的谈话、讨论。
? 一个客户团队包括那些可以保证软件能够达到目的用户需求的人,可
能包括测试人员、产品经理、真实用户和 交互设计人员。
? Story由客户团队来写,因为他们能够最好的表达客户所希望实现的
功 能,而且他们稍后必须能够和开发人员一起制定story细节和划定story的优先级。
? Story的优先级划分取决于他们对组织来说的价值大小。 ? 通过在迭代过程中放置story到来制定发布和 迭代计划 ? 速率是开发人员能够在一个迭代过程中完成的工作数量
? 每一个迭代过程中估算的story总数不能超过 预计的开发人员开发
那个迭代的速率
? 如果一个story放在某个迭代中不合适,你可 以把这个story分解成
两个或更多的更小的story
? 验收测试用来验证一个已经开发完成story是否已经达到了客户团队
在编写这个story时脑中希望它完成的功能。
? User story是很有用的,因为他强调平等的口头交谈,这个交谈可以
同时被你和开发人员理解,他还可以用来计划迭代,很好的配合迭代过程的工作,而且他鼓励延缓细节。
1.1.10 练习
1、 user story 包括哪三部分? 2、 客户团队包括哪些人?
3、 以下哪个不是好的user story ,为什么?
1) 客户可以在windows和linux上运行系统. 2) 所有图表运用第三方的库来做.
3) 客户可以进行15次命令以上的撤销。 4) 软件将在6月30号发布。 5) 软件将用java语言编写.
6) 用户可以从下拉列表中选择她的国家
7) 系统将使用Log4J把所有的错误信息记录到一个文件里 8) 如果客户15分钟没有保存他的工作,则系统提示用户进行保存。 9) 用户可以选择“XML输出”这一功能 10) 用户可以将数据导出成XML. 4、 需求讨论比起需求文档,有哪些优势? 5、 为什么你要在卡片背后 写上简单的测试用例呢?
1.2编写Story
本章我们重点 关注story的编写,一个好的story需 要具备以下六点:
? 独立性(Independent) ? 可协商性(Negotiable)
? 对客户或用户有价值(Valuable to Purchasers or Users) ? 可估算(Estimatable) ? 短小(Small)
? 可测试的(Testable)
Extreme Programming Explored and Refactoring Workbook的作者Bill Wake将这六点总结为INVEST。
1.2.1 独立性
应该尽可能的注意避免引入story之间的依赖性。User story之间的依赖会导致优先级及计划问题。例如,假使客户把某个story作为高优先级,而这个story恰恰依赖于一个低优先级
的story, 那会怎样?而且Story间的依赖关系会使估算变得比他原本所需要的更复杂。例如,假设我们在BigMoneyJobs网站工作,需要为“公司如何为他们在网站公开发布职位付款”编写story,我们可以这样写:
1、公司可以通过visa卡为发布职位付款。
2、公司可以通过MasterCard(万事达卡)为发布职位付款。
3、公司可以通过American Express card(美国运通公司的信用卡)为发布职位付款. 假设开发人员估算完成对第一种卡的支持需要3天时间(不管是三种卡中的哪一种),然后剩下的两种各需要1天的时间。像这种依赖程度很高的story,你就没 办法估算每一个story花费的时间,请问你应该为哪一个story分 配3天呢?
当遇到这种依赖,有两种处理方式:
? 将这些相互依赖的story合并成一个大的且没有依赖性的story。 ? 寻找另外的story划分方式
把关于不同信用卡的story合并为一个单独的story(“公 司可以通过信用卡为发布职位付款”)。工作就很好做了,因为这个被合并的单独的story只需要5天时间。如果合并后的story太长,可以选择另外 一种比较好的方法处理,就是通过其他的维度来划分story。如果估计这些story太长了,可以选择下面这种分解方式来代替:
1、客户可以通过一种信用卡支付 2、客户可以通过两种其他的信用卡支付
如果你不想合并story而且也找不到好的分解方式,你也可以选择一个简单方法,就是在一个卡片上放两个估算结果:一个是如果这个story在其他story之 前做,那么估算值是多少,在下面写上如果它在其他story之后做,估算值又是多少。
1.2.2 可协商的
Story是可协商的。它不是软件必须要如何实现的书面合同或者需求。Story卡片是功能点的简要描述,而客户和开发团队在谈话中对细节进行讨论。因为story的作用是提醒有这样一次讨论而不是详细完整的记录需求细节本身,他不需要包括所有有关的细节。但是,如果在编写story的时候,你知道一些重要细节的话,应该把他们作为一个注释包括在story中,例如story card2.1所展示的 那样。学习包含足够的细节是一个挑战。
Story Card 2.1是很好用的,因为他为将讨论这个story的开发人员和客户提供了正确的信息量。当开发人员开始编码的时候,卡片会提醒他大家已经确定可以接受三种主要信用卡,并且他可以问用户是否可以接受Discover card(发现卡)。卡片上的记录帮助开发人员和客户继续先前已经停止的某次讨论。最理想的是,无论这次讨论的开发人员和客户是否和上次是相同的
人,在story卡片的提醒下,都能很容易的继续上次的讨论.把这个作为给story添加细节的指导。
Story Card 2.1. 一个提供了一些附加细节的故事卡片.
反过来,来考虑一个story像Story Card2.2一样在一个story上做太多记录。这个story记录了太多细节(收集了Card的有效期限),并且收集了一些应该放到另外一个story中的信息(“系统能够为特征用户存储一个卡号”) Story Card 2.2. 一个包含了太多细节的故事卡片.
使用像Story Card2.2这样的Story来工作是 很困难的。大多阅读这个story的读者都会误认为更多的细节代表着更精确。但是,很多情况下,太早的定义这些细节只会带来更多的工作。例如,当两个程序员讨论“a company can pay for a job posting with a credit card(公司可以通过信用卡为发布职位付款)”这个故事卡片的时候,他们不会忘了,他们讨论的只是一些摘要。这个Story不具备太多的细节,因此他们不会认为自己的讨论是最终的或者估算是很准确的。但是,当像Story Card2.2那样添加太多细节的时候,会导致讨论人错误的认为story更像是具体的和真实的。这样会导致讨论者错误的认为story 卡片已经反映出了所有的细节,所以不需要再就这个story和客户进行讨论了。
如果你把story卡片作为开发人员和客户某次对话的提醒来考虑,那么考虑在story卡片上包含以下两点是非常有用的:
? 一两个作为提醒的短语,以便维持谈话 ? 记录谈话过程中解决的问题
通过谈话确定 的细节将会变成测试用例。测试用例可以记录到story卡片的背面,无论你使用记录卡片还是任何电子系统。Story Card2.3和Story Card2.4展示了Story Card2.2中一些儿多余的细节怎样被转变成测 试用例,卡片的正面只剩下关于讨论的记录。这样的话,卡片的正面包括story和讨论的问题,背面 以测试用例的形式记录细节,这些测试用例可以用来验证story是否按预期的希望被实现。
Story Card 2.3. 修改后的story,只包括story和被讨论的问题
1.2.3 对买主或者用户有价值
“每一个story都应该是对用户有用的”,类似这种方式的表达是诱人的,但是是不正确的。很多项目包含着那些对用户没有价值的story。记住用户(谁使用这个软件)和买主(谁购买这个软件)的不同。例如:一个开 发团队正在构建一个要在大用户群中发布的软件,也许是一个公司的5000台pc。产品的买主会很关心这5000台pc是否使用相同的软件配置的问题。这个也许会产生一个“所有的配置信息从一个中心位置读取”的story。用户们不会关心配置信息在哪里存储,但是买主会关心。
Story Card 2.4. 包含测试用例的细节从story本身中被分离出来. 然后 记录在卡片背面.
类似下面这些story对购买产品的买主就可能是有价值的,但是对实际用户来说并没有价值。
? 开发过程 中,开发团队应该编写符合ISO9001认证的文档。 ? 开发团队要按照CMM3级标准开发
你应该避免只对开发人员有价值的Story,例如: ? 所有与数据库的连接都通过数据链接池 ? 所有的错误处理和记录都通过一个公共类来设置
像他们本身所写的那样,这些story关注的是技术和编程的优势。有可能这些story背后有一些想法,且这些想法应该被写出来以替代上面这两个story,这些新想法应对客户或者用户的价值更加明显。这个允许客户优先把这些story考虑进开发日程中。把这些story做下面这些转变,会更好:
? 用户许可证的数据库应用应该能够被大于50的用户使用 ? 为客户显示所有的错误信息,并使用统一的方式记录
不要把一些关于客户接口的设想带到story中来,同样也不要把技术设想带到story中。例如,上面修改过的story已经把“统一使用一个链接池”和“一个错误处理类”从story中移除了。
保证每个story都对客户或用户有价值的最好的方法就是客户编写story。 通常在开始的时候客户是感觉不舒服的,可能是因为开发人员培养他们去考虑他们要写的所有东西,而且这些东西以后可以被拿来反对他们(你看,需求文档上并没有说? ?)。story card是用来 提醒稍后要进行的讨论,而不是记录明确的需求,这种概念一旦被客户意识到,并且让他们感到比较舒服的时候,他们就开始自己写story了。
1.2.4 可估算的
对开发人员来 说,能够估算一个story的大小和开发这个story的 时间是非常重要的。通常有三种原因会导致story不可估算:
? 开发人员缺少域知识 ? 开发人员缺少技术知识 ? Story太大
首先,开发人 员缺少领域知识。如果开发人员不明白story描述的内容,他们应该跟写这个story的客户进行讨论。再者,开发人员也没必要了解关于story的所有细节,但是开发人员需要对story有个大概的基本的理解。
第二,开发人员不了解所用的技术也会导致story是不可估算的。例如,在一个java项目中,我们需要在系统中提供一个CORBA接 口。团队成员没有人做过这个,所以没有办法对工作进行估算。解决这种问题的办法是向一个或多个开发人员传递什么是极限编程,这个过程被称之为技术穿刺,也就是一个了解应用领域的简短实验。在穿刺过程中,开发人员只需要学到他们能够进行工作估算的程度就够了。给技术穿刺本身定义一个最长的时间,也叫timebox,以便我们用来估算技术穿刺。这样那个不可估算的story就 被转变成了两个story:一个快速的收集信息的技术穿刺,和一个真正去实现功能的工作.
最后,如果story太大开发人员可能也无法估算它。例如,为BigMoneyJobs网 站所写的story“A Job Seeker can find a job(搜索工作的人可以找到工作)”就太大了。为了估算他,开发人员必须要把它分解成更小的story。
领域知识缺乏 来看一个需要更多领域知识 的例子,我们正在为慢性病的长期医疗护理构建一个网站。客户(一个资深护士)写了一个story“New users are given a diabetic screening(新护士要进行糖尿病测验)”,开发人员不确定他的意思是什么,他可以是在网上发布一个调查问卷,或者像生产支气管病人所用产品的公司那样,给新护士送些东西做一个家庭体质测验。开发人员和客户在一起讨论后发现,他想要一个简单的包含少量问题的网页形式。 即使story太大了以至于确实无法估算,但是写类似“A Job Seeker can find a job”一样的epics也是很有用的,因为他们对系统一些大的需要讨论的模块起到占位符和提醒者的作用。如果你正在做一个为系统的一个大模块做临时的注释的决定,那么考虑写一个或者两个epic来概括这部分。可以给这些epic做一个大的,当然也是非常之困难的估算.
1.2.5 短小
就像Goldilocks(戈笛洛克斯,一个童话故事中的金发小姑娘)寻找舒适的床一样,有些story太大了,有些太小了,有一些大小正合适。Story的 大小是有关系的,因为太大或太小的story都没办法被用来做计划。Epics很难直接被拿来用,因为他们经常会包括许多个story。 例如,在一个旅游预订网站中,“A user can plan a vacation(用户可以计划一次假期)”是一个epic,计划一个假期对旅游预订网站来说是很重要的,但是它包含了太多的 工作。这个epic应该被分解成更小的story。 最终决定story的大小是否合适取决于团队的能力和所使用的技术。
? 分割story
Epics属于以下两类代表性中的一种: ? 复合story ? 复杂story
复合story就是一个epic中包含许多更小的story。例如,BigMoneyJobs系统包含 “A user can post her resume(用户可以发布简历)”的epic。在初期的系统计划中,这个story是合适的。但是当开发人员和客户讨论的时候,他们会发现“post her resume(发布简历)” 实际上表示:
? 简历可以包括教育,工作经验,薪酬历史,出版物,报告,社区服务和目标 ? 用户可以静态制作简历 ? 用户可以拥有多个简历 ? 用户可以编辑简历 ? 用户可以删除简历
依赖于这些story将花费多少的开发时间,每一个都可以变成他自己单独的一个story。 但是,这会是epic在相反的方向上走得太远,也就是把它分解成一系列的太小的story。例如,依靠使用的技术,大小和团队的技巧,下面的这些story通常就太小了:
? A Job Seeker can enter a date for each community service entry on a resume(工
作查询者可以在简历中的每个社区服务输入时间).
? A Job Seeker can edit the date for each community service entry on a resume
(工作查询者可以修改简历中的社区服务的时间).
? A Job Seeker can enter a date range for each prior job on a resume(工作查询
者可以给简历中的每个工作经验录入一个时间段).
? A Job Seeker can edit the date range for each prior job on a resume(工作查
询者可以修改简历中的工作经验时间段).
通常,下面这样可以更好的解决把更小的story化零为整的问题:
? A user can create resumes, which include education, prior jobs, salary history,
publications, presentations, community service, and an objective.(用户可以制作简历,简历包括教育,工作经验,薪酬历史,出版物,报 告,社区服务和目标) ? A user can edit a resume(用户可以编辑简历). ? A user can delete a resume(用户可以删除简历).
? A user can have multiple resumes(用户可以 拥有多个简历).
? A user can activate and inactivate resumes(用户可以拥有静态和动态的简历).
有一些常用的分解一个复合story的方法。前面是按创建、编辑和删除这条常用的线路来分解。在一个创建story小到可以被作为一个story的情况下,这 种方法是很有效果的。另一个分解方法是按数据边界。这种方法需要考虑简历的组成部分,对每一部分单独添加和编辑,同样也会导致完全不同的分解结果:
? A user can add and edit education information(用户可以添加和编辑教育信息)。 ? A user can add and edit job history information(用户可以添加和编辑工作经验). ? A user can add and edit salary history information(用户可以添加和编辑薪酬历
史).
? A user can add and edit publications(用 户可以添加和编辑出版物). ? A user can add and edit presentations(用 户可以添加和编辑报告). ? A user can add and edit community service(用户可以添加和编辑,社区服务). ? A user can add and edit an objective(用 户可以添加和编辑目标). 等等.
和复合story不同,复杂story本身是非常大而且不容易被分解的。如果一个story是因为对它的不确定而变得复杂,你可能要把它拆成两个story:一个是研究的一个是开发新功能的。例如:假设给了开发人员一个“A company can pay for a job posting with a credit card(公 司可以通过信用卡为发布职位付款)”,但是以前没有人做过信用卡付费流程。他们可能会选择把story分 解成下面这样:
? 在网上研究信用卡付费流程 ? 用户可以通过信用卡付费
分割的第一个story是让一个或多个开发人员迅速补充技术方面的技能。当复杂的story按这种方式分割的话,总是定义围绕着研究或者急训的story来定义一个timebox。即使story无法用任何准确的精度来 估算,也可以定义花费在学习上的最大时间。
在开发新的或 延伸的知识算法时,经常会出现复杂的故事。某个生物工艺公司的团队有一个这样的story:在“期望最大化”这个标准统计近似值中添加异常统计。这个复杂story被重新写成两个story:第一个研究定义扩展“期望最大化”的可能性;第二个在产品中添加功能。这种情况下,我们很难对研究 定义这个story花费多长时间做出定义。
考虑把技术穿刺放到其他的迭代中去 如果可能的 话,把研究类的story放到一次迭代中,其他的story 到其他某个或多个后续的迭代中是比较好的。通常,只有研究类的story可以被估算。把无法估
算的story和能确定的story放到一个迭代中,意味着这个迭代的完成时间的不确定性变得高于一般程度。 拆解无法估算的story关键一个好处是可以让客户把研究和新功能拆分开来划分优先级。如果客户只拿一个复杂story进行优先级划分(“Add novel extensions to standard expectation maximization”)和story估算,她也许会在错误的前提-新的功能被提前交付的条件下进行估算。相反,客户有一个技术穿刺story和一个功能story,她必须选择是在一个迭代中添加技术穿刺story而不添加任何新的功能story还是添加其他的一些story。
? 组合Story
有时候story太小了。小到开发人员不想去记录或者估算它,因为做这些事情比做修改花费的时间还多。但是报告者和用户接口修改通常都很小。极限编程团队处理这些小的story的好办法就是把他们组合成需要花费半天到几天时间实现的一个大story。然后给这个组合起来的story起 一个名字,并且跟其他story一样处理。
例如,假设一个项目有5个bug和一个修改一些查询界面 颜色的要求。开发人员把所有的工作当作一个story来估算。如果你选择使用纸片,你可以通过把它 们拿一张大纸作为封皮订到一起来实现story组合。
1.2.6 可测试性
Story必须被编写出来,以保证它的可测试性。成功通过测试证明story被成功开发。如果story不能被测试,那开发人员怎么能知道他们什么时候完成了编码呢?
不可测试的story通常表示非功能性的需求,是软件需求但不直接是它的功能点。例如,考虑下面两个非功能性的story
? A user must find the software easy to use(客户必须觉得软件非常好用). ? A user must never have to wait long for any screen to appear(客户不需要对
页面显示进行任何等待).
这些story是无法测试的。尽可能保证测试自动执行. 这 意味着自动测试要争取做到99%,而不是10%.你总是可以比你认为的你可能做到的更多做一些。当产品被逐渐开发的时候,事情改变非常快,昨天开发的东西今天就有可能停止开发。你需要能很快发现这些问题的自动测试。
有一个非常小的测试用例的子集是无法实际的被自动测试的。例如:“A novice user is able to complete common workflows without training(新的系统使用者在不需要训练的情况下就能完成普通的流程操作)”这个story可以被测试但是不能自动操作。测试这个story可能包括一个人性因素的专家设计一个测试用例,对随即抽取的新手进行观察。这种测试是耗时和昂贵的,但是story是可测试的并且对某些产品来说是合适的。
“a user never has to wait long for any screen to appear” 是不可测试的,因为他说了“never”而且没有定义“wait long”的意思。论证某事永远不会发生是不可能的。一个简
单些的、合理的目标是论证某事极少发生。这个story可以被重新写成“95%的新页面都可以在2秒内显示”。更好的是,可以写一个自动的测试用例来验证这个。
1.2.7 摘要
? 理想的情况 是,Story之间是相互独立的. 虽然不 是绝对的,但是Story在大多情况下应该
是可以按任何顺序开发的.
? Story的细节是可以被用户和开发人员讨论的
? Story对客户和用户的价值应该是清楚的。达到这一目的的最好方法就是客户写story。 ? Story应该有细节的注释,但是太多的细节会模糊story的意思,并给人造成客户和开发人员
之间的讨论是不必要的印象。
? 为story添加注释的最好办法就是给story写测试用例 ? 可以把太大的复合story和复杂story分割成更小的story ? 如果story太小,可以把多个小的story合并成一个 大story。 ? Story需要是可测试的。
1.2.8 开发人员责任
? 你有责任帮助客户编写概述对客户有价值、独立、可测试并且大小合适的story,而非细节描
述。
? 如果试图去问一个关于技术或者构造的story,你有责任把它转换为对客户和用户有价值的表
述方式。
1.2.9 客户责任
? 你有责任编写概述对客户有价值、独立、可测试并且大小合适的story,但不是非细节描述。
1.2.10 问题
1、指出下面的story是否是好的story,为什么?
1) 用户能够快速掌握 系统使用. 2) 用户可以编辑简历中的地址. 3) 用户可以添加、编辑和删除多个简历.
4) The system can calculate saddlepoint approximations for distributions
of quadratic forms in normal variables. 5) 采用统一的方式记 录系统运行错误。
2、 请把这个epic拆 解成大小合适的story,“A user can make and change automated job
search agents(用户可以设置和更改自动的职位查询代理)”。
1.3.3另外两个技术
如果我们想停止的话,到这就可以了。到现在为止,一个团队可能已经花费了一个小时,当然大部分也不会再多了,他们可能会比99%的团队更多的考虑他们软件的用户。实际上,大部分的团队到这里就可以了。但是,还有两个附加的技术是值得 提出的,因为对某些项目来说,这是有帮助的。当你希望对项目产生一个直接的、很实际的好处时,来使用这两个技术。
1.3.3.1人物
定义用户角色已经是向前跨越一大步了,但是对一些很重要的用户角色,是值得更进一步为角色创建一个人物的。人物是用户角色一种虚构的表现。在本章前面,我 们遇到了Mario,他负责为公司发布新的工作空缺。创建一个人物比只给用户角色添加一个名字要求 的更多。当团队的每个人都觉得他们认识这个人的时候,人物的描述就算成功了。例如,可以采用如下的方式描述Mario:
Mario是SpeedyNetworks(网络构件制造厂商)公司人力部的一名招聘人员。他已经在这个公司工作了六年。Mario有一个弹性的时间安排,每周五从家中去上班。Mario对 电脑很精通,他认为他自己有能力使用所有他所使用的产品。Mario的妻子,Kim,毕业于斯坦福大学化学系,并获的工程学士学位。因为SpeedyNetworks公 司业绩一直在持续增长,所以Mario总是要寻找好的工程师。
如果你选择为你的工程创建人物,请仔细确定你进行了足够的市场调查和人数统计,保证你选择的人物确实表现了产品的目标受众。
人物描述对Mario进行了很好的介绍。但是,没有什么比图片表示的很真切,所以你应该再找一个Mario的图片包含到人物定义中。你 可以在网上查找或者从杂志上剪一个下来。一个由图片组成的立体人物定义可以给项目成员一个彻底的人物介绍。
大部分的人物定义都很长,不太适合写到记录卡片上,所以我建议你把他们写到一个纸上并且悬挂到团队公共的地方。你不需要把每个用户角色都进行人物定义。你 可以考虑为一、两个主要的用户角色进行人物定义。如果某一、两个用户是否满意你的产品对你系统来说是生死攸关的,那么这些用户是需要考虑扩充到人物定义中 的。
使用用户角色或人物的话,story变 得更加有表现力。在你区分了用户角色和一、两个人物后,你可以使用角色和人物来代替许多“the user”。 写“A Geographic Searcher can restrict his job searches to a specific geographic region。(一个地域搜索者可以在指定的地理区域内进行职位搜索)”比“A user can restrict job searches to specific geographic regions(用户可以在指定地理区域内进行职位搜索)”要好。这样写story可 以提醒团队Allan这个任务,他在寻找Maui岛 上工作。使用用户角色和人物
正在阅读:
中文User Stories Applied For Agile Software Development04-20
2016年全国导游基础知识全真模拟题11-18
EcIo优良比优化案例 - 图文02-02
农家书屋读书心得体会doc05-08
顶管施工方案04-28
SQL Server 2005及SQL Server 2008快照同步配置说明06-16
山东省淄博市淄川中学2019-2020学年高二(下)期中物理试题07-22
黄超勇简历04-27
- 1PPF - Development - Guide
- 2Unit 16 Stories 教案
- 3Kindergarten Level 01 Stories
- 4HPLC Method development
- 5HPLC Method development
- 6Software Engineering Chapter 2
- 7Mobile Application Development-lecture
- 8A Survey of the Development of English Literature
- 9Chapter 11 Applied linguistics(1)
- 10Computer Methods in Applied Mechanics and Engineering
- 多层物业服务方案
- (审判实务)习惯法与少数民族地区民间纠纷解决问题(孙 潋)
- 人教版新课标六年级下册语文全册教案
- 词语打卡
- photoshop实习报告
- 钢结构设计原理综合测试2
- 2014年期末练习题
- 高中数学中的逆向思维解题方法探讨
- 名师原创 全国通用2014-2015学年高二寒假作业 政治(一)Word版
- 北航《建筑结构检测鉴定与加固》在线作业三
- XX县卫生监督所工程建设项目可行性研究报告
- 小学四年级观察作文经典评语
- 浅谈110KV变电站电气一次设计-程泉焱(1)
- 安全员考试题库
- 国家电网公司变电运维管理规定(试行)
- 义务教育课程标准稿征求意见提纲
- 教学秘书面试技巧
- 钢结构工程施工组织设计
- 水利工程概论论文
- 09届九年级数学第四次模拟试卷
- 中文
- Development
- Software
- Stories
- Applied
- Agile
- User