#
摘要: 运行SPRING BATCH JOB 的时候,有可能出错,如果能有相关的错误处理机制,则这些错误就能及时得到处理。
SPRING BATCH 提供了监听器,可配置在JOB执行完后,或执行JOB前,要执行的方法。
JOB的定义及BEAN的配置文件:
Code highlighting produced by Actipro CodeHighlighter (...
阅读全文
敏捷协作——Daily Scrum 的重要性
我不仅发挥了自己的全部能力,还将我所仰仗的人的能力发挥到极致。
——伍德罗·威尔逊,美国第28任总统(1865—1924)
只要是具备一定规模的项目,就必然需要一个团队。靠单打独斗在自家车库里面开发出一个完整产品的时代早已不再。然而,在团队中工作与单兵作战,二者是完全不同的。任何一个人的行为都会对团队以及整个项目的生产效率和进度产生影响。
项目的成功与否,依赖于团队中的成员如何一起有效地工作,如何互动,如何管理他们的活动。全体成员的行动必须要与项目相关,反过来每个人的行为又会影响项目的环境。
高效的协作是敏捷开发的基石,面对面的会议是最有效的沟通的方式。每日例会(Daily Scrum)是最早引入并被极限编程所强调的一个实践。它是将团队召集起来,并让每个人了解当前项目进展状况的一种会议。它是一个快速的会议,每个参与者只能被给予很少的发言时间(大约两分钟)来介绍自己的项目进展概要。为了保证会议议题不会发散,每个人都应该只回答三个问题:
- 昨天有什么收获?
- 今天计划要做哪些工作?
- 面临着哪些障碍?
Daily Scrum 有诸多好处:
- 让大家尽快投入到一天的工作中来。
- 如果某个开发人员在某一点上有问题,他可以趁此机会将问题公开,并积极寻求帮助。
- 帮助团队带头人或管理层了解哪些领域需要更多的帮助,并重新分配人手。
- 让团队成员知道项目其他部分的进展情况。
- 帮助团队识别是否在某些东西上有重复劳动而耗费了精力,或者是不是某个问题有人已有现成的解决方案。
- 通过促进代码和思路的共享,来提升开发速度。
- 鼓励向前的动力:开到别人报告的进度都在前进,会对彼此形成激励。
总之,Daily Scrum 能帮助所有的团队成员全心投入到项目中,并且一起向着正确的方向努力。IBM® Rational® Team Concert (RTC)对于团队来说,已经被证明是一种在软件开发过程中进行协作的高效方式。RTC 实现了源代码管理与工作项管理的完美集成。它能够帮助进行敏捷计划、并生成报告,方便管理工作项,并且它还提供了一种有效的框架来支持每日例会(Daily Scrum)。下面,本文将介绍三种使用 RTC 进行 Daily Scrum 的方式。
在 RTC 里使用默认的 sprint backlog 进行 Daily Scrum
双击打开项目当前所处于的 sprint backlog(sprint 是 scrum 中的术语,指敏捷开发周期中的一个迭代计划),如图 1 所示,在窗口底部选择“Planned Item”标签,在窗口右侧选中 Schedule Risk 单选按钮,窗口将呈现将列出当前 sprint 中的所有工作任务项 story 和 task。在进行 Daily Scrum 时,团队成员可以根据这个窗口,逐一更新这些任务的状态。
图 1. 默认的 sprint backlog 窗口
用户可以展开任务项来显示其各个子任务,了解子任务是由谁负责,进展等详细信息。如图 2 所示。
图 2. 展开的默认 sprint backlog 窗口
这种召开 daily scrum 的方式非常简便。它能够展示整个项目的进展和最近的变化,但是任务项不是按照团队成员分组的,不太适应于了解各个团队成员状态。为了解决这个问题,本文下一章介绍另一种用 RTC 进行 daily scrum 的方式。
在 RTC 里定制 sprint backlog 进行 Daily Scrum
定制的 sprint backlog 又称为“开发者任务一览表”。一览表按照团队成员展示任务,每一行表示一个正被开发的任务。任务显示在第一列,其余几列显示其子任务的开发状态:ToDo(将要做),In Progress(正在做)和 Done(完成)。并且,各任务根据其当前状态,分别用不同的颜色显示,一目了然。定制 sprint backlog 的具体步骤如下:
- 打开项目所在的当前 sprint backlog,点击 Copy 拷贝这个计划的模式。如图 3 所示:
图 3. 拷贝当前计划的模式
- 修改某些选项的值。比如修改定制 sprint backlog 的名字为“Developer's Taskboard”,风格选择“Taskboard”,分组选择“Owner”,排序选择“Creation Date”,进度条选择“Progress”。如图 4 所示:
图 4. 修改某些选项
- 修改视图的布局。从窗口底部选择“View Layout”标签,从左侧列表中选择“Effort Tracking”和“Owner”到右侧列表。如图 5 所示:
图 5. 修改视图布局
- 为 sprint backlog 添加色彩。从窗口底部选择“Colorize”标签,根据自己的需要添加、修改、删除各种颜色。如图 6 所示:
图 6. 添加色彩
- 保存所做的修改,用户将得到自己专属的 sprint backlog。显示的效果如图 7 所示:
图 7. 用户定制的 sprint backlog 显示结果
当工作任务项不是很多的时候,这种方式非常适合进行 daily scrum。但是,如果当迭代计划中的工作任务项很多时,这种方式就不再适合了。为了解决这个问题,下一章将介绍最后一种用 RTC 进行 daily scrum 的方式。
在 RTC 里创建自定义的查询进行 Daily Scrum
一般在进行 daily scrum 时,项目管理者需要查询出最近正在被修改的任务,这包括状态是“New”和“In progress”的任务。创建这种自定义的查询具体步骤如下:
- 在“Work Items”下的“My Queries”上点击鼠标右键,选择“New Query…”,如图 8 所示:
图 8. 创建一个查询
在打开的窗口中点击“start from scratch”,如图 9 所示:
图 9. 从零开始创建一个查询
- 在打开的窗口底部选择“Conditions”标签,在窗口右上角点击加号,选择“Add Conditions…”添加查询条件,如图 10 所示:
图 10. 添加查询条件
根据需要选择一些查询条件,为这个查询取一个名字,保存。如图 11 所示:
图 11. 添加如下查询条件
- 共享刚刚创建的这个查询,供每个团队成员使用。如图 12 所示,在窗口底部选择“Details”标签,在窗口右上角点击“Share”,选择“Team or Project Area…”。
图 12. 共享查询
在弹出的窗口中选择共享这个查询给哪个团队,如图 13 所示,然后点击 OK,保存。
图 13. 选择共享团队
- 根据需要定制查询结果的布局,包括选择显示哪些列,按照哪些列排序等,如图 14 所示:
图 14. 定制查询结果的布局
- 显示查询结果。如果按照上述配置,查询结果将在“Work Items”标签下显示,如图 15 所示:
图 15. 查询结果
这种召开 daily scrum 的方式能够列出在最后一天工作任务项的变化,以及哪些工作任务项还没有完成。但是它们都是以列表的方式显示出来,界面友好性和可读性不是很好。
结束语
本文介绍了 daily scrum 在团队项目开发中的重要性,以及三种用 IBM Rational Team Concert 进行 daily scrum 的方式:默认的 sprint backlog,定制 sprint backlog,和创建自定义查询。这三种方式各有其优缺点:
- 当团队人员比较少,一般小于 5 人,并且只是关注当前 sprint task 时,比较适合采用第一种方式进行 daily scrum。使用它可以清楚的看到 Task 与 User Story 之间的层次关系,以及 User Story 的开发进度。
- 当团队人员比较多,规模比较大,有自定义的 RTC Task 或者有子 Scrum Team 时,比较适合采用第二种方式进行 daily scrum。使用它与第一种方式一样,也是只关注当前 sprint task,但它还可以按照自定义的方式分组显示,更清楚的了解每个团队成员的 task 状态。
- 当希望关注团队中所有 Task,而不仅仅是当前 sprint task 时,前两种方式都无法满足 sprint plan 的显示需求,可以考虑使用第三种方式自定义创建查询,进行 daily scrum。与前两种方式相比,它更加灵活,建立查询的条件非常丰富,可以根据需要创建多个查询同时使用。
请用户根据自己的需要选择不同的方式进行 daily scrum,进行高效的团队项目开发。
@import url(http://www.blogjava.net/CuteSoft_Client/CuteEditor/Load.ashx?type=style&file=SyntaxHighlighter.css);@import url(/css/cuteeditor.css);
Rational Team Concert 是一个建立在可伸缩,可扩展平台上的团队协作开发工具,提供了很多功能,整合了软件开发项目生命周期的所有任务,包括计划、迭代、流程定义、变更管理、缺陷跟踪、源代码控制和源代码管理、产品构建自动化,和各种各样的分析报告等。
1 介绍 Rational Team Concert
Rational Team Concert 是建立在 Jazz 技术平台上,支持若干种 Agile 开发模型。Jazz 技术平台使软件开发更加灵活,支持团队成员分布在不同地理位置,提供从小型团队到大型企业的可扩展的软件开发解决方案。Rational Team Concert,有时简称 RTC,具有如下特性 :
使用 Rational Team Concert,在软件开发中,能够实现信息的交换和信息集成,如果某个需求变化了,团队成员就会自动收到通知,团队成员也可以通过多种方式了解这种变化。Rational Team Concert 中的各种视图可以让你更详细地了解信息,跟进团队的开发进度和活动。
Rational Team Concert 使开发团队能够轻松和有效地执行和定制流程,这个流程是角色、实践活动、规则、权限的集合。
Rational Team Concert 中,变更管理的主要特点是用工作项跟踪和协调各种任务,这些任务包括故事(story)、缺陷(defect)、计划项(plan item)、以及普通任务(task)等。工作项和工作流程是灵活可定制的,工作项也可以与其他的变更管理系统进行整合和集成。
Rational Team Concert 中提供了工具来保证计划管理能力,对于项目团队,这些工具能够计划、跟踪、平衡项目的工作量,以反映团队的实际状态。对于 Scrum,可以创建和管理迭代计划。
Rational Team Concert 内置的源代码控制管理系统是基于组件的和建立在 Jazz 平台上的,它支持并行和敏捷开发,支持分布在不同地理位置的团队开发,同时它紧密地集成了缺陷跟踪、构建、和以流程为中心的自动化。
对于开发和测试团队,Rational Team Concert 提供了自动地构建识别、构建控制和构建可追溯性。团队成员可以跟踪构建的进度,查看构建的警告信息和结果,提交构建请求,并跟踪构建过程。
Rational Team Concert 的报告组件能够显示项目的进展和项目状态,可以容易地分析某些可能被隐藏的趋势;软件开发过程中的可视化数据和各种分析报告,能够支持有效的决策。
- Eclipse 客户端,Visual Studio 客户端和 Web 界面
这些客户端界面为开发者提供了一个灵活的集成开发环境。
2 Rational Team Concert 与 Scrum
Rational Team Concert 是个非常优秀的 Agile 敏捷开发管理工具,内置了几个过程模板,可以用来支持一些敏捷开发方法,比如 Scrum 过程、OpenUP 过程和 Eclipse Way 过程等等。本文分享一些使用 Rational Team Concert 实现 Scrum 敏捷开发的使用经验。
Scrum 是一个典型的迭代式增量的敏捷软件开发过程。整个开发过程由很多次迭代组成,每一次迭代是一个 Sprint,每个 Sprint 的周期一般是 2 周到 4 周。在 Scrum 中,用 Product Backlog 来管理产品功能或项目的需求,用 Sprint backlog 管理每个 Sprint 的任务。在每个 Sprint 中,Scrum 产品负责人从 Product Backlog 中挑选最高优先级的需求,在 Sprint planning 会议上由团队成员讨论,估算工作量,确定 Sprint backlog 任务列表。在项目进行中,每天要举行 Scrum 例会(Daily Scrum meeting)。在每个 Sprint 结束时,Scrum 团队提交增量的可交付物。每个 Sprint 结束时,团队成员进行总结和回顾,吸取本次 Sprint 的经验教训,为下一个 Sprint 做准备。请参考图 1 Scrum 模型。
图 1. Scrum 模型
Scrum 由以下几个部分组成:
- 角色(Roles)
- 产品负责人(Product owner)
- Scrum 负责人(Scrum master)
- 团队成员(Team member)
- 各种仪式和会议(Ceremonies)
- 每天 Scrum 例会(Daily Scrum meeting)
- Sprint 计划会议(Sprint Planning meeting)
- Sprint 评审会议(Sprint Review meeting)
- Sprint 回顾会议(Sprint Retrospective meeting)
- 工件(Artifacts)
- Product Backlog
- Sprint Backlog
- Burndown Chart
- Impediments List
在 Scrum 中,产品功能或项目的需求会列在 Product Backlog 中。Product Backlog 是一个项目所需的所有需求或功能的优先级列表,这个列表条目常常以用户故事(user story)的形式体现。产品负责人(product owner)维护这个列表,根据项目的进展和商业环境的变化修改优先级列表。产品负责人对产品的成功负责,定义产品特性和产品发布时间表,负责确定各种功能的商业价值,不断完善和优化 Product Backlog。
Scrum 负责人(Scrum master)管理 Scrum 过程,确保 Scrum 的做法是正确的,并且让团队成员理解 Scrum 的价值,消除项目进展中遇到的障碍,并保护团队成员不受外界干扰。
在每个 Sprint 开始的时候,小组举行 Sprint Planning 会议。在 Sprint Planning 会议上,产品负责人为即将到来的 Sprint 展示最想要实现的产品功能或项目需求,让团队成员把握和分析需要实现的功能,产品负责人和团队成员在本次 Sprint 中的目标达成一致,确定未来 2 周到 4 周的工作重点。然后团队成员决定如何完成这次 Sprint 的目标,并分解成所需的任务,这些任务就组成了 Sprint Backlog 的任务列表。在 Sprint Backlog 中,每个任务按小时预估完成时间,团队成员确定是否可以按时完成开发任务,如果没有足够的时间完成某个功能,可以将该功能从当前的 Sprint Backlog 中返回到 Product Backlog。Sprint Backlog 中列出了团队成员已经承诺在本次 Sprint 期间完成的工作。根据团队经验来评估工作量,而不是由 Scrum 负责人或产品负责人决定,这是 Scrum 的一个特点。
在每个 Sprint 结束,需要召开 Sprint Review 会议,评审已经完成的工作。Sprint Review 会议是一个简短和非正式的会议,任何感兴趣的人都可以参加,并从参与者得到一些反馈。
团队成员可以举行 Sprint 回顾会议(Sprint Retrospective),分析项目的经验。通过本次 Sprint 回顾会议,不断改进团队工作方式和不断提高工作效率,为下一个 Sprint 做好准备。
Rational Team Concert 中提供了 Product Backlog 和 Sprint Backlog 的功能,它们同 Scrum 敏捷开发中的重要工件 Product Backlog 和 Sprint Backlog 一致。
在 Rational Team Concert 1.0 中,如果创建 Product Backlog,切换至 Team Artifacts 视图,并在项目区域中,选择 Release 1.0,然后选择 New > Plan。在 New Plan 窗口中,输入 Product Backlog 作为名字。选择 Product Backlog 作为 Plan Type。
在 Rational Team Concert 3.0 中,在 PlansAll plansMain DevelopmentBacklog 下,有默认的 Product Backlog。打开 Product Backlog,点击 Planned Items 项,可以为 Product Backlog 添加工作项,这些工作项的类型为 Epic 和 story,对于 Scrum,类型为 story 和 epics 的工作项,描述了 Agile 中的用户故事,包括项目需求或产品功能。
在添加所有的工作项之后,产品负责人要为工作项设置优先级,优先级属性有 High、Medium 和 Low,这可以定义实现工作项的优先级顺序。
图 2. Product Backlog
图 2 大图
在 Rational Team Concert 中,Sprint Backlog 中包含了来自于 Product Backlog 相关的具体工作项。RTC3.0 含有默认的 Sprint,例如 Sprint1,Sprint2,并且有默认的 Sprint Backlog,对于有多个 Sprint 的项目,如果要创建新的 Sprint Backlog,首先需要创建 Sprint,然后才能为该 Sprint 创建 Sprint Backlog。打开 Sprint Backlog,在 Sprint Backlog 的 Notes 页面上,能够填写 Sprint 的目标,在 Planned Items 页面上,可以为 Sprint 添加工作项,然后,详细分解工作项,定义任务。
图 3. Sprint Backlog
还有另外一种方法为 Sprint 添加工作项,在 RTC 中,打开 Product Backlog 窗口,选择相关的工作项,然后右击并选择 Plan For,把这个工作项指定给某个 Sprint。
图 4. 给 Sprint 添加工作项
图 4 大图
在 Sprint Planning 会议中,团队成员分析需要完成的任务,为每个任务估计时间,
当估计完所有的工作项之后,可以看到每一个故事的总体估计值,以及整个 Sprint 阶段的总体时间估计值。
一般来说,Scrum 负责人分配任务给团队成员,团队成员也可以主动领取,在 Sprint Backlog 的列表内,可以实现将任务分配给团队成员。
图 5. 给工作项分配所有者
图 5 大图
在每个 Sprint,团队成员要每天更新 Sprint Backlog 中的工作项状态和时间估计,这样,根据更新后的工作项,RTC 便可以产生一个 Sprint Burndown 图表,这个 Sprint Burndown 图表以图形方式显示剩余的工作项和工作量,显示项目的进展,预测项目的未来情况。
3 使用 Rational Team Concert 有效地进行每天的 Scrum 会议
Agile 敏捷开发实践中,强调团队的自我管理。在 Scrum 中,自我团队管理体现在每天的 Scrum 会议中和日常的协同工作,在每天的 Scrum 例会中,团队成员一般回答一下几个问题 :
- 昨天完成了什么?
- 今天要做什么?
- 项目进展中,遇到了什么障碍和问题?
整个会议应该少于 15 分钟。这种经常性的沟通,让团队成员能够了解每个人都在做什么,他们正面临着什么问题,有什么事情需要其他团队成员帮助解决,提高团队成员的协作。
在 Scrum 中,要坚持举行每天的 Scrum 会议 , 了解团队成员的工作进展和遇到的问题,Scrum 负责人要维护一个障碍列表(Impediments List),帮助解决团队成员遇到的阻碍和问题,保证项目顺利进行。
每天的 Scrum 会议可以增加团队成员之间的沟通,并帮助团队成员更有效地工作。
在 Rational Team Concert 中,通过集成的视图,团队成员能够了解各种任务、计划、工作项,也可以查看当天需要完成的工作项,当团队成员更新每日的工作项时,其他成员也可以看到。
在 Rational Team Concert 中,通过持续跟进工作项,团队成员可以更好地了解工作项的优先级,集中精力在优先级高的工作项上,保证项目的正常进展。团队成员还可以规划自己的工作内容和更新剩下的工作项。例如,在 Rational Team Concert 的迭代计划编辑器中,团队成员可以直接看到今天或本周的工作项。这些都有助于每天的 Scrum 会议,了解每天的 Scrum 会议中的问题。
Team Central 视图中的 Team Load 部分也可以显示团队工作负荷,在每天的 Scrum 会议之前,Scrum 负责人可以监控团队成员工作负荷。
Rational Team Concert 提供了 My Work 视图以帮助每一位团队成员查看和跟踪自己的工作项状态。在 Sprint 阶段,团队开发人员可以在 My Work 视图中看到任务和工作项。
图 6. My work 视图
Planned Time 视图可以查看工作项的剩余时间,支持 Daily Scrum 会议,团队成员可以根据 Planned Time 视图讨论哪些已经完成和哪些还没有完成。为了帮助跟进每个工作项的工作量,团队成员应该在 RTC 中每一天更新每个任务的剩余时间。
图 7. Planned Time 视图
图 7 大图
开发员的任务面板也可以分配和监视工作项,它显示了每个团队成员的任务。
团队成员可以使用查询来监视工作的进展状况,Rational Team Concert 已经有很多可用的预定义查询,还可以轻松创建新的查询。预定义的查询,预定义了一些查询条件,可以直接用来查询工作项,比如,'Open assigned to me','Recently modified'等,这些预定义的查询可以用于每天的 Scrum 会议,团队成员和 Scrum 负责人可以快速了解每个工作项的进展。
图 8. 创建一个新查询
对于地理位置上分散的团队,每天的 Scrum 会议有时通过电话或视频会议进行。Rational Team Concert 可以更好地辅助管理每天的 Scrum 会议,可以很快捕捉和处理阻碍项目的事情,然后,通过团队成员的协作,完成这些工作项或重新分配这些工作项。
4 在 Scrum 中,用 Rational Team Concert 进行软件源代码控制管理
在 Agile 敏捷开发最佳实践中,持续集成和自动化构建可以保证高质量的软件开发,持续地交付有价值的软件产品来提高客户的满意度。作为软件开发项目,需要一个高效和协作的软件源代码控制管理系统。Rational Team Concert 就是这种源代码控制管理系统,可以进行变更管理和配置管理,帮助开发团队管理源代码、管理文档、跟踪代码和共享代码的各种变化,并保持整个开发团队的高效协同工作;同时,Rational Team Concert 提供了自动地构建增量可交付物的功能,实现了软件开发的持续集成和自动化构建,实现高效的敏捷开发。
下图显示了在 Rational Team Concert 中源代码控制流转过程,开发人员把变更的源代码检入到存储库工作空间;然后提交到共享的开发流中,其他开发人员接受这些变更的源代码,并且装载到存储库工作空间中。
图 9. 源代码控制流转过程
在 Rational Team Concert 中进行源代码检入(check in)和检出(check out),需要连接存储库和项目区域,下载源代码到本地存储库工作空间中。首先把源代码从开发流装载到本地存储库工作空间,然后,在本地存储库工作空间修改源代码,提交变更的源代码到开发流中。开发人员在 Pending Changes 视图中,展开 Unresolved 节点,检入源代码,加上一些注解,然后,在 Outgoing 节点下,通过提交(Deliver)的功能,就可以把变更的源代码提交到开发流中。
当开发人员提交了变更的源代码到开发流中,团队中其他成员就可以接受这些变更,把变更的源代码同步到自己的本地存储库工作空间中。开发人员在 Pending Changes 视图中的 Incoming 节点下,选择变更集,然后,接受(Accept)这些变更,这些变更的源代码就进入了自己的存储库工作区。
5 在 Scrum 中,灵活使用 Rational Team Concert 的工作项
在 Agile 敏捷开发中,以用户故事(user story)的形式定义各种需求,Rational Team Concert 为 Agile 敏捷开发提供了类型为故事(story)和历史(Epic)的工作项,可以定义用户故事,定义的工作项会显示在 Product Backlog 中。在每个 Sprint,Sprint Backlog 中的任务也是一种类型的工作项,同时,工作项也是跟踪、协调开发任务和工作流转的基本机制,它是各种部件和元素之间的联系枢纽。
在 Scrum 过程中,Rational Team Concert 提供了一些常用的预定义工作项类型,这些类型的工作项全面支持 Scrum 敏捷开发。
- 缺陷(defect):定义缺陷和跟踪缺陷。
- 回顾(retrospective):记录先前正常但在最近完成的迭代中不再正常的内容。
- 故事(story):描述用户故事和需求。
- 历史(Epic):用户故事或需求很大而需要在多个迭代(Sprint)中完成,或者由于未知情况过多而无法估计工作量的用户故事。
- 任务(task):描述特定的工作任务。
- 障碍(impediment):跟踪导致无法取得进展的因素。
在 Rational Team Concert 中,Product Backlog 中的用户需求或产品需求是通过工作项来描述,在 Scrum 的每次迭代中,用户需求或产品需求会被分解成为足够小的类型为任务的工作项,放在 Sprint Backlog 里,并且每一个任务是被赋予了优先级。
在工作项中有很多属性,充分和准确使用这些属性,Rational Team Concert 可以让 Scrum 敏捷开发更有效率。
图 10. 工作项属性
摘要(Summary)字段是一个工作项的简短总结和标题,可以让 Scrum 成员和 Scrum 负责人快速理解工作项内容。
工作项的类型(Type)定义了工作项的特性,包括缺陷(defect),任务(Task),故事(Story)等,不同的类型有不同的属性和不同的状态变化。类型为故事(story)的工作项,可以描述 Scrum 的 Product backlog 中的用户需求或产品需求。类型为任务(task)的工作项可以定义 Scrum 中每一次迭代(Sprint)的任务。类型为缺陷(defect)的工作项可以记录每个 Sprint 中测试验证阶段的缺陷,跟踪缺陷的修复状态和进展。
严重级别(Severity)定义了工作项的严重等级。
描述(Description)字段详细描述了工作项的目标和相关信息,描述 Scrum 中的需求和任务。
所有者(owner),显示这个工作项当前的拥有者或执行者。在 Scrum 中,团队成员可以通过这个字段知道自己负责的任务,Scrum 负责人可以分配任务和了解团队成员的任务情况,在每天的 Scrum meeting 时,可以监控 Sprint 的进展。
优先级(Priority)属性指定这个工作项的重要性和优先顺序。高优先级的工作项将会被优先开发并确保完成。低优先级的任务有可能被转入下一个迭代(Sprint)周期继续开发。
计划目标(Planned for)属性指定这个工作项属于某个 Sprint。
状态 / 解决(State/Resolution),显示这个工作项的当前状态。
在 RTC 中,灵活使用工作项,可以提高 Scrum 的执行效率,下面介绍一些使用工作项的技巧:
在摘要(Summary),描述(Description)和讨论(Discussion)字段中,支持粗体("bold")和斜体("italic"),也可以创建与其他工作项的链接。在工作项中,可以选择一些文本,使用上下文菜单中提取工作项的功能(Extract Work Item),提取相关的工作项内容。
在讨论(Discussion)字段中,添加评论,也可以和评论的作者进行聊天会话或发送邮件。
在快速信息(Quick Information)部分 , 可以通过上下文菜单添加订阅者、附件、链接到其他工作项,也可以附加屏幕截图。
可以使用"查找"对话框,搜索包括摘要(Summary),描述(Description)和讨论(Discussion)部分的内容。
在编辑器的工具栏中,可以使用'寻找潜在的重复工作项'(Find Potential Duplicates),发现可能重复定义的工作项。
6 总结
Rational Team Concert 是一个建立在可伸缩和可扩展平台上的团队协作开发工具,整合了软件开发项目生命周期的所有任务,包括计划、迭代、流程定义、变更管理、缺陷跟踪、源代码控制和源代码管理、产品构建自动化,和各种各样的分析报告等。Rational Team Concert 有力地支持了一些 Agile 敏捷开发方法,利用 Rational Team Concert 进行 Scrum 敏捷开发,能够开发出高质量的产品和项目,能够进行高效率的协同工作,持续的集成和自动化构建交付物。
@import url(http://www.blogjava.net/CuteSoft_Client/CuteEditor/Load.ashx?type=style&file=SyntaxHighlighter.css);@import url(/css/cuteeditor.css);
SPRING BATCH 柯以测试的内容:JOB, STEP, INTEMPROCESSOR, ITEMREADER, ITEMWRITER。
JOB, STEP属于功能测试(黑盒)的范畴,INTEMPROCESSOR, ITEMREADER, ITEMWRITER属于单元测试(白盒)的范畴。
/*
* Copyright 2006-2007 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package example;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import java.util.Date;
import java.util.concurrent.Callable;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.batch.core.BatchStatus;
import org.springframework.batch.core.Job;
import org.springframework.batch.core.JobExecution;
import org.springframework.batch.core.JobParameters;
import org.springframework.batch.core.JobParametersBuilder;
import org.springframework.batch.core.StepExecution;
import org.springframework.batch.core.launch.JobLauncher;
import org.springframework.batch.item.ExecutionContext;
import org.springframework.batch.item.ItemReader;
import org.springframework.batch.item.ItemStream;
import org.springframework.batch.item.NonTransientResourceException;
import org.springframework.batch.item.ParseException;
import org.springframework.batch.item.UnexpectedInputException;
import org.springframework.batch.test.JobLauncherTestUtils;
import org.springframework.batch.test.MetaDataInstanceFactory;
import org.springframework.batch.test.StepScopeTestExecutionListener;
import org.springframework.batch.test.StepScopeTestUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.annotation.DirtiesContext;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.TestExecutionListeners;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.support.DependencyInjectionTestExecutionListener;
@ContextConfiguration(locations = { "/test-context.xml",
"classpath:/META-INF/spring/batch/hello-tasklet-context.xml",
"classpath:/META-INF/spring/batch/jdbc-job-context.xml",
"classpath:/META-INF/spring/integration/hello-integration-context.xml"})
@RunWith(SpringJUnit4ClassRunner.class)
//测试ITEMREADER/ITEMPROCESSOR/ITEMWRITER时用到
@TestExecutionListeners( { DependencyInjectionTestExecutionListener.class,
StepScopeTestExecutionListener.class })
public class HelloTaskletTests {
@Autowired
private JobLauncher jobLauncher;
@Autowired
private Job helloWorldJob;
@Autowired
private JobLauncherTestUtils jobLauncherTestUtils;//测试JOB/STEP的入口
@Autowired
private ItemReader xmlReader;
public void testLaunchJobWithJobLauncher() throws Exception {
JobExecution jobExecution = jobLauncher.run(helloWorldJob, new JobParameters());
assertEquals(BatchStatus.COMPLETED, jobExecution.getStatus());
}
/**
* Create a unique job instance and check it's execution completes
* successfully - uses the convenience methods provided by the testing
* superclass.
*/
@Test
public void testLaunchJob() throws Exception {
JobExecution jobExecution = jobLauncherTestUtils.launchJob(jobLauncherTestUtils.getUniqueJobParameters());
assertEquals(BatchStatus.COMPLETED, jobExecution.getStatus());
}
public void testIntegration()
{
while(true)
{
}
}
/**
* 测试某个STEP
*/
@Test
public void testSomeStep()
{
JobExecution jobExecution = jobLauncherTestUtils.
launchStep("xmlFileReadAndWriterStep",getJobParameters());
assertEquals(BatchStatus.COMPLETED, jobExecution.getStatus());
}
/**
* 测试READER的方式1时,所需的方法
* @return
*/
public StepExecution getStepExecution() {
StepExecution execution = MetaDataInstanceFactory
.createStepExecution(getJobParameters());
return execution;
}
/**
* 测试READER的方式1
* @throws Exception
*/
@Test
@DirtiesContext
public void testReader() throws Exception {
int count = StepScopeTestUtils.doInStepScope(getStepExecution(),
new Callable<Integer>() {
@Override
public Integer call() throws Exception {
int count = 0;
try {
((ItemStream) xmlReader)
.open(new ExecutionContext());
while (xmlReader.read() != null) {
count++;
}
return count;
} finally {
((ItemStream) xmlReader).close();
}
}
});
assertEquals(3, count);
}
/**
* 测试READER的方式2
* @throws UnexpectedInputException
* @throws ParseException
* @throws NonTransientResourceException
* @throws Exception
*/
@Test
@DirtiesContext
public void testReader2() throws UnexpectedInputException, ParseException, NonTransientResourceException, Exception
{
assertNotNull(xmlReader.read());
}
/**
* 测试READER的方式2时,必须加的方法
*/
@Before
public void setUp() {
((ItemStream) xmlReader).open(new ExecutionContext());
}
/**
*
* @return
*/
private JobParameters getJobParameters() {
String inputFile = "/Users/paul/Documents/PAUL/DOWNLOAD/SOFTWARE/DEVELOP/"
+ "SPRING BATCH/spring-batch-2.1.9.RELEASE/samples/"
+ "spring-batch-simple-cli/file/trades1.xml";
String outputFile = "/Users/paul/Documents/PAUL/DOWNLOAD/SOFTWARE/DEVELOP/"
+ "SPRING BATCH/spring-batch-2.1.9.RELEASE/samples/"
+ "spring-batch-simple-cli/file/output/out.xml";
JobParameters jobParameters = new JobParametersBuilder()
.addString("input.file.path", inputFile)
.addString("output.file.path", outputFile)
.addDate("date", new Date()).toJobParameters();
return jobParameters;
}
}
参考例子:
前段时间招聘。因为我一直在我的部门推行一些有效却被绝大多数中国公司忽视的开发理念,比如平级人事结构、测试驱动开发、制度化绩效、设计先行、迭代开发等等,所以招软件设计师非常困难。最终问题还算解决了吧。以下是我的面试总结。
一般来说,作为迎接面试的人,我会借着询问路况、接引进会议室或者索要简历,来表达出自己的礼貌,让对方有一定紧张感。这样我认为有利于对方表现出自然状态的思路。
然后我会根据简历,大概咨询下对方工作中所做过的设计工作。因为我在招软件设计师,所以只问设计,看看他对设计的理解是什么样子。通过这种询问,可以考察对方的简历是否作假,如果作假那么无法明确讲述其过往工作。还需要看对方的表达能力,即主动展现自己思路的能力。按照我这一批面试的人看,大多数人会讲述其项目经历的业务或者架构。只有一个人能够把软件设计和架构设计、软件开发分离出来。
然后就会开始做面试题了。面试题附在下边。我会先让其看第一大题,设计能力,请ta选择一道题目作答。看题之后,对方一般会陷入思考沉默。那么根据对方眼神不再在题目间扫动,表示对方已经针对某一个题目思考。当然,如果是沟通能力好的人,这这之前会主动告诉我,ta准备作答哪道题目。此时需要打断沉默,对对方说,希望对方谈一谈想法,任何一点想法都可以说出来。这个时候如果对方能够针对题目问一些具体没表示明白的细节,或者自行设定细节,都表明此人沟通能力极好,否则应该认为其沟通能力打折扣。
当对方陆陆续续讲述自己的设计时,作为面试的人,需要指出其没有思考到的地方,或者赞扬对方想的很合理。一般来说,面试的人在经历了之前的客套和紧张之后,不太容易沉下心来仔细思考。凡是这时候依然能保持有序高效的思考能力,说明这个人抗压能力极强,至少是心理调节能力极好。通过这时的回答,就可以看出此人对设计是否了解,设计能力怎么样。
以 1.1 为例,我随便说几个要点。比如说,我们应该抽象出牌局状态这么一个类,作为传输给每一个玩家的内容。比如说,我们可以抽象出一张牌这么一类,作为出牌的玩家上报的内容。比如说,此场景应该有一个短连接请求处理类,还应该有一个房间控制类;房间控制类里边维护一个个开通的房间;当每一个进入房间的请求来临时,都应该通过房间控制类,将连接转移到这个对应的房间编号;那么房间编号可以由客户端通过参数传递上来。比如说,每一个房间能够维护一组长连接,这可以开一个线程来处理;线程由一个单例的线程维护器对象来启动。比如说,房间在新线程中执行的代码,应该是轮询每个长连接看谁发来了“牌”,然后调用数据计算模块,通过牌和原有牌局(保存在房间对象里),得到新牌局,发送给每一个连接。当然了,如果能对断链识别什么的做出设计就更好了。不过控制此题时间不要超过 10 分钟,所以一般不可能讲述出太多内容。
接下来,要根据刚才设计方面的能力,中转到 2 或者 3 。如果设计能力不错,则应该转移到 3 ;如果设计能力不好,则应该转移到 2 。这个设计能力的好不好,是根据面试者觉得达标不达标,够用不够用来说的。
先来说说转到 2 编程能力测试的情况。首先,应让其在 2.1 和 2.2 中选一道作答。2.1 的要点,是建立合适的数据结构。最佳的是 money 与 id 双排序的基础对象构建的 TreeSet ,通过 NavigableSet 提供的子树功能,以 size() 获取名次。自己前后几位可通过正反向迭代器取得。当然,也可以使用链表和散列集合的二重结构。这要慢不少,但是也还算在可接受范围内能实现功能。
此题非常多的面试者会联想到 SQL 的 order by 子句。问题是这些人应该设计不出合适的二维表结构,配合 SQL 实现想要的功能。如果面试者能够实现,那也至少算能够做出来一种实现,不应苛求。
2.2 我认为用二维表传统关系型数据库很合适。应该有二个表,一个是历史表,一个是实际操作记录表。每次受影响玩家登录,都会激活从实际操作记录表到历史记录表的总结过程;这是一种最小型的数据挖掘。受试者能够正确写出总结过程,能够正确写出读取历史表的合并过程,则是满分。
编程过程测试,可以随时提供设计思路指导。旨在督促受试者利用短暂的面试时间,认真思考,发挥出最强的思维能力,以检测其通过自己思考解决问题的水平。如果能在不断的设计方案提示下,指出语句写法,则应该认为设计能力为零,但编程基本功很扎实。如果算法也需要提示,则认为编写程序的技能本身不好,但语言知识尚可。
做完 2.1 和 2.2 其中一题,应准备查资料的条件,也就是连接互联网的浏览器,让其做第 3 题。如果其对 Java5.0 多线程类库非常了解,则认为此人关注技术新闻,有很强的技术敏感性和学习能力。否则则应通过观察其查资料选用关键词的方式、查看内容的耐心敏感度,来判断此人的学习能力和心性。至此,您应该对面试的人有了较全面的认识。推荐记录下来,以便比较不同的面试者,谁综合看来更适用。
我们再来说说直接从 1 题转移到 3 题的情况。同样是 3.1 和 3.2 选做一题,来测试受试者的架构能力。以和设计能力测评同样的节奏进入互动,然后探寻受试者思路。架构的核心,在于指派分布,即指派哪些逻辑运行在什么地方,以及这些“地方”的布局方式。非常多的受试者无法分清软件设计和架构设计的区别。每当这个时候,面试官就应该主动给受试者讲述架构的含义,同时记录受试者不具备可用的架构工作经验,但应根据接下来的思路表现,来判断其架构见识、思路以及资质。
3.1 的要点在于网络存档应该与应用服务分离。应用服务做负载均衡的话,应制作单独的数据服务以支持网络存档。这样可以保证无论是运营后台还是玩家都能够看到全部的数据。如果受试者无法摆脱分区的概念,则应指出,运营后台页面,能够选择分区,每次选择,程序能够连接到不同区的数据服务。
3.2 首先这种全球性质或者打地理范围的系统,肯定要使用地域分流的域名服务(DNS)负载均衡。那么也需要建立专门的用户数据传输机制,以保证用户大范围移动物理位置之时,能够在对应区域取得自己的数据。为此,也就需要设置统一的数据中心,以登记不同区域的位置关系以及服务器地址。考虑到系统不可能一次性完成,使用能够自动加载的云基础结构,应该会是一个最合理的选择。
通过架构测评,如果受试者能够展现出关于自由软件的很多知识,则说明此人在技术进步上有较高追求。架构这边如果用时很短,也就是受试者表示出了对架构的恐惧和放弃,应该认为受试者面对困难问题的解决决心坚韧程度打折扣。这时应将其引导至 2.3 题,以考察其通过查资料解决问题的水平和心性。面试完毕之后,您应该记录面试情况,以便比较不同的面试者,谁综合看来更适用。
最后我想说一句。很多面试官都相信自己对受试者的感觉。其实面试流程的目的,就是通过流程,让受试者更多地表现自己,以丰富面试官的感觉,以防以偏概全、认识不足等情况发生。
下边附面试题目
1 设计能力(选做其一)
---------- ---------- ---------- ----------
1.1 现有多人卡牌游戏,由用户根据场上情况出牌。玩家出的牌可被其它玩家看到。每一种游戏牌将会对场上局面造成某些影响。请设计本游戏服务器端关于数据传输部分;其它部分如需指明,也可以指出。
1.2 现有某军事对战型网络游戏。架构设计安排在战斗发起之前,通过短连接方式进行信息处理。对战为一对一,对战开始之后,进行长连接,传输双方对军队控制的操作。请设计本游戏开始建立长连接以及传输操作数据部分的服务器程序。
2 编程能力(2.1 和 2.2 选作其一)
---------- ---------- ---------- ----------
2.1 数据结构
有一种数据,结构是
{
id: 38,
name: "Shane",
money: 3010.50
}
数据量大概有 100 0000 份。
请你设计一种方式,能够支持以下要求。
首先,需要能往已有数据集里边追加数据。如果 id 重复,则为修改。
其次,需要得到某指定 id 对应的人,全部数据按照 money 排序,其所在的名次。此过程不能太慢。
最后,能得到这个 id 对应的人,全部数据按照 money 排序,其名次的前、后几名的 name 。此过程不能太慢。
2.2 逻辑
一个社交游戏,玩家可以互相访问,并在访问时对对方进行某些操作。被访问的人在登录时统一接收上次登录到这次登录之间被访问的报告。
获取记录通过 InteractSysRecord.INST.getRecord(int userId) 方法,获得一个 List<ActRecord> 。
ActRecord 具有如下属性
int fromUserId
int toUserId
Kind actKind
int actEffect
其中 Kind 是一个枚举,包括一些类型,比如“赠送礼金”、“伤害”、“偷钱”等。
玩家获取的记录,需要按人整理。也就是说,在一个玩家登录之时,与其上次登录之间,某一另外玩家多次访问此玩家生成的多个 ActRecord ,应该合成一条。
请编程完成记录整理。允许设计合理的 InteractSysRecord 结构。
2.3 多线程(允许查资料,希望观点能独特、精辟、有实效)
请简述 Java5.0 多线程框架的机制和要点
3 架构能力(选做其一)
---------- ---------- ---------- ----------
3.1 请为如下功能需求设计架构。文字或图示都行。
现有某多客户端弱联网网络游戏,需要实现网络存档。请简述网络游戏存档的架构方案。注意,后台操作人员应该能任意查看、修改任何人的存档。要求说明设计理由。
3.2 现有基于位置的移动网络游戏。在游戏界面中,当玩家离开自己实际位置之时,就会在游戏中受到一个吸引力,吸引游戏中的角色回到玩家现实中的位置。此吸引力随着距离增加而增加。所有的玩家在统一的世界地图上进行对战。请设计此网络游戏的架构方案。并说明设计理由。
@import url(http://www.blogjava.net/CuteSoft_Client/CuteEditor/Load.ashx?type=style&file=SyntaxHighlighter.css);@import url(/css/cuteeditor.css);
扩展 Rational Team Concert 进行缺陷和代码质量分析
基于 Rational Team Concert 和 Maven 的差分发布
利用 Rational Team Concert 实现 Rational Functional Tester 自动化测试脚本的版本控制
在敏捷开发中如何使用 Rational Quality Manager 缩短软件测试周期
《孙子兵法》在敏捷项目管理中的应用
Rational Team Concert 用户的自动化管理
敏捷项目管理实战之进度管理
基于 Rational Team Concert 实现持续集成
利用 Selenium 和 Rational Performance Tester 轻松实现 Web 性能测试
急速性能测试之旅: 使用 Rational Performance Tester 8.2 完成 web 应用性能测试,第 2 部分
用 Rational Team Concert SCM Tool 实现代码自动化部署
stream 简介
Stream(流)是 Jazz 源代码管理系统中的重要成员,体现项目开发中的一个版本,由一个或者多个 component( 组件)构成。流的建立使得团队成员在不同的版本之间进行代码的共享与管理,满足项目迭代开发中代码管理的需要,促进团队成员之间更好的协作。组件是代码共享与管理的基本单位,由一个文件或者文件夹所构成,团队成员可以通过使用流中的组件进行代码的共享。
多个 stream 的应用场景
目前,软件开发中迭代开发非常普遍,项目的开发经常涉及两个或多个版本。即在一个版本尚未发布就需要进入下一个软件版本的开发,这样使得项目开发人员需要同时维护多个软件版本。特别是一个缺陷需要在多个版本上解决,这样在这些不同的软件版本上进行代码同步就成为团队开发人员日常的工作内容。如何简化代码同步的流程,提高多个软件版本代码同步的效率以及减少在多个软件版本中由于代码同步引起的缺陷数,对于降低软件开发成本和提高软件质量具有重要的意义。
RTC 对多 stream 代码同步的支持
源代码管理与共享是项目开发中的重要内容,而 RTC 作为主流的源代码管理工具,对项目的源代码的管理与共享提供了很好的机制。在实际的项目开发过程中,项目拥有者需要在远程 Jazz 服务器上创建 stream,项目开发人员在远程 Jazz 服务器上基于此 stream 创建自己的版本库工作空间。除此之外,开发人员还需要在本地的机器上创建自己的本地工作空间。开发人员通过 Check-in 操作将本地工作空间的改动同步到远程 Jazz 服务器上的自己的版本库工作空间,通过 Deliver 操作将远程版本库工作空间的代码同步到团队共享的 stream 上。其他团队人员则通过 Accept 操作将代码从 stream 同步到自己远程的版本库工作空间,并通过 Load 操作将版本库工作空间的源代码下载到本地的工作空间。依此类推,RTC 就可以同时管理多个 stream 并进行有效的共享,其具体的源代码管理与共享机制如图 1 所示:
图 1. RTC 中多 stream 源代码管理与共享机制
通过 RTC 中对源代码的管理与共享机制可以看出,如果不进行任何修改与配置,在多个 stream 上,开发人员只能通过单独维护每个 stream 上的源代码,并在这些 stream 上进行代码的来回复制达到多 stream 上的源代码同步,这样无疑增加了维护和同步多个 stream 上的源代码成本。事实上 RTC 可以通过更改相应的 flow target(目标流指向)来简化多 stream 上的源代码同步,有效的提高项目开发的效率。
总的来说,RTC 对多 stream 上源代码的同步提供了三种方式:各 stream 单独同步,stream 由低版本向高版本同步及 stream 由高版本向低版本同步,具体操作如下图所示(图中以两个 stream 为例,多个 stream 可以依此进行类推):
图 2. 各 stream 单独同步
图 3. stream 由低版本向高版本同步
图 4. stream 由高版本向低版本同步
从图 2 可以看出,同步 stream1 和 stream2 上的源代码需要在每个 Local workspace 上 Check-in 相应的代码,在同步第二个 stream 时需要从一个 Local workspace 上拷贝源代码到另一个 Local workspace 上,这样加大了开发人员的工作量,并且增加了一些由拷贝源代码所造成的缺陷。图 3 与图 4 的同步机制没有多大差别,图 3 所示的为源代码从低版本(stream1)向高版本(stream2)同步,开发人员先将代码提交到 stream1,然后改变 stream2 的目标流指向,接受之前提交到 stream1 上的变更集,最后通过 Jazz Server 上的 Repository workspace 将变更集提交到 stream2 上。图 4 所示为源代码从高版本(stream2)低高版本(stream1)同步,具体过程与低版本(stream1)向高版本(stream2)同步相反。由于高版本往往会包含低版本没有实现的功能,所以对于多 stream 的源代码同步,采用从低版本向高版本同步的方式遇到的潜在的源代码冲突相对较少,开发人员解决这些冲突并合并变更集所付出的成本也随之降低。因此,在实际项目开发中,对于多 stream 的源代码同步,采用低版本(stream1)向高版本(stream2)同步的方式最佳。
RTC 中多 stream 代码同步的示例
由于多 stream 从低版本中向高版本同步时潜在的冲突最少,因此本文将以这种同步方式作为示例说明如何在两个 stream 实现源代码的同步。对于三个或三个以上 stream 的代码同步,读者可以依此类推。在示例中,我们拥有两个 stream,6.3.1.1 和 6.3.2。并且我们已经创建好两个 stream 上对应的两个我们自己的版本库工作空间。
无代码冲突情况下的代码同步
打开 Pending Changes 视图,在 6.3.1.1 版本库工作空间上有个新的可交付变更集,右击选择 deliver 对其进行交付,具体操作如图 5 所示:
图 5. 交付变更集界面
打开更新版本的 6.3.2 版本库工作空间,更改其 Flow Targets 到 6.3.1.1 stream。如图 6 所示,将 6.3.1.1 stream 置成当前 flow target 且是默认 flow target,然后确认保存。
图 6. 版本库工作空间界面
保存后结果如图 7 所示。
图 7. 更改 Flow Target 界面
如图 8 所示,此时再次查看 Pending Changes,6.3.2 版本库工作空间已经指向 6.3.1.1 stream,刚才在 6.3.1.1 版本库工作空间中交付的变更集出现在 6.3.2 版本库工作空间的可接受变更集中。此时该变更集与 6.3.2 版本库工作空间中代码不存在冲突,可以直接选择接受。
图 8. 接受 Incoming 变更集界面
接受后,将 6.3.2 版本库工作空间的 flow target 改回 6.3.2 stream ,如图 9 所示:
图 9. FlowTarget 配置界面
从图 10 中可以看出,在 Pending Changes 中,6.3.2 版本库工作空间中有了新的可交付变更集,该变更集正是 6.3.1.1 版本库工作空间之前交付的变更集。由于不存在冲突,我们可以直接将该变更集交付到 6.3.2 stream 中,从而实现两个 stream 上针对该变更集的源代码同步。在下一节中我们将给出存在代码冲突的同步示例,为了模拟这种情况,我们暂且不交付此变更集。
图 10. 交付 Outgoing 变更集界面
有代码冲突情况下的代码同步
同样,打开 Pending Changes 视图,在 6.3.1.1 版本库工作空间提交一个新的变更集模拟代码冲突,右击选择 deliver 对其进行交付,具体操作如图 11 所示:
图 11. 交付 Outgoing 变更集界面
更改 6.3.2 版本库工作空间 flow target 到 6.3.1.1 stream。从 Pending Changes 视图中可以看到 6.3.1.1 版本库工作空间中新提交的变更集。该变更集前出现橙色高亮,说明该变更集和 6.3.2 版本库工作空间中可交付的变更集存在代码冲突。具体操作如图 12 所示:
图 12. 接受 Incoming 变更集界面
选择接受该变更集,此时会弹出是否自动解决冲突的对话框如图 13,我们这里建议选择 Resolve Later,以防止出现代码合并错误的情况发生。下面我会给出具体的情况说明在接受冲突变更集后如何 Resolve。Resolve 有两种方法:自动合并和手动合并。什么时候选择自动合并,什么时候需要手动合并,这对于维护代码的同步和准确性十分重要。
图 13. 冲突提示界面
选择 Resolve Later 后,将 6.3.2 版本库工作空间的 flow target 改回 6.3.2 stream。如图 14 所示,出现未解决代码冲突。双击打开冲突比较视图。
图 14. 未解决冲突界面
如果视图中仅有蓝色标识,说明没有严重冲突。如图 15 所示,可以选择 Auto Merge 自动合并代码。
图 15. 自动解决冲突操作
图 15 大图
如果视图中有红色标识,说明存在严重冲突,自动合并代码将导致代码错乱。如图 16 所示,将红色部分右侧代码拷贝覆盖到左侧,手工完成覆盖后,选择 Resolve As Merge 完成合并。
图 16. 手动解决冲突界面
图 16 大图
在弹出的对话框中选择 OK 确定手动合并操作,如图 17 所示:
图 17. 手动解决冲突确认界面
这样合并完成后,6.3.2 版本库工作空间可交付变更集如图 18 所示。此时可看到被合并的原变更集后出现 1 merged 字样,合并操作完成。对其交付后,6.3.1.1 stream 和 6.3.2 stream 在该变更集存在冲突的情况下实现了代码同步。
图 18. 交付合并后变更集界面
撤销已交付的错误代码
在同步两个或多个 stream 的时候,很可能误将不属于本 stream 的代码 deliver 到 stream 上。如果错误交付的代码过多的话,手动去删除错误交付的代码将会需要花费很大的工作量来将代码还原到原来的状态。而且,还会带来代码被错误修改的风险。而 RTC 提供了一种回退(Reverse)的功能,将错误交付的代码自动清除掉,并恢复到原来的状态。
回退(Reverse)功能的具体操作步骤如下:
- 右击错误提交的代码所相关的 work iteam,并单击弹出的 Reverse 菜单。
图 19. work iteam 的回退
- 点击 Reverse 菜单后,会弹出如下图 20 所示的窗口,指示修改前的文件将会在 Pending Patches 以 patch 的形式显示出来。然后,点击 OK 按钮。
图 20. 添加到 Pending Changes
- 如图 21 所示,在 patch 中你可以通过双击 java 文件来查看原来文件里的内容和错误交付代码后的文件的差异,来查看是否是你想要恢复的结果。
图 21. Patch 显示界面
- 将这个 patch 添加到现有的 workspace 上面,从而将原有的变更集先恢复到本地的 workspace 上。
图 22. 合并 Patch 界面
- 原有的文件将会作为未提交的文件显示出来。
图 23. 未解决冲突界面
- 通过将原有的代码重新 check-in 和 deliver,从而将被错误修改的代码从项目组共享的 stream 上删除出去。
图 24. Check-in 变更集界面
如果将代码错误提交到 stream 后,有其他开发人员提交了自己的代码,这个时候要进行回退的时候,需要查看需要回退的文件是否和其他开发人员修改的文件有冲突。如果有冲突,可以通过前面提过的方法进行代码冲突的整合;或者把错误提交代码以后其他开发人员提交的代码先回退回去,在把错误提交的代码从 stream 上删除以后,重新将其他开发人员提交的代码 deliver 到 stream 上。
致谢
衷心的感谢钱巧能工程师在本文大纲方面的讨论所提供的意见和支持。
结束语
本文详细介绍了 RTC 代码同步的原理,并且比较了目前 RTC 中多 stream 上代码同步的几种方法,最后以具体示例说明了如何在 RTC 中进行多 stream 的代码同步,解决代码同步中出现的冲突及如何撤销错误的代码同步。读者可以通过阅读本文,掌握各种在 RTC 中多 stream 代码同步的方法,并根据项目实际情况选择,灵活运用,提高项目开发的整体效率。
简介
本文介绍了 IBM Rational Team Concert(RTC)的代码评审功能(Code Review)。这一功能可以使代码评审流程变得更加规范,完善代码提交流程;对于不同区域的成员可以更高效的协同工作,在代码提交前发现到潜在的问题,尽快修复,提高代码质量,有效减少缺陷数。
代码评审的重要性
多数情况下,评审者能够发现开发人员自身不能发现的问题或潜在问题,毕竟思维方式和考虑的点等会有差异
- 优秀的评审者通过评审,不仅可以发现开发人员的不足,更可以通过开发人员的代码学到很多知识
- 对团队而言,通过评审以及互相评审,了解到其他团队成员负责的任务,必要时互相帮忙,互为后援,提高项目开发效率,降低项目风险
代码评审的规则
- 从逻辑上讲,本次修改是否符合需求,是否有类似的地方需要修改
- 可读性上,是否有足够的解释说明,以便以后维护
- 就代码规范而言,是否符合公司代码规范,以保持代码风格一致性
- 从代码性能上讲,是否有更有效的方案可以实现
- 单元测试(如果必要),测试用例是否能覆盖本次的修改
RTC 对代码评审的支持
作为目前主流的代码管理工具,RTC 对代码评审的功能已经有了很好的支持,比如利用邮件作为代码提交者与评审者通信的工具,代码评审过程中各个角色的划分,代码提交的权限设置等等,本节将具体介绍 RTC 在代码评审过程中所涉及的概念及详细配置。
对邮件的支持
在整个代码评审过程中,邮件是作为代码提交者及其他相关人员之间的重要通信工具,比如在代码评审前提交、对代码添加修改意见,团队相关人员都应收到相应的邮件提醒,用户可以通过如下配置是否启用邮件支持:
- 打开 Repository Connections 界面并连接
图 1. Repository 连接界面
- 打开用户编辑窗口,如图 2 所示:
图 2. Open My User Editor
- 找到 Mail Configuration 页面,进行相应的配置并保存,如图 3 所示:
图 3. 邮件配置界面
代码评审中所涉及的角色的划分
在整个代码评审过程中,RTC 将会涉及到如下几种角色
- Submitter:代码提交者,由实现新功能的开发者自己担任,可执行的操作有 Submit for review、Check-in,Deliver、Add Approver 等等。
- Review:代码审查人员,负责代码提交前细粒度的代码审查工作,排除潜在的缺陷,一般由团队中对所要修改的代码比较熟悉的人员担任。可执行的操作有 Add comment、Rejected、Approved 等。
- Approver:代码评阅者,负责代码提交前粗粒度的代码审查工作,一般由资深开发人员及 tech lead 担任,可执行的操作有 Add comments,Rejected、Approved 等。
- Verifier:功能的验证者,对功能的实现作一些单元测试等等。
事实上对于以上这些角色,Submitter,Reviewer 和 Approver 是必须,Verifier 是可选的,用户可以根据团队实际情况决定在代码评审过程中是否需要 Verifier。
代码提交前的权限控制
RTC 在代码提交时有了较好权限配置的支持,用户(一般由 Project owner 或团队的 tech lead 配置此权限)可以根据如下步骤进行配置:
- 连接自己所在的项目并打开,如图 4 所示:
图 4. 项目连接界面
- 切换到 Project Area 中的 Process Configuration 页面,如图 5 所示:
图 5. 流程配置界面
- 双击 Team Configuration 中的 Operation Behavior 选项,如图 6 所示:
图 6. 操作行为界面
- 从右边列表中选择 Source Control 中的 Deliver(server)选项,双击对应 Everyone(default) 图标,并双击 Add ... 按钮添加代码提交时的 Preconditions. 如图 7 所示:
图 7. Add Preconditions
- 在弹出的 Add Preconditions 对话框中选择 Require Work Item Approval 选项,如图 8 所示:
图 8. Add Preconditions 界面
- 双击 Required approvals 栏中 new ... 按钮添加代码提交时的 Required Approval,针对不同的 Approval 类型选择相应的 Approvers,单击 ok 按钮,最后保存所有配置。如图 9 所示:
图 9. 添加 Approval
经过上述一系列配置后,代码提交者必须先取得相应的 Approval 之后才能提交代码,从而达到代码提交时的权限控制,保证代码的质量。
RTC 代码评审使用示例
在 RTC 中,代码评审的流程大致如下,各个团队可以根据实际情况进行优化。
图 10. 代码评审时序图
下面我将以一个简单的实例来说明在 RTC 中是如何进行代码评审的:
- Check in 变更集
修改源代码,在 RTC 客户端中找到 Pending Changes 视图,并将这些变更集 check in 到在 Jazz repository 上的 workspace,如图 11 所示:
图 11. Check in 变更集界面
- 关联 work item
在 Pending Changes 视图中,将 check in 的变更集关联到相应的 work item(story 上的 task work item 或者是 issue 类型的 work item) 上。
图 12. 关联 work item 界面
- 提交代码给相应的 approver review
在 Pending Changes 视图中,找到相应的 Outgoing 变更集,点击右键菜单中的 Submit for Review... 选项。
图 13. Submit for Review 界面
- 添加注释和相应的 Approver
在弹出的 submit for review 的对话框中添加相应的注释及添加相应的 Approver 类型(具体类型请参考 RTC 中对代码评审章节)。
图 14. 添加注释和 Approver 对话框
- 确定需要评审代码关联的 work item
Approver 将会根据 RTC 中关于代码评审的邮件找到相应的 work item,并从 work item 中找到链接页面。
图 15. work item 链接界面
- 查找对应的变更集
Approver 从链接页面中找到需要评审的变更集,双击此变更集,变更集将会在 RTC 客户端的变更视图中显示。
图 16. 查看变更集界面
- 给出评审结果及意见
每个 Approver 根据代码评审的实际情况给出相应的修改意见和评审意见,如对于哪一行代码需要修改或者同意提交等等,具体操作如图 17 所示:
图 17. 代码评审界面
如果给出的评审结果为同意提交,则 submitter 直接进入代码提交阶段。如在此阶段给出的评审结果为拒绝,则 submitter 需要从 work item 的 overview 视图或 RTC 邮件中查看 Approver 添加的修改意见,并根据意见进行代码修改,重新提交代码评审。
- 代码提交
代码 Submitter 在 Pending Changes 视图中找到相应的 Outgoing 变更集并提交。
RTC 代码评审的注意事项
一次代码评审和所提交的一个变更集是一一对应的关系,当对一个变更集提交代码评审后,这个变更集就被冻结,此后对其中任何文件的修改都将通过另一新的变更集来跟踪。所以,对于新的修改,需要再次提交代码评审。
评审者在应用被评审者的变更集进行代码评审时,有时会和评审者本地的变更集产生冲突,此时只要将产生冲突的本地变更集暂停(Suspend),就能暂时避免冲突从而继续进行评审。
RTC 代码评审的不足及展望
虽然 RTC 已经能够支持完整的代码评审功能,但在实际使用中还有一些改进之处。比如无法动态嵌入或链接到评论所涉及的代码中的指定行,方便被评审者阅读修改意见。而且评审的粒度较大,基于每个评审者的修改意见无法针对每条评论进行接收或拒绝。此外,如果加入代码静态分析功能,就能更快的找到问题,避免人为的疏漏。
为什么很多看起来不是很复杂的网站比如 Facebook、淘宝,需要大量顶尖高手来开发?
就拿淘宝来说说,当作给新人一些科普。
先说你看到的页面上,最重要的几个:
【搜索商品】——这个功能,如果你有几千条商品,完全可以用select * from tableXX where title like %XX%这样的操作来搞定。但是——当你有10000000000(一百亿)条商品的时候,任何一个数据库都无法存放了,请问你怎么搜索?这里需要用到分 布式的数据存储方案,另外这个搜索也不可能直接从数据库里来取数据,必然要用到搜索引擎(简单来说搜索引擎更快)。好,能搜出商品了,是否大功告成可以啵 一个了呢?早着呢,谁家的商品出现在第一页?这里需要用到巨复杂的排序算法。要是再根据你的购买行为做一些个性化的推荐——这够一帮牛叉的算法工程师奋斗 终生了。
【商品详情】——就是搜索完毕,看到你感兴趣的,点击查看商品的页面,这个页面有商品的属性、详细描述、评价、卖家信息等等,这个页面的每天展示次数在 30亿以上,同样的道理,如果你做一个网站每天有10个人访问,你丝毫感觉不到服务器的压力,但是30亿,要解决的问题就多了去了。首先,这些请求不能直 接压到数据库上,任何单机或分布式的数据库,承受30亿每天的压力,都将崩溃到完全没有幸福感,这种情况下要用到的技术就是大规模的分布式缓存,所有的卖 家信息、评价信息、商品描述都是从缓存里面来取到的,甚至更加极致的一点“商品的浏览量”这个信息,每打开页面一次都要刷新,你猜能够从缓存里面来取吗? 淘宝做到了,整个商品的详情都在缓存里面。
【商品图片】——一个商品有5个图片,商品描述里面有更多图片,你猜淘宝有多少张图片要存储?100亿以上。这么多图片要是在你的硬盘里面,你怎么去查找 其中的一张?要是你的同学想拷贝你的图片,你需要他准备多少块硬盘?你需要配置多少大的带宽?你们的网卡是否能够承受?你需要多长时间拷贝给他?这样的规 模,很不幸市面上已经没有任何商业的解决方案,最终我们必须自己来开发一套存储系统,如果你听说过google的GFS,我们跟他类似,叫TFS。顺便说 一下,腾讯也有这样的一套,也叫TFS。
【广告系统】——淘宝上有很多广告,什么,你不知道?那说明我们的广告做的还不错,居然很多人不认为它是广告,卖家怎么出价去买淘宝的广告位?广告怎么展示?怎么查看广告效果?这又是一套算法精奇的系统。
【BOSS系统】——淘宝的工作人员怎么去管理这么庞大的一个系统,例如某时刻突然宣布某位作家的作品全部从淘宝消失,从数据库到搜索引擎到广告系统,里面的相关数据在几分钟内全部消失,这又需要一个牛叉的后台支撑系统。
【运维体系】——支持这么庞大的一个网站,你猜需要多少台服务器?几千台?那是零头。这么多服务器,上面部署什么操作系统,操作系统的内核能否优 化?Java虚拟机能否优化?通信模块有没有榨取性能的空间?软件怎么部署上去?出了问题怎么回滚?你装过操作系统吧,优化过吧,被360坑过没,崩溃过 没?这里面又有很多门道。
不再多写了,除了上面提到的这些,还有很多很多需要做的技术,当然并不是这些东西有多么高不可攀,任何复杂的庞大的东西都是从小到大做起来的,里面需要牛叉到不行的大犇,也需要充满好奇心的菜鸟,最后这一句,你当我是别有用心好了。
功能上面虽然不复杂,但是要完成的细节却很多. 比如news feed里面的推荐算法就很重要,要根据用户之前的记录和与好友的关系来生成. 另外就是根据用户的信息和行为,要做机器学习和数据挖掘,从而来挑出最匹配的广告.这也是比较花人力的事情.
另外Facebook的用户量奇大无比. 假设你只是做一个学校内部用的社交网站, 那肯定很简单. 但是如果考虑到上亿人在上面用. 你首先服务器就必 须是一个分布式的机群,还要保证能抗住那么大的流量. 同时为了性能够好,不得不加上mem cache和网页分块加载等功能. 还有就是每天用户产生的总数据量(状态,留言,照片,分享等)有TB的数量级,你数据库是否撑住等等.
另外树大招风,你要一个很强的安全小组来保证网站在受攻击的时候能防御好,还有要防止垃圾信息和恶心广告或者程序的散播. 另外还有为了全球化而带来的多语言问题.
总之,一个网站做大了之后,很多问题就会产生,不是在校园里面做一个学期作业那么简单.狼大人,休,行。
某个历史上的大神曾经说过一句话:
要判断一个算法的好坏,只要给它足够的数据。
当用户、数据和系统规模上到一个程度之后,所有曾经可以忽视的问题都会变得必须用从来不可想象的精力和技术去解决。
来来来 看看这个 刚看到的《当用户点击“举报”后,Facebook在后台会做哪些事情》
很多东西并不是表面看到的那样简单
身为前端攻城师,就这方面说一下这样一个Facebook看起来“很简单的网站”需要顶尖高手来开发和维护
写前端程序要考虑很多,如下:可维护性,JS的执行高效性,JS文件的大小,用户体验等等
1. 可维护性
并不是所有人写的程序都具有可维护性,清晰易懂的,这个区别在刚接触编程和高手直接的差异体现的特别明显
2. JS的执行高效性
一个网页加载JS并执行,浏览器执行并渲染了半天还在渲染,相信很多用户都不想看到吧?非常上海用户体验。
如何提升JS的执行速度呢?相信我,初学者大部分都是不知道的(排除写过浏览器内核的同学),了解浏览器如何执行JS,如何渲染DOM能帮助开发者提升执行速度
3. JS文件的大小
JS文件或者HTML或者CSS文件过大,有很多缺点
第一,受网速影响,文件大,加载速度慢
第二,Facebook的用户量非常巨大,每个人访问就算多加载1KB(即使有cache,第一次总需要加载吧),可想而知,这个流量非常巨大,流量都是要钱的啊
4. 用户体验
略之
高手往往比非高手要注意的东西要多很多,这点相信大家不会质疑吧,只是就前端方面发表一些建议
如果要把一件简单的事情搞复杂,你需要的是市场总监
如果要把一件简单的事情搞简单,你需要的是产品经理
如果要把一件复杂的事情搞复杂,你需要的是一堆码农
如果要把一件复杂的事情搞简单,你需要的是顶尖高手
明白了吧,顶尖高手的意义就在于让你觉得这个东西看起来很简单。
学“懂”计算机系统结构之后,理解这个问题比较容易点吧。
比如,你打开知乎,简单的敲下几行字,点击提交,然后你看到了你的评论,这复杂吗?不复杂。
1、为什么知乎要用浏览器才能打开呢,记事本不能访问知乎?为什么用输入自己的知乎用户名和密码才能访问呢,我QQ密码为嘛不能用?为什么我只能看到我关注内容,而不是网站所有用户的所有内容呢?
2、当敲下键盘时,电脑是如何识别按下的具体哪个字符呢?是如何经过到达的CPU呢?CPU进行了如何的处理操作呢?显示器为什么可以显示相应的字符呢?
3、当点击“提交”时,发生哪些变化呢?显示的内容是保存了在本地电脑上了,还是保存在了知乎服务器上了呢?从本地的数据是如何传输到知乎服务器呢?从物 理层、数据链路层、网络层、传输层、会话层、表示层、应用层这一系列的过程提交的评论内容传输形式是经过一系列的如何变化过程呢?
PS.对于一个字符从输入到最后结果输出的处理流程我也没搞彻底清楚。随便说说。。。希望有高手能具体解释下啊。

手上没有网站的结构层次示意图,随便拿张图说明下原因吧。像计算机最初问世的时候,操作计算机的用户既是设计者也是维护者的时代已经过去。每个节点都应该 是一个属于一个节点的专属内容,对个每个节点都应该是更清晰化更简单化的:用户的操作的应该简单化,网络的传输应该简单化,数据的存储也应该是简单化。因 此对于用户来说只需要用户界面操作就足够了,没必要把数据库之类的东西也交给用户处理的。
TEAMLEAD这部分指任务分配
- PROJECT AREA
根据计划来,不同的计划建立不同的PROJECT AREA。
- TIME LINE FOR PROJECT AREA
定义起尺和结束时间,也指一组ITERATION和TEAM AREA的组合。
一个PROJECT AREA可以搞几个TIME LINE。
- ITERATION FOR TIME LINE
一个TIME LINE可以分若干个ITERATION阶段去完成。
- TEAM AREA FOR TIME LINE
这段时间的TIME LINE的PROJECT 是需要人来完成,先定义TEAM AREA。就是USER的组合。
- USER FOR TEAM AREA
就是TEAM AREA的组织成员。
- CATEGROY FOR TEAM AREA
CATEGORY就是WORK ITEM的类型,但要和TEAM AREA关联。
- PLAN FOR ITERATION
在上面的时间段ITERATION增加PLAN,也是一组WORK ITEM的组合。
- WORK ITEM FOR ITERATION,USER
工作内容,父类是ITERATION,USER等。
上面的这八项的建立顺序是从前到后,只有前面建立了,才能建后面的。
如何与SOURCE CONTROL结合?每次提交代码的时候,要指定CHANGE SET,CHANGE SET的名字取WORK ITEM的名字,这样就可以关联上了。