![]() |
![]() |
|
首页 作文 翻译 随笔 本站 English |
项目回顾:一个开发人员的观察与思考胡健2002年11月项目背景这个项目的客户是欧洲一家人寿保险公司。该保险公司目前进行的一个计划是对现有的业务流程 (business process)和IT系统进行较大规模的改造,以适应新的市场要求。我们的项目是 这个计划的一个组成部分,它的目标是建立一个浏览系统与保险公司的后端保险 管理系统相连。这个浏览系统用Web浏览器作为用户界面,以取代目前使用的字符终端界面。 2002年初,公司的有关部门(专门作金融服务)曾作了一些 可行性研究工作。项目于2002年四月底正式启动,主要的开发工作于10月底结束。然后由 另一组人马进行用户接收测试(user acceptance test)。 技术与系统构架系统采用J2EE技术,系统基本上是三层(3-tier)结构,即Web接口(web presentation), 应用逻辑(application logic)和后端服务器(backend)。 系统需求与规范该项目主要有两种文档提供给开发人员:一种是系统功能描述,由一系列的模块组成。 每个模块类似于一个use case,主要给出了该模块需实现的屏幕/窗口(screen shot), 并一般地描述了这些屏幕上的操作以及它们之间的切换。这样的模块描述文件在项目 中被称之为“故事板”(story board)。“故事板”由业务分析人员(business analyst) 会同用户产生。 另一种文档是与后端服务器接口的规范说明,如命令格式,数据格式等,由后端系统 设计开发组提供。按照项目规定,两种文件都需要经过充分讨论并基本稳定下来之后, 由相关负责人员签发(sign off),然后交给开发组。 项目团队与工作地点项目组有14个开发人员,2个业务分析人员(business analyst),一个项目经理。主要开发 组在英国(10个开发人员),项目经理和其余人员则在客户所在地(与英国有一小时的飞行的 距离)。 工作笔记由于工作习惯,我一般每天都作工作笔记。而在这个项目中前两个多月中,我也每周都 写一篇小结,主要是对项目运行的观察(所计述的都是对我所在的公司本部开发组而言) 以下便是稍作整理后的前十周的小结(略去了公司和人员的名字)。这些笔记可能显得有些 杂乱和琐碎,列在这里的主要目的是想忠实地把我眼中的项目进展情况展现出来。 第一周
第二周
第三周
第四周
第五周
第六周
第七周
第八周
第九周
第十周
第三至六月第3-6月基本上是顺着第6-10周的路子走,但也有一些明显的变化:
讨论与思考下面的讨论将主要围绕一些XP的实践原则展开。 用户在场(On site customer)尽管开发组的一部分在客户地点,但主要的开发工作却是在公司本部进行的。这里没有用户, 没有业务分析人员。这点显然与XP的原则相违背,而其造成的不利影响贯穿于项目 始终。首先是对制订计划与进度表的影响。一般来说,在制订计划之前,开发人员需要花 一两天读一个“故事板”,然后作出初步估计。故事板简单易读,能使人很快地大致了解 一个功能模块的需求。但是,很多地方比较模糊,有些地方在阅读文档中仔细一点就能看出来。 这时最好有用户/业务人员在场,马上就能澄清。象我们靠电话和email,时间花的多,还不见 得能说得很清楚。 第二个影响要更严重一些。“故事板”中的不确定性有些在读故事板时能发现, 而有些就只能到了编码的时候才能暴露出来。由于业务分析人员在客户 那边,只能靠电话和email,其质量当然不如面对面的讨论好。特别是当不能及时 得到答案而时间又紧迫时,程序员往往得靠经验和“推理”作一些假定。如果是错的话, 就只能在功能测试和用户接收测试时再改了。 另外一个类似问题是与后端系统通讯的规范说明,这是由另一个项目组提供。那么我们与他们 之间也是有个沟通的问题。而糟糕的是该项目组也是在客户那边,因此只能靠电话和email。 总之,我觉得这个项目的实践是从反面证明了用户在场的重要性。 制订计划与进度如上所言,制订计划和进度表是从阅读“故事板”和规范说明开始。经过若干电话与email的 往来后,制订出一个计划,主要是把需完成的模块进一步分解成一些任务,以及估计完成每个 任务要花的时间,以0.5天为一个单元。该计划是一个spreadsheet文件,放在项目的文档 服务器上,大家随时可查看。 “并行开发”我们的项目有一点和正规的use case driven的过程不太一样。一般是一个周期主要是做一个 use case。在我们项目中,一个“故事板”大概算一个use case。如在“工作笔记”中所言, 在项目走上“正轨”后(从第六周开始),一般是2-3人做一个“故事板”。 所以,一般同时可能有两三个“故事板”在进行。每个“故事板”的周期约3-4周。 这样做的好处是提高了生产率,但我觉得这样做的前提条件是每个开发人员必须是 有足够的经验与技能,还有就是熟悉开发过程(第4-5周的实践是非常重要的)。 单元测试单元测试是客户的一个要求。在前两个月,我们做还有些“过分”。我们是用NetBeans提供的 工具对每个类(class)都生成相应的JUnit测试类(test class)。对一个类而言,其中的每一个 public和protected method都在test class中有对应的一个test method。而这个test method 里只有一个fail语句。这样强迫你用测试来替换这个fail(当然你也可以把它删掉)。结果我们 发现花了很多时间去写getter和setter的测试,实在不值得,因为这些methods非常简单。 我们因此说服客户,允许我们不用对getter和setter些测试。不过,我倒是发现,对 getter的测试,实际上是在测试相应attribute的初始值。设置初始值常常被忽略,而会在 运行中引起一些问题,如最常见的NullPointerException。 单元测试通常要求把被测的对象孤立起来,即测试不要用到其他的类。而实际中,一个类 往往要用到其他的class提供的服务来完成自己的功能,最常见的如使用数据库或一个远程服务。 单元测试需要切断这种依赖性,即一次只测试某个我们需要测的类。这可以利用Mock Object (“模拟对象”)技术来达到,例如,用一个mock service来代替真正的service,而我们可以 很方便地对这个mock service进行状态设置。在我们的单元测试中就大量地运用了这种技术。 网上有一些工具可用来帮助产生mock objects,如MockMaker,可以节省一些时间。 总的来说,单元测试的确提高了源码质量。那些逐步建立起来的test cases,我感觉是起到了一张 “警戒网”的作用。源码修改需要作改动时,这种作用特别明显。不过,我们也注意到,对一个类 进行完整的单元测试所花的时间往往不少于编码的时间。因此,一个很重要的问题是决定测试到什么 程度。XP的建议是对“可能会出问题”的地方要重点测试。但什么是“可能会出问题”的地方则需 视具体情况而定。 系统集成与功能测试由于我们这里没有一个真正的后端系统,因此没办法作真正的集成与功能测试。在项目的前半期, 我们曾建立了一个“哑”后端,这的确对我们的测试/调试起到了很大作用。但是,当越来越多的 功能加入后,“哑”后端变得越来越负责和不可维护。最后,我们只得放弃这种做法。 项目的管理层曾作了很大努力,想使我们这里能直接连上客户那里的后端系统,这在技术上是完全 没有问题的(毕竟这是网络时代)。但不幸的是,这个合理要求没能得到满足。所以项目后半期, 当一个“故事板”的的编码与单元测试完成后,一般由编码者或测试者飞到客户那里去做集成与 功能测试。 结对编程(pair programming)在我们这个项目的实际中,pair programming与“传统”上的意义有些不同。首先,因为我们坐得 都很靠近,如果某人有什么问题,只要一叫,一般就会有人跳起来跑过去帮忙。这可算是一种 “基于解决问题”的pair programming。 另外一种更主要的是方式是编码与单元测试的结对。由于测试者对于如何使用一个(待测试)的类 一般不会有着与编码者完全一致的思路,这样对于发现问题是很有帮助的。另外,由于测试者一 般都会在测试时详细阅读源码并与编码者讨论,这对于改进一个class的细部设计与实现也是很有 用的。但这种审阅与源码有所不同,这里主要是着重“逻辑”的正确与有效,而源码审阅则偏重于 源码的风格与标准的统一。 还有一种方式可称之为“结对排故”(pair debugging),我发现这种情况多在系统功能测试中出现。 如果在测试中出现一个问题(bug),找来找去找不到(因为这时涉及的东西的较多),搞得昏头胀脑。 那么最好是抓一个同事到屏幕边上(最好不是和你搞同一个部分的),然后给他讲讲是怎么回事。他可能 会一眼看出问题所在(如果他曾遇到过类似的问题),或者会从另一个角度来提供一个思路。另外, 常常也有这种情况,来帮忙的可能只是听着,而你在讲的时候可能就自己发现问题了。我想这是因为 你在给其他人解释一件事的时候,你实际上是在强迫你自己清理自己的思路,而这肯定是有助于找到 问题的(特别是在昏头胀脑的时候)。 编码标准(coding standards)项目开始的时候,我们就决定采用Sun的“Java Code Conventions”作为我们编码标准的蓝本。随着 项目的进行,大家不断地讨论并同意加入一些与项目有关的标准,例如:
源码审阅(code review)源码审阅一直是项目的要求之一。但在项目的前半期,这点做得不是很正式。当然,一个主要的原因是大家想 尽快地做出一些功能。这样造成的一个后果是源码开始有些杂乱并且不一致。项目后半期开始比较严格地进行 源码审阅,并且规定一个“故事板”的源码在进入系统测试之前一定要有正规的源码审阅。 进行源码审阅时,审阅者一般是根据编码标准上所列的条款对源码进行检查,看是否符合标准。同时,也可 对一些具体实现上提出自己的看法。这些意见用一张专门的表格一项一项地记录下来,交给编码者修改或给 出进一步的说明。最后,审阅者对源码复查,对每一项进行核对,满意之后签字认可。我们的经验表明,这样 的源码审阅大大地提高了源码的质量以及可读性和可维护性。另外一个作用是使refactoring得以经常 及时的进行。 源码重整(refactoring)我们项目里,refactoring基本上是与编码标准和源码审阅同步进行的。项目的前半期,基本没有refactoring, 尽管有些不好的码段或实现被不断的发现并记录在案。当然,主要原因还是由于大家想集中精力先做出一些 功能。在项目的后半期,开始和源码审阅一起较严格地执行。和源码审阅一样,这样做的结果是大大地提高了源码 的质量。 以上这些就是对这个项目的一些观察与思考。总之,对开发人员来说,这个项目有许多的不确定性, 这主要反映在需求与规范文件上,也反映在相关项目组之间的协调(或扯皮)上。项目组分散两地, 测试环境的缺乏都是开发中的很大问题。在这种情况应用XP的实践原则,如密切沟通,单元测试,源码审阅 与重整,能有效的(也许是艰苦地)推进项目的进展。 后记记得几年前曾看过一篇文章是讲中国的MBA的教育的。大意是说工商管理是个实践性很强的专业,做MBA的一 项主要工作是做大量的个案分析。而目前中国似乎还没有足够的个案,有待于现在的MBA们毕业后在工作 中去积累。这些积累起来的个案将是今后MBA们一笔宝贵资源。由此想到软件开发,何尝不是如此。 软件开发是个实践性很强的群体/团队工作,这点从三十几年前“软件工程”的提出时,人们就已经认识到了。 提出的方法也是层出不穷,但真正在实践中运用的并不多。 这几年出现的以XP为代表的agile方法兴起,主要原因就是在于它们是从工程实践中提炼出来,而其可行性 至少在一定条件下或范围内又为他人的实践所证明。那么我觉得现在最重要的不是高谈阔论,而是扎扎实实的实践, 即在了解这些原则后如何在工程实践中加以运用。更进一步,如果能把这些实践记录下来,加以总结,这 对自己和同道都是一件好事。基于这样的想法,在下不避琐碎,把自己对一个项目的观察与思考写下来,期望 能抛砖引玉,看到更多的同道能把自己的经验写下来,与大家共享。 修改记录
|
|
[首页] [作文] [翻译] [随笔] [本站] [English] | ||
![]() Except where otherwise noted, this site is licensed under a Creative Commons Attribution-NonCommercial 2.5 License. |