前言
最近参与的项目代码托管是用github,用下来感觉和我平时使用的svn还是有些不同的,一直在构思和摸索PLM项目中使用版本管理软件来管理代码的开发流程,借此机会细化总结一下。
问题
PLM项目在实施过程中,开发团队常常被诟病为小作坊,没有开发流程,没有代码版本管理,或者有代码管理但仅用于归档。
这是由于PLM项目性质决定的,开发占比比较少,辅助为主,且多为二次开发,功能相对比较独立,我参与过的的项目有一个开发工程师,兼项目经理、业务顾问、实施的小项目,也有十几个开发的大项目,在大多数项目配置中,开发也就一两个且还不一定在现场,所以开发过程中也不是迫切需要代码管理及开发流程规范,往往是在后期项目上线及运维升级时候,才暴露出未对代码版本管理及开发流程规范的弊端,比如如下这些情况:
1.代码冲突
多人并行开发合包时候库文件版本、工具类等冲突。
2.代码冗余
各自维护的工程及工具类,到最终合包时候工具类中很多重复相似的方法,但已经到后期,不太愿意安排额外的时间去做代码重构整合重新测试了。
3.版本不好追述
比如代码回撤,如果未做代码物理备份及变更记录,将变的很困难,经历过的有些客户,代码只能在企业内网编写,且内网并没有版本管理软件,代码在开发和运维时候,我为了避免代码版本出现问题,对开发团队采用了代码物理备份的开发流程规范,修改代码前先对最新代码做一次备份,在记录文件中记录签出签入的人、时间、原因及改动的代码文件清单,为了避免出现问题,大家都尽量避免对未签入的代码做再次签出修改,好在平时协同开发运维的场景比较少,团队也严格遵守这个流程,未出现过代码版本问题。
4.生产环境和代码不匹配
因为没有开发流程,随着上线后的运维及人员流动交接,最终的结果往往就是最新代码和生产环境的部署包匹配不上,java代码还可以通过反编译出生产代码来和当前最新代码对对比,c代码就比较困难了,只能通过梳理功能重新开发来恢复代码,给运维及升级带来额外工作量和风险。
5.代码丢失风险
如果没有很好的代码本地及异地备份机制,可能会出现辛苦写的代码不小心丢失了的情况,经历过磁盘或者虚拟机坏掉的同学一定感同身受。
解决
平时我们实施项目时候需要帮客户梳理业务流程,然后在PLM软件上面落地,其实我们开发团队也需要根据情况梳理出一个开发流程,然后在svn或者git这些版本控制软件上落地。
我的团队使用的是学习成本比较低的svn,从使用svn的4年期间,总共在svn上管理了26家客户的37个大大小小的项目代码,不断总结实践,总结了基于svn的PLM项目特色开发流程(svn中相关概念可以参照“关于svn”章节)。我们使用的开发流程和规则(图1,后面“项目案例”章节将结合该开发流程介绍我在上汽大通项目PLM项目开发及运维过程中实战案例):
1.trunk:主干,用于维护和生产环境一致的代码
2.branches:分支,每个项目开发时候对应一个分支
3.tags:标签,快照,每个项目最终上线部署后,代码(分支基于主干合并后的代码)对应一个tags
4.项目及日常bug修复开发流程如下:
4.1.开发经理基于当前trunk创建branches
4.2.给branches分配开发工程师和权限,并通知开发工程师
4.3.开发工程师将branches签出到本地进行开发
4.4.开发工程师定期同步branches中代码到本地(一般每天工作开始时候),定期提交代码到branches(代码到一定成熟度时候,建议每天下班时候)
4.5.开发经理定期同步trunk中最新代码到branches中(一般是有其它项目上线或者运维修复bug上线后)
4.6.功能测试时候基于branches代码编译发布
4.7.最终功能上线时,开发经理\开发工程师合并branches代码到trunk,并编译快速测试,发布tag
5.紧急修复开发流程如下:
其它步骤和项目和常规修复bug一样,区别在,不需要创建branches,直接签出trunk到本地修复bug测试通过后直接提交到trunk发布

图1:PLM项目基于svn的开发流程
关于svn
svn有一个很标准的目录结构,是这样的。比如项目是proj,svn地址为svn://proj/,那么标准的svn布局是 :

图2:标注svn的目录结构
这是一个标准的布局,trunk为主开发目录,branches为分支开发目录,tags为tag存档目录(不允许修改)。但是具体这几个目录应该如何使用,svn并没有明确的规范,更多的还是用户自己的习惯。
svn各个目录含义
trunk:主干,如果说把一个软件项目从开始到消亡比作一个故事的话,主线情节都在这里被svn记录着。
branches:分支,有很多种用法,比如:版本发布维护分支、新特性开发分支,甚至是缺陷修复分支等等。
tags:标签,或者叫快照,某个版本发布时候,都在这里留档。
示例如图:

图3:标准svn目录结构
使用svn开发流程可以分成集中式和分散式两种:
集中式:trunk进行主要开发
一般的,我们的所有的开发都是基于trunk进行开发,当一个版本/release开发告一段落(开发、测试、文档、制作安装程序、打包等)结束后,代码处于冻结状态(人为规定,可以通过hook来进行管理)。此时应该基于当前冻结的代码库,打tag。当下一个版本/阶段的开发任务开始,继续在trunk进行开发。
此时,如果发现了上一个已发行版本(Released Version)有一些bug,或者一些很急迫的功能要求,而正在开发的版本(Developing Version)无法满足时间要求,这时候就需要在上一个版本上进行修改了。应该基于发行版对应的tag,做相应的分支(branch)进行开发。
这是一种很标准的开发模式,很多的公司都是采用这种模式进行开发的。trunk永远是开发的主要目录。
分散式:分支进行主要开发
这种开发模式当中,trunk是不承担具体开发任务的,主要承担版本发布,一个版本/阶段的开发任务在开始的时候,根据已经release的版本做新的开发分支,并且基于这个分支进行开发。
这其实是一种分散式的开发,当各个部分相对独立一些(功能性的),可以开多个dev的分支进行开发,这样各人/组都不会相互影响。比如dev_2.0_search和dev_2.0_cache等。但是这样merge起来就是一个很痛苦的事情。
所以,合包时候选择性的merge,是可以当2.0开发结束后一起把dev_1.0(bugfix用)和dev_2.0(新版本开发用)merge回trunk。或者先把dev_1.0 merge到dev_2.0,进行测试等之后再merge回trunk。
这两种方法各有利弊,第一种方法是可以得到一个比较纯的开发分支,而第二种方法则更加的保险,因为要测试嘛。
多人协作时,合包是最经常出问题的地方,严重的甚至会导致代码被覆盖回滚情况,其原因在于分支管理者创建分支后不再或长时间从主干拉回数据,导致最终合并回主干时分支的文件甚至结构都与主干有较大差别,产生较多冲突。需要人手解决,浪费了很多时间。
针对这个问题,是否有一种方案可以在分支提交时即检测该分支最后一次合并的版本是否与主干版本相符,如果不符则不允许提交,强制要求大家养成从主干拉数据的习惯呢?如果可以实现,那么在分支合并回主干时将几乎可以消灭掉冲突。
两种方法的优缺点
第一种开发模式(trunk进行主要开发,集中式):
优点:管理简单。
缺点:当开发的模块比较多,开发人数/小团队比较多的时候,很容易产生冲突而影响对方的开发。因为所有的改动都有可能触碰对方的改动。
第二种开发模式(分支进行主要开发,分散式):
优点:各自开发独立,不容易相互影响。
缺点:管理复杂,合包merge的时候很麻烦,容易死人。
项目案例
下面我将结合一个比较复杂的项目场景介绍下开发流程的实战,该案例跨度有一年左右,加上日常系统运维,算是同一个客户的7个项目并行开发,我身为开发经理,借用上面总结的PLM项目中的开发流程避免了很多坑。
首先介绍下案例情况,客户是上汽大通,项目主干线是从Teamcenter8.3升级到Teamcenter11.3,升级过程中并行了6个项目开发,总共投入了9个开发工程师,角色和项目情况如图4,从表中可以看出来有5个是多个开发协同项目,且有4个由于部分开发不使用svn导致代码不能全部用svn管理,会多出额外的代码比对合并工作量。

图4:开发、角色、是否使用版本管理软件及项目矩阵表
该案例我使用的开发流程如下,主要加入了不使用svn开发的代码处理:
1.trunk:主干,用于维护和生产环境一致的代码
2.branches:分支,每个项目开发时候对应一个分支
3.tags:标签,快照,每个项目最终上线部署后,代码(分支基于主干合并后的代码)对应一个tags
4.项目及日常bug修复开发流程如下:
4.1.开发经理基于当前trunk创建branches
4.2.给branches分配开发工程师和权限,并通知开发工程师
4.3开发工程师将branches签出到本地进行开发
4.4.对于不使用svn的开发,需要开发经理下载最新代码后,离线发送
4.5.开发工程师定期同步branches中代码到本地(一般每天工作开始时候),定期提交代码到branches(代码到一定成熟度时候,建议每天下班时候)
4.6.对于不使用svn的开发,需要开发经理定期接收代码和trunk代码做线下对比,并和开发确定修改内容后合并到trunk
4.7.开发经理定期同步trunk中最新代码到branches中(一般是有其它项目上线或者运维修复bug上线后)
4.8.功能测试时候基于branches代码编译发布
4.9.最终功能上线时,开发经理\开发工程师合并branches代码到trunk,并编译快速测试,发布tag
5.紧急修复开发流程如下:
其它步骤和项目和常规修复bug一样,区别在,不需要创建branches,直接签出trunk到本地修复bug测试通过后直接提交到trunk发布。
这套开发流程使用下来,虽然开发经理每次合包merge时候都要对比代码很是麻烦,但好在稳当可靠没出现重大的代码版本错误,还通过日常review代码时候避免了一次事故(不使用svn代码的开发后来开始使用svn,提交代码前未从trunk同步最新代码,导致将本地老代码提交到了trunk中),我在日常review代码时候及时发现了做了代码回撤。
总结
整体上使用版本管理PLM项目代码,优点多于缺点,如果你的开发团队没有使用,强烈建议使用。





