版本发布:
软件部门的产品版本作为可以直接部署到设备上的文件集合,根据项目进度进行周期性地演进,当项目经理判断到达一个产品稳定状态,会发布ReleaseNote给各相关人员,该ReleaseNote包含了以下几点内容:
- 主文件:可能是安装包或压缩包,作为版本部署的主体。
- 支撑工具:版本得以部署使用的附属文件,比如界面、数据库等。
- 用户手册:产品的用户使用手册,描述了产品部署、配置、使用、维护、常见问题指南等信息。
- 配置文件:产品得以部署生效的默认配置文件集合及详细说明,实际上是作为用户手册配置部分的专门拓展。根据产品应用场景可能会有多组配置文件集合。
以上几点是提供给用户和内部人员的,均包含了各自的版本号和地址信息。
- 模块版本信息:软件部门内部会将构建主文件的多个模块分别维护,各模块有自己的版本号并区别于主文件版本号
- 调试命令手册:供内部运维人员处理产品现场问题使用的命令手册,包含了版本号和地址信息
- 主要特性列表:版本功能简要说明,并罗列了主要的特性,并强调了该版本中新发布的特性(该新特性在后续版本ReleaseNote中会因为重要性不够而不再说明)
- 发布的问题单列表:版本包含变更的全部说明,以问题单的形式罗列(即所有的特性/缺陷/优化都以问题单的形式进行描述)
- 通过的回归测试和结果:版本回归通过的系统测试及测试结果的详细描述(因为版本之间的变更程度差异巨大,考虑系统测试的实施成本,需要描述清所选取的回归测试用例集;而且随着版本的演进,回归用例集本身也在不断演进)
- 相关分支:版本发布后用于软件研发部门进行后续工作的分支名和地址(具体在“分支系统”一节进行描述)
- 遗留缺陷列表:版本包含的遗留缺陷,一般是性能或可靠性方面的难以解决,并且不会导致版本无法使用的缺陷。如果在后续版本中没有解决,将一直积累记录到后续版本中。
以上几点仅仅是提供给内部人员的。
分支系统:
- tag分支:在版本发布过程中创建,是该产品版本对应的代码分支。基于上一版本test分支演进到某一个稳定的Revision创建,产生后的初始Revision被称为预发布版本。预发布版本是版本发布过程进行回归系统测试的对象。严格来说回归测试中遇到的新的缺陷,被称为版本发布异常,有些异常能够解决使得该分支有修改提交(进一步fix或回退掉异常引入的修改),而有些异常无法解决将被加入遗留缺陷列表(严重的会暂停版本发布)。理想情况下,tag分支创建后是不会再有什么和产品内容相关的变更提交。
- test分支:该分支在版本发布完成之后由tag分支创建,它是下一个新版本功能构建的原型。原则上所有和接口/系统/平台等跨模块全局性的变更在经过开发阶段之后都会Merge入该分支;而各模块版本在发布后也会第一时间合入到该分支。test分支的核心意义是针对挂机测试,挂机测试是利用每天夜晚和假期来长时间地运行系统并进行各种相关测试。挂机测试的对象即是test分支上的各个稳定revision,原则上讲新的产品版本的代码变更都会在test分支上预先经过或长或短的挂机测试,在一定程度上以保证代码演进的可靠性。在tag分支创建后,因为预发布版本可能会经历一定时间的“版本发布异常解决”阶段,所以这段时间内日常的开发工作仍然可以在该test分支上继续进行,只是不再进入当前的待发布版本;等到预发布版本被正式发布之后创建了新的test分支,再把这个阶段的修改依次合入新的test分支。
- trunk分支:trunk分支是一直存在的,是产品唯一的演进分支。除了最初始阶段,后续演进不会基于该分支创建分支,也不会进行直接的代码提交或测试版本构建,所以该分支实际上起到的是一个记录产品演进的文档作用。每当版本发布完成后,都需要从该版本的test分支的日常演进以及tag分支的发布异常处理中,选择合适的revisions进行merge到trunk分支(这里合适是指不考虑那些提交又回退的修改或临时性debug修改),并标记正式版本基线。为确保该合入工作不发生遗漏或错误的合入,因此在认为合入完成时应该与正式发布版本的tag分支代码进行比较,确定合入的正确性。
- 模块trunk分支:将系统划分为多个模块,每个模块维护自己相关的代码,并具备独立的主干分支。该分支的核心意义是针对模块测试,因此模块测试框架以及模块测试所有用例的代码,都在模块主干分支上进行维护,故随着模块演进模块主干分支将因为测试用例的逐渐增长而变得越来越臃肿。当模块主干分支演进到某个稳定的revision,模块负责人可以根据项目需要决定发布模块版本,将模块代码Merge入test分支,但模块测试用例是不合入的。(在模块一节将会进行更深入讨论)
- 模块开发分支:针对的是模块内部的重要变更,当该变更在分支上最终完成了实现和模块测试,会直接合入模块trunk分支。原则上由模块负责人来判断是否要针对某个变更来创建模块开发分支。
- 系统开发分支:针对的是跨模块系统全局的重要变更,一般是基于tag分支或test分支上某个稳定的revision来创建。原则上任何涉及多模块协作的问题,要么非常简单可以直接提交到test分支,否则都需要创建系统开发分支。在该工作项的开发过程中,原则上还需要将已完成的代码实现,合入模块trunk分支或模块开发分支进一步补充模块测试用例验证,当模块测试发现的细节缺陷或优化,可以回过来补充提交到系统开发分支。当该变更在系统开发分支上最终完成了系统测试和模块测试,会直接合入test分支进行后续的挂机测试。这里需要注意一个问题:该变更必须先从test分支合入,而不能以模块版本的形式先从模块分支合入;这是因为先提交该变更后提交包含该变更的模块版本,回退该工作项的提交不会影响模块版本中包含的其他修改。
为使这些分支良好运作,需要制定版本号管理方法。一些重要内涵包括:能够在版本中加入体现版本号信息的标签代码,作为各分支上的稳定Revision的提交标记;产品支撑工具能够提供有效手段来查询产品版本号,而不是简单依靠比如版本文件名来进行形式上的区分;版本号的命名规则在各个分支上有清晰的区分,即能够通过版本号内容直接判断出来自于哪个tag/test/开发分支。严格执行的版本号管理方法,能够使得从研发部门交付给系统测试部门甚至客户的产品版本,都有迹可循并可以重演;这种方法同样对研发人员在开发分支上的代码提交提出了一定要求,研发人员不能在开发分支上随意地提交代码和发布“尝试性”的版本。
模块
从直观意义上来看,划分模块是为了对高层进行抽象,使得高层设计者仅需关注产品整体的概念完整性;另一方面也是为了互相隐藏模块内部的细节,使得模块内部的研发人员只需要关注模块本身的功能细节,提升工作效率。这是划分模块最基础的出发点,但在具体实施中,模块并不仅仅是产品源代码结构中的一个文件夹而已。
从上一节分支系统中提及的模块主干分支来看,模块已经可以有别于产品而进行独立演进。该独立演进的重要前提是模块代码的独立运行,否则仅仅是模块代码的独立编译是没有意义的,所以关键问题即是模块在辅助机器/环境上的运行。辅助机器/环境有别于目标机器/环境,它的本质是其硬件资源是充裕的,比如linux或windows办公PC。当模块代码能够在辅助机器上独立运行之后,进一步针对模块代码就能够构建并维护一套模块测试框架/环境,该框架负责对模块代码的内聚功能进行验证,或者对一些性能点进行仿真分析。以下是模块在辅助机器/环境上实施需要注意的几点:
- 模块代码在辅助机器上的独立运行是一个重要过程,可能涉及到平台中间层的构建或仿真(难点),模块间接口的规范化,以及一些模块间依赖的外部函数的打桩等内容。
- 模块测试用例回归的搭建也是一项重要内容,可能涉及到用例的批量自动执行、模块状态复位、日志的按用例存储、运行结果统计和汇报、模块异常重启等要点。
- 模块回归的修复
当模块及其分支能够正常运作之后,以下是日常工作需要注意的一些细节:
- 辅助机器和目标机器的编译去warning/pclint检查
- 模块测试回归:模块测试回归能够确保模块的演进不会引入新的问题,不会捡了芝麻丢了西瓜。另外与挂机测试相对的,辅助机器/环境的夜间/假期的回归测试也能够在一定程度上保证代码的可靠性。
- 模块版本发布:
- 代码覆盖率:测试用例的持续补充
问题单系统:
问题单的题目原则是简短和精确,因为问题单是描述版本变更的重要工具。
- 原则:只要是修改及可能修改产品代码的缺陷、优化、新特性,都要提单;有些修改是跨模块的,那么就需要每个模块都分别提单,并且另提一个总的单子
- 问题单内容介绍:缺陷、优化、新特性
- 调研结果,会议纪要,接口纪要,文档链接,备忘录
- 状态变迁
- 重要问题单的历史记录
系统测试
(注意区别于界面测试):
- 场景设计:开发主导,测试把关
- 用例设计:测试主导,开发给予帮助
- 回归用例的选取:研发关注覆盖,测试关注成本
- 测试文档的管理
开发阶段和文档
- 设计:为什么需要设计文档?设计文档的编写过程是作者深入思考子系统实现方案的过程;仅仅在稿纸上随手写画,而直接进行细粒度的伪代码编写很可能带来返工。设计文档给予同事一个检视的媒介,设计检视必须严格把关。文档的粒度(因为设计变更是经常现象,所以没有必要精细到伪代码级)
- 编码:编码的检视重要性不及设计检视,因为枯燥而且耗资源。可以由作者或组长根据经验或实际情况选择部分重要内容进行集体检视,如果资源充分,交叉检视还是必要的。
- 模块测试:是对编码质量的保证
- 特性开发:比较重要的特性才需要用独立的特性文档描述,否则采用问题单的形式记录即可。设计原因,方案描述,接口变更。
接口管理:
配置管理:
- 配置文件与商用场景的表格
- 配置文件检查脚本
该流程复制的技术关键点:
- 有力的操作系统封装(使得模块测试能够在便捷的辅助机器而不是目标机器上运行)
- 模块测试驱动的构建和自动化执行,模块测试脚本抵御变更的能力(使用XML)
- 版本的自动编译、构建、发布
其他技术关键点:
- 构建早期的性能原型系统
- 概念完整性
- 从用户角度出发去做设计
- 挂机测试的实现和数据分析
- 抵御变化的能力