敏捷开发
敏捷开发的几个误区
不少公司都在考虑采用敏捷开发,或者在项目开发过程中融入敏捷的思想,在这里,我列出几个常见的误区,希望能对大家有所帮助。
欢迎发表不同意见。
误区:敏捷开发 == 极限编程/Scrum/…
敏捷开发是一种方法论,只是一些基本原则的集合,并非具体流程。
极限编程、Scrum等流程是具体的实施方法,它们都声称符合敏捷开发的思想,但执行起来是否真的“敏捷”,还得看参与者究竟思想上是否真的接受敏捷开发的原理。
如果把结对编程、daily scrum当做是敏捷开发的表现,那更是本末倒置,可悲的是,不少人还真是这么认为的。
误区:敏捷开发 == 简化流程
敏捷开发不一定能简化工作流程,而且简化流程也并非提出敏捷开发的初衷。敏捷开发最重视的是拥抱变化,至于怎么拥抱,只能随机应变。实际应用中,既有流程相当简单的经典Scrum过程,也有极为冗繁、不亚于CMMI的RUP,根据应用场景不一样,项目组应该使用最适合的流程。
选择敏捷开发流程时也应带着敏捷开发的思维去选择,即快速响应项目实际的流程需求、拥抱流程应用过程中遇到的各种变化。没有银弹,也没有长期适合的项目流程,生搬硬套某个看似成熟的敏捷开发流程是大忌。
误区:敏捷开发 == 快速开始编码
敏捷开发强调迭代,鼓励开发人员用代码说话,不过绝对不鼓励没想明白就写代码。
符合敏捷开发思想的流程往往主张在一个稳定的基础之上迭代完成各种功能。如果基础都不牢固,迭代就无法进行,整个开发过程就退化成不断重写的过程,浪费开发时间。敏捷开发实际非常重视“设计”,并且对开发人员的设计水平提出了极高的要求,既要“持续重构”又不能“过度设计”,稍有不慎就会陷入反复推翻已有代码的窘境。对于内功不够的开发人员最好还是想好再写代码,设计的时候慢一点没关系,尽量少的做无用功才是最重要。
误区:传统开发能随时转变成敏捷开发
敏捷开发过于诱人,很容易让深受传统软件开发思想折磨的开发人员感觉敏捷开发就是灵丹妙药。
要想转变,首先需要从思想上正确认识敏捷开发的含义,了解它能解决什么问题、会带来什么新的问题、对现有软件/硬件资源有什么要求等。
例如在原先采用CMM的团队中,想利用敏捷开发简化冗余的文档、降低沟通成本,那么敏捷开发确实能在一定程度上缓解这些问题,但也会造成内部文档缺失、沟通不够深入的问题,在应用敏捷开发之前需要先确定适合团队的新的文档流程(代码注释能够自动/半自动的变成团队需要的文档么?),并且确定沟通的一些原则(比如,对于一些重要的沟通,是否还是用邮件来进行,不要过于“敏捷”?)。
有趣的是,有可能在回答这几个问题之后会发现,敏捷开发并不能解决项目中遇到的问题,反倒是其他方面出了问题。
举例来说。如果之前开发方法是简单的目标管理,遇到的问题是项目进度不可控、开发+测试的周期较长、不能及时响应需求变化,那么敏捷开发能解决的是快速响应需求变化,对项目进度和开发测试周期帮助不大(没有一种流程能够承诺改善项目的开发效率!),但前提是开发人员必须懂得怎样正确的去迭代开发,并且必须认识到一次迭代的结束是以完成测试为标准的。
在这个例子中可以看到,敏捷开发能带来的好处非常有局限性,如果开发人员达不到一定的层次是很难受益的。与其号召使用敏捷开发,不如想想如何增加执行力,以及找到周期偏长的根本原因(是因为设计不充分而返工?还是因为没有可以快速回归的测试用例?等等)。
分享/收藏
软件开发中的理想与现实(十三)(第一部分完)——新的培训即将开始
2月25日是非常值得纪念的,我们花了一个星期实现了一个最小的系统。虽然一切的设计还都非常原始,很明显有不少值得改进的地方,但我们确实已经实现程序的框架,并能够生成一些小东西了。这真的很令人振奋!
大家都从测试先行和迭代开发中尝到了甜头,每日会议也不会那么拘束了,每天都会感觉有所收获。这种感觉令人着迷,也让我对自己推行的东西更加有信心了。
不过,我们项目中始终有一项风险,那就是我的时间投入可能不够。这个星期,我为了让小组能够按我的想法工作,我投入了绝大多数时间在这里,而把管理另一个项目组的事交给其他几个同学负责去了,而实际上,那才是我最初最重要的工作。
另一个项目正是我们做这个代码自动生成程序的用户,也就是模拟客户了。这个项目也是刚开张,用C语言开发,原来安排的项目组长以及一些骨干都上北京培训去了,需要一个多月才能回来,剩下的同学大多没有任何经验,需要好好的培训。由于我在团队中培训和管理大项目都有些经验,而且这个项目也是那家大公司的外包项目,我已经有丰富的经验,所以刘老师就把临时管理的重任委托给我。
我当然不能辜负刘老师的期望,更不能厚此薄彼,我需要拿出点实际行动来做培训才行,但是那个项目需要遵循公司的CMM4的规范来做,挺郁闷,怎么办?
经过仔细思考,我决定在这两者之间找一个平衡点。
以下是我培训的通知:
2月28日下午2点,项目中的各种角色职能介绍,估计1小时。
3月1日下午2点,单元测试技术讲座,加上单元测试演练,估计3小时。
3月2日下午2点,结构化设计的演练极为精简版,包括模块分解图的绘制(只用在纸上绘制即可)、部分伪码的编写(请大家都准备好VC6)、部分单元测试的编写、C代码的编写,估计3.5小时。由于这个演练需要分3组,每组4人,按列分组,这里面需要一个组名和一个组长,所以我希望大家积极讨论组名、推荐或者自荐成为组长。
我还是把重点放在设计、编码和单元测试上,虽然我不敢在这个组里面真的推行测试先行,CMM4的流程往往更倾向于使用经典的V模型,但我可以让大家体会测试的重要性以及单元测试的方法。其实之前我就想把自己做的一个CUnit给大家介绍试用(不是网上最著名的CUnit,因为我觉得那个太繁琐,不好用,就自己做了一个),但没有办法体现测试的重要(还记得单元测试的重要性那七条理由么?),好了,现在有机会了。
我希望这些培训能够让大家既接受我的想法、又能够按照CMM4做下去,看看理想是否能够变成现实。
分享/收藏
软件开发中的理想与现实(十二)——作坊的经理失业了
2月22日,转眼就开发的第三天。
项目刚开始的时候会遇到很多问题,特别是架构的设计会出现很多变故。昨天刚经历了“过度设计”的事件之后,使我更加认识到真实项目的艰险——这仅仅是一个实验项目,难度也不高,但前两天过的就那么的有声有色,还是有点出乎意料。嗯,可以想象,今天也绝对不会平淡。
果然,“作坊”出事了!
还是先回顾一下“作坊”的作用吧。作坊主要的工作是把词元(零件)进行分类,而分类的原理则是基于以下事实(请原谅我们最初对ASN的肤浅认识吧,以后我会用正确的认识更正这些误解):
所有用ASN语法的定义数据结构都能够规约成 typereference ::= Type Definition Constraint 的形式,而其中的Type包括 SEQUENCE、CHOICE和SET,以及其他更加简单的格式(SET和其他的格式我并没有介绍,不过没关系,这不影响本文叙述),Definition是大括号之间的Constraint则可以为空。
例如:
A ::= SEQUENCE
{
b BOOLEAN,
c INTEGER
}
其中,typereference = "A",Type = "SEQUENCE",Definition = "{ b BOOLEAN, c INTEGER }",Constraint = ""。
又例如:
B ::= INTEGER (1..255)
其中,typereference = "B",Type = "INTEGER",Definition = "",Constraint = "(1..255)"。这个 Constraint 表明,B 类型的变量只能是范围在 [1, 255] 的整数。
既然有这个前提假设了,那么再来看看 Definition 怎么解析比较好。注意到去掉大括号之后 Definition 就变成"b BOOLEAN, c INTEGER",而且事实上 c INTEGER 还可以扩充为 c [...]
软件开发中的理想与现实(十一)——够用就好
2月21日,项目正式开始第二天。
依照昨天设计的框架和接口,我们开始实现这些功能,不过似乎大家的进展都比较慢,特别是XophiiX,似乎他陷入了困境之中。
具体是什么问题呢?请看下面的接口定义:
class CReader
{
// … public: template <class ForwardIterator, class InsertIterator> bool ReadFile(ForwardIterator &input, InsertIterator &output);
};
为了让ReadFile尽量的通用并且完全不依赖于输入和输出的具体介质,我们把ReadFile设计成模板方法,入口参数是输入和输出的iterator。实际上,input接受的是istream_iterator<char>,output接受的是一个deque的inserter。这件事本身应该还不算艰深,只是XophiiX原来并没有关注过iterator的用法,不了解inserter的重大作用,也不清楚模板的成员方法如何实现,使得他实现这个接口时非常郁闷,只好慢慢的翻C++ Primer。
面对这种情况,我也比较矛盾。的确,我可以采用不同的、更简单的方式实现这个接口(例如直接传ifstream和deque),但是扩展性呢?我昨天才说要在设计之初降低耦合,怎么能够走回头路呢?所以我坚持了,而且主动帮他补课,但我知道,要很好的理解这些事情还要点时间。
OK,无论如何,他似乎已经对上面这些技术问题有所了解,不过新的麻烦又来了。由于这个函数要实现的是分词,所以我们必须读取单个的字符,包括空格符和回车符,但是很可惜,用istream_iterator<char>得到的iterator并不能得到空格符和回车符,我们试了很多方法都不行。这回真的郁闷了……怎么办?如果要坚持这种设计,我可以考虑设计一种调用ifstream的get方法的iterator,这可行但似乎小题大做了,毕竟我并没有义务去扩展STL。麻烦麻烦麻烦!
接下来的时间里我一直在权衡,说实话,我不想放弃这种“完全没有耦合”的完美设计,但又不想在系统设计之初就开始构建自己的基础库,这似乎是一种经典的过度设计。嗯,不知不觉这一天就过去了!
回寝室的路上我好好的总结了一下自己的想法,我突然意识到一个严重的问题:ReadFile接口设计本身是不是就是一种过度设计?我真的需要如此之低的耦合度么?是的,我其实不需要这样复杂的设计!在可以预见的未来(甚至一直到项目结束),我们读取的介质都只是文件,ifstream其实完全足够;至于输出介质,我可以封装一个CWordQueue(直接把deque<string>重新定义了一次),让CReader和作坊工厂都依赖于CWordQueue,未来就算要进行某种扩展,只需要保证push_back意义不变的前提下重新实现CWordQueue就可以。
那么,新的接口可以这样表示:
class CReade
{
// … public:
bool ReadFile(istream &input, CWordQueue &output);
};
我相信这个接口应该可以稳定到项目结束,其实这已经足够了。嗯,明天我一定要为自己的过度设计向大家道歉,如果不是因为这个烦人的接口,XophiiX也不会那么郁闷了。过度设计,让它离的更远些吧。
分享/收藏
软件开发中的理想与现实(十)——臭皮匠们的思考方法
2月20日真是令人难忘的一天。我们从无到有、从郁闷到兴奋,在此期间,大家都围着白板陷入痴狂,而且我们最终真的设计出来一点东西,可以开始往前走了,这感觉令人着迷。
不过我们确实还是走了很多弯路,在这里还是有很多经验教训值得总结:
举出足够典型的样例,根据例子来归纳设计。这其实正是测试先行的一种做法,当我们设计能力并不足以一眼看穿最佳的设计方法时,通过不断的归纳来逼近最佳的(或至少是可行的)设计是最有效的方法。例如,XophiiX的第一个设计,虽然并不能解决所有问题,但至少也是一个能够解决问题的设计(不要怀疑,这是真的),它比那种纯粹的空中楼阁好多了。
先从最粗略的系统流程开始考虑。这里说的流程并不一定指的是数据流图,还可能是状态迁移、用例图等等,反正就是最粗略的东西,只要能够理解需求就能够说出来的东西。例如,我画的那个流程图,大家起码都了解设计的重点和难点在哪里。
采用隐喻(metaphor)的方法可以形象的找到问题的切入点。我不知道原理到底是什么,但是当我们找到一个可以类比的实际系统之后,我们的思路就开阔和活跃了许多,甚至类的职责都可以通过类比来确定。例如,我们把收集词元信息比作“作坊”,然后再想象作坊内部运作模式,惊奇地发现思路一下就通了。
尽量在一开始就降低类之间的耦合。在设计之初降低耦合往往只是举手之劳,但是如果最开始没有理会这样的问题,那么到以后再试图解耦合则可能会造成极大的代价。例如,如果作坊一开始就需要专门为一个客户服务,那么如果我们需要加入更多用户就必须改动作坊的内部实现,而且测试的时候也需要假定作坊的客户是稳定的,实在是不爽。其实为了使类拥有“易测试性”,解耦合是非常必要的。
我们通过今天的开发过程意识到自身设计能力的缺失,我们离“设计师”还有很长很长一段路要走,不过通过总结这些经验教训,我们起码还是在前进。嗯,大家加油!
尽管今天确实得到了一个看上去不错的设计,但是谁都吃不准什么时候会开始第一次重构。能根据设计写出优质的代码才是检验设计合理性的方法,写代码的工作就放在明天吧,今天到此为止。
分享/收藏
软件开发中的理想与现实(九)——三个臭皮匠,顶个诸葛亮
我说过要介绍一下项目组成员的,既然马上要真正开始做项目,那么互相好好了解一下还是很有必要的。
项目组包括我一共四人,分别是realdodo(我)、chanjinn、wumaomao、XophiiX。
我自不用多说,在项目中以项目流程的引导者身份出现,同时也参与开发。
chanjinn是我的学长(噢,忘说了,我们四个都是学生),做过好几个项目,编过很多代码,嵌入式、Linux都有不少研究,做项目很有思想,唯一只是C++基础相对差一点,不过不要紧,软件开发中的经验和悟性很重要。他笑起来很可爱(^______^),就像括号里面那样,很和蔼可亲。
wumaomao是团队中少有的C++高手,了解不少C++和设计模式的东西,有很强的编程能力,绝对将是项目中的中坚力量。而且他写得一手好字,有深厚的文化内涵,令我十分佩服。
XophiiX是项目组中最年轻的同学,比我小整四岁,但在编程方面已经很有感觉,并且酷爱游戏编程,对新东西非常感兴趣。我见到他之后就马上感觉到后生可畏,他超过我只是时间问题了!
在团队中能够拉到这么强大的阵容真是十分难得,我相当知足了。不过,如果放到更大的范围内比较,我们都是菜鸟中的菜鸟,我们的能力还远没有值得骄傲的地步。这不,2月20日,项目正式开张的第一天,我们就遇到大难题了。
我们项目的第一个迭代目标是,将用ASN语法描述的消息转换成C语言数据结构。至于什么是ASN、为什么要自己开发而不用现成的ASN到C的转换工具、为什么不用yacc、为什么用C++开发这些功能等问题我都不想回答,反正我们有自己的理由(呵呵)。写一个最简单的例子,假设有下面的消息:
A ::= SEQUENCE
{
b BOOLEAN,
c INTEGER
}
那么转换成C语言之后应该是:
typedef struct tagA
{
BOOL b;
LONG c;
}A;
相信一看这个例子就能够明白,SEQUENCE和struct相对,BOOLEAN和BOOL相对,INTEGER和LONG相对,只要处理好这个对应关系就问题不大了。
根据这个想法,XophiiX提出一种设计(白板上画的草图,我把它稍微整理了一下):
当然,这是一种有效的做法,但是扩展性实在太差,因为ASN的语法可不比C语言简单!例如这个消息:
Sample ::= CHOICE
{
b BOOLEAN,
c INTEGER
}
那么换成C语言之后应该是:
enum Sample_E
{
I_B,
I_C
};
typedef struct tagSample
{
ULONG ulIndex;
union
{
BOOL b;
LONG c;
}choice;
}Sample;
噢,这是什么东西,根本就没有办法简单的进行对应了!如果用刚才简单对应的方式来处理,这个系统真的就会变成一个怪物了!所以这个方案就被否定了,啊,XophiiX不要伤心,在最开始这是很常见的事情。
为了方便确定设计的方向,我根据需求画出这个系统最基本的处理流程图(好了,大家终于知道我有多么菜了):
但是我还没有想好如何把它变成可分解的类,所以就算大家都比较认同这样的流程也没有用,不过作为一个大体思路,起码有助于指明方向。
马上,我们就把上面这个做了一个精简,并准备对各部分进行细化。精简图如下:
大家心里都明白,最重要也是最麻烦的就是如何收集词元信息,但是如何做最好呢?不知道!眼看着上午就要结束,白板上的图画了又擦,方案往往提出几分钟就被否,然后所有人都陷入一种抓狂之中。
OK,it’s lunch time。人是铁饭是钢,还是去休息一下吧。
午餐的时候大家都比较沉默,虽然我一直安慰大家,每个项目开始的时候都是这样的,设计的灵感会突然冒出来的,不过大家还是不太相信。
嗯,不管怎么样,灵感还真的就出来了。不知道是谁提出了一个“作坊”模型,让大家眼前一亮,简单的说就是,把处理ASN文件得到的词元当作零件,收集词元信息当作零件分类,修饰词元信息当作零件组装,输出C文件则是最终包装,那么“作坊”(就是收集词元信息)负责进货(得到零件)和销售(零件分类输出)。按这样的说法,为了进货,我们需要一个库存;为了分类,我们需要工人;为了管理工人,我们需要一个经理。他们的职责也很清楚,库存负责存放零件,经理负责根据库存情况划定工作范围并“雇佣”合适的工人,工人则仅仅专注于工作。他们的关系如下:
这个图并不详细,甚至有些明显地错误,但是我们已经可以按照中央的想法进行工作了!综合来看,现在可以把整个处理过程表达如下:
下面我们就可以针对这种设计,具体规定这几部分之间的接口了!在规定接口时我们发现,这个流程并不具有弹性,因为作坊必须知道它的顾客(修饰词元信息)的情况才能工作,而我们是想实现一个面向广大人民群众的作坊,所以我们引入了一个代理商来解决这个问题。嗯,代理商具体是什么呢?哦,直接用main来做这样的代理其实就可以了!
最终,今天的框架如下:
至于接口,我们也慢慢的一一确定,此处不再赘述。今天的晚餐吃得特别香。
好了,喘口气,今天收获很多,等会我们来好好总结一下。
分享/收藏
软件开发中的理想与现实(八)——温故而知新
眼看着2月18日这一天就要结束,我不能再耽搁,必须要给大家总结一下这三天所讲的内容。
回顾2月15日晚我所讲的内容,我在这三天最想引进的东西是:
测试先行
迭代开发
每日会议
这些是我认为最为核心的东西。
此外我还介绍了以下内容:
重构
计划游戏
配置管理
风险管理
这是项目中必须要经历的或者要用到的东西,它们极为常用也非常有用,无论是怎样的软件项目都需要关注这些问题。
但是,嗯,好像对于迭代开发我并没有半点涉及啊……不,其实迭代开发就蕴含在测试先行、每日会议、重构和计划游戏之中!计划游戏确定最近的一次迭代目标,每日会议确定每天的工作重点,测试先行和重构就是一个一个迭代周期当中更加细微的迭代。迭代开发更多的是一种思想,而不是一种可以让每个人“掌握”的东西。
我看得出来,这些东西大家依然是一知半解(当然,我其实也只是一知半解),恐怕还没达到“学以致用”的地步,只有当理想与现实触碰的时候才能够产生最真实的思维闪光。究竟在这个项目中是否适用,我并没有十足的把握——嗯,我可没有那种随便下载一个文档模板自己试都不试一下就敢在团队里面大肆推广(甚至强制要求填写)的“魄力”,我连自己的小菜园都还要担心一下,更别谈推广了!我始终觉得,测试先行很重要,我必须等到项目达到一定的成功了才能公布这些经验和教训。
OK,虽然我们都带有一些疲倦,但是我们大概已经准备好接受现实的挑战了!
2月20日,项目将正式拉开帷幕!
分享/收藏
软件开发中的理想与现实(七)——有备才能无患
然后要说的是风险管理。
“风险”这个词很好懂但不容易精确定义,主要麻烦是它和“问题”之间的关系。
简单的说,风险是未发生的问题。这包含两点:
风险中所描述的事情现在还不是问题。
如果不加处理,风险会转化成问题。
比方说,彗星撞地球,使得项目无法继续进行(默哀……),这是一个风险;配置库遭到损坏,导致以前的配置信息丢失,这也是一个风险;而下星期一我要上课不能来,这是一件确定的事情,那就是问题了。当然,大家也有反驳,说如果课程临时取消了怎么办,没发生的就不能断定嘛。嗯,是的,我承认我说的不严谨,其实这样定义更好:问题是已发生或发生概率极大的风险。
风险会转化成问题,也可能会消失,它消失的原因可能有以下几条:
项目结束,所有风险消失。
由于措施得当,风险被规避。
风险变成问题的必要条件消失,所以风险消失。比如3月份我可能很忙,导致投入项目时间不足,但如果3月份已经过去,那么风险自然消失;又比如项目资金可能发生困难,但是由于来了一大笔钱,风险也自然消失。
尽管风险确实可能消失,但我们不能够通过虔诚的祈祷来让风险消失,我们需要认真面对这些事情,想出规避的策略。不过并不是所有风险都需要跟踪,要根据某总原则进行选择(要不然我得每天跑天文台,问他们会不会有流星砸中我们……)。这个原则就是风险发生的代价和规避风险的成本的比值必须大于1。
风险的代价一般用风险发生的概率和风险造成的损失的乘积来衡量,而规避风险的成本则是实际的成本估计。例如前面说的彗星撞地球的问题,损失很大,概率极小,而规避成本极大,所以这个比值肯定小于1,于是我们不予理会(听天由命吧)。而配置库的问题则是损失很大,概率比较小,规避成本比较小,比值应该远大于1,所以我们应该去好好考虑一下。不过,嗯,好像我又不严谨了,就算是严密跟踪风险,有些风险还是要变成问题,所以实际中我们考虑的是规避措施带来的效益和规避风险的成本之间的比值必须大于1,这个效益也就是最可能减少的损失。
理论上来说,我们应该试图跟踪每一个比值大于1的风险,不过实际中我们要讲究一个度,毕竟“提交可以使用的软件”才是我们的最终目标呢!按一般的经验,我们只关注值得跟踪的风险中代价最大的5~10个,这个根据项目不同而不同。
好了,理论聊了一大堆,实际上我们应该怎么做呢?
为了跟踪风险,我们需要开一个“风险管理会议”来找出所有感兴趣的风险。在这个会议中,大家首先各自用五分钟沉思,想想项目中有哪些风险(这是头脑风暴法的一种形式),并在纸上写下5个自认为值得跟踪而且代价最大的风险(“5”这个数也只是一个经验值,可根据实际情况进行改变),这个步骤叫做发现风险。五分钟后,大家将纸条贴在白板上,会议进入第二步,标识风险。详细分析风险之前,先去掉那些不是风险、不值得跟踪的风险,这是大家都得发表意见的环节。之后,为所有留下的风险按照风险发生的概率和风险造成的损失的乘积排序(为什么不按照规避措施带来的效益排序呢?因为我们还没有制定规避措施呢!为了简化问题,我们就用这个乘积了,这也就是为什么会有第一个不严谨定义的缘故),找出乘积最大的5个风险,这里的“5”也是一个经验值。好了,到了最后也是最重要的时候,我们要开始分析风险。分析风险包括为风险制定详细的规避措施并估计规避的成本、万一风险变成问题后如何解决问题、指定跟踪的负责人、确定开始跟踪风险的日期等,这些分析是由大家群策群力来分析,力求措施既有用又有效。
比方说,关于配置库的那个风险我们最终是这么分析的:
风险编号:3(仅仅是一个编号,编号的规则可以根据实际情况来定)
开始日期:2月20日
跟踪人:chanjinn(噢,我还没有介绍组里面的每个同学的情况呢,嗯,尽快补上)
风险描述:配置库可能因为种种原因损坏,导致开发资料丢失。
发生概率:中(有一定的可能性,不算大也不算小)
造成损失:高(我们都比较心疼这些资料,嗯)
规避措施:每日备份VSS数据库,并用邮件把备份发给项目组每位同学。(我们的配置库比较小,所以这样做没问题)
解决方法:恢复最近的VSS备份,并尽量收集最近的资料。
分析完毕后,我们就将这些风险一个一个抄在便条纸上并贴在白板上,不过在便条纸上还有些其它的内容需要预先留着:
关闭日期:(如果风险消失、或者变成问题,那么我们就无需继续风险,于是可以将风险关闭)
执行结果:(风险关闭时关闭的原因和最终的执行结果)
OK,这个会议完成了,嗯,花了不少时间呢,居然前前后后有一个半小时!以后分析风险不能这么慢了,要不然谁还敢做风险的管理。那么以后应该如何更新风险呢?最建议的做法是在每日会议上,每个跟踪人都应该关注自己跟踪的风险,并且及时提出风险跟踪过程中遇到的问题,包括跟踪成本超出预算、风险发生变化、发现新的跟踪方法等,然后至少每周做一次简单的风险管理会议。不过一定要注意,以后的风险管理会议就不需要这么冗繁了,直接把三步一次完成就行,时间也是一种成本啊!
参考文献:
[1] Tom DeMarco,Timothy Lister,与熊共舞:软件项目风险管理,清华大学出版社,2004.3
分享/收藏
软件开发中的理想与现实(六)——给自己留颗后悔药
做完今天计划的事情还剩下一些空余的时间,这可不能浪费,已经是培训最后一天了,还有一些简单但又关键的东西需要掌握呢!
首先我要跟大家讲的是配置管理,从某种意义上来说等同于版本控制(但不能划等号)。
说起这个话题,不得不首先说一下配置管理的工具。现在各种各样的配置管理工具都有,包括CVS、VSS、Clear Case等等,如果要评价谁好谁坏,其实没有任何意义,简单的说,够用就好。比如,对于这个小项目,VSS的功能对我们来说已经绰绰有余,而且它还和Visual Studio.Net结合的很好,所以我们就用它了;对于Internet上的开源项目,配置管理软件就需要考虑它的价格(最好是免费的)、稳定性、功能,CVS是一个很好的选择。
VSS的基本用法很简单,而我们做项目用最多的就是Check in、Check out、Get latest version和Show history,不要一分钟就可以讲完,不过还是有些注意事项要说明:
Check in的原则。不是所有的东西都能够Check in的,特别是代码,如果不能编译通过和测试通过的代码原则上是不能够Check in的(当然,具体问题具体分析,嗯)。而工程文件(Solution或者project)Check out之后要尽快Check in,当然,Check in时要满足前面的原则。每通过一个用例、或经过一次小型重构之后都应该Check in,以保存自己的工作成果。
Get latest version的原则。应该及时的Get latest version,特别是准备编译或运行测试用例时,应该先Get再Compile。这样做可以保证自己测试的结果始终是最新的、最正确的,也使得类之间的兼容或依赖的问题及早暴露出来。另外,千万不要在Get latest version的时候保持本地文件writable,要不然就有可能不小心改动了没有Check out的文件而导致一些损失。
经过简单的演练,大家就都明白这是怎么回事了,不过还有一个疑问没有解决:配置管理和版本控制的区别到底在哪里呢?
作为一个不正规的说法,版本控制可以认为是配置管理中最主要的一个内容,也是最贴近开发人员的内容,但配置管理还包含一些更加复杂、和普通开发人员关系不大的内容:
管理配置库的权限。在我们这个小项目中,权限对所有人都是一样而且都是可读写的,但是对于正规度高的项目,则需要根据阶段开放或关闭权限。例如在原来实习的公司里,每一个阶段结束的时候需要关闭CI目录(基线化版本所在的目录)的写权限,阶段开始时开启CI目录中相应阶段的子目录,如果这个阶段要修改前几个阶段的文档或代码,就必须向配置管理员、项目经理甚至外部评审专家申请才能够开放权限修改。这样确实挺麻烦的,但对于大型的或重要级别比较高的项目,如此严格的管理还是挺有必要的。
管理配置库的基线。做完一个阶段就在配置库相应的文档或代码上面打一个Label,方便以后回溯问题,也方便其他相关组提取正确版本的文档或代码。
对配置库进行备份。这一定要做!虽然通常而言配置服务器挂掉的可能性很小,但一旦挂掉,损失极大!而且就我的经验而言,这种风险还是时常会发生的,我自己就曾遇到过2次项目组级的VSS崩溃,和一个公司级的配置库故障。小心总是一件好事。
写配置状态报告。如果自己的工作会影响到其他的小组,那么就一定要写这个报告,把自己这边文档或代码的变化及时同时到其他小组。这件事是由配置管理员负责,是配置管理的一项活动。
这些事情就由我主要负责好了,反正也花不了多少时间。大家只要能养成一个使用配置库的习惯就不会有什么问题了。
分享/收藏
软件开发中的理想与现实(五)——知己知彼,百战不殆
冬天改不了凶残的本性,唯一能躲过它的淫威的地方就只有实验室,所以,嗯,2月18日早早的从实验室开始了。
今天是培训的最后一天,终于我也和大家一起投入真正的开发之中,不过我更多的还是以一个引导者的身份出现。昨天大家已经各自认领了一些人任务,也做了一些事情,不过如何知道互相之间进展呢?先从每日会议开始吧!
一听到这个名字可能就会让人产生反感,嗯,每日会议,真是文山会海啊!其实不然。每日会议只有项目开发人员参加,一般情况下只会持续10分钟(当然,根据项目人数不同,时间也有多有少),而且为了让这个会议尽量简洁,所有与会者采用站立的方式开会,所以每日会议有一个别名:站立会议。每日会议的议题十分确定,只用回答以下五个问题就行:
自从昨天工作之后,你都做了些什么?
从现在开始到今天工作结束,你将做什么?
是什么阻碍了迭代目标的实现?
有没有任务添加到待办事宜中?
相对其他的团队成员,你是否学到了一些东西,或者做出了一些新的决定?(技术方面、需求方面……)
这些问题的答案应该是尽量全面而且简练的,不要将回答问题变成了技术讨论,如果要讨论技术问题,或者要详细介绍前些天的所学所得,那么可以在会后请感兴趣的同学留下来慢慢交流。回答问题的顺序一般是根据站的位置确定的,大家围一个半圆形的圈,白板作为直径,从最左边的同学开始按顺序回答(抢位子很重要,嗯,不过万一没有抢到好位置,临时要求反序发言也是不错的^_^)。回答问题和一般讨论式的开会不同,大家各自发言,只有很少情况下会引发一些简短的讨论,简单的说,嗯,大家玩过“杀人游戏”没,每日会议可能和“杀人游戏”中的自辩很像,不过气氛不用那么沉闷……
通过这样的交流,项目的引导者(就是我啦)就会知道现在的项目情况到底如何,是否遇到了困难,大家也可以明确一天的工作重点,把自己遇到的问题、学到的知识用最方便的方式进行交流,让信息在项目组之内快速传播到每个人。
10分钟,花的还是很值得的!
分享/收藏
