典型问题及最佳解方案 ======================= 这里收录我遇到的或者朋友遇到的软件工程中配置管理相关的问题,其中大多是管理问题,有些是技术问题和管理问题交织在一起。 我写的源代码不见了 ----------------------------- 开发过程中的代码不见了 * 修改代码导致正确代码被覆盖或删除,很多开发人员会遇到这类问题,编写代码时进行验证,并在功能全部完成之 后再提交代码。 例如大约2008年的一个项目,我负责安装及卸载程序的开发,该程序需要卸载之后删除自己生成的文件。 在我已经写了将近一周左右的代码时,我进行测试验证,这时卸载程序把开发代码自动删除了。 * 硬盘物理故障,计算机的硬盘在到了一定工作年限后,故障率会上升。 例如,大约在2012年的项目,是一个android嵌入式系统项目,大约有近百名研发人员,研发服务器为ubuntu10.4, 提供每个研发人员有一个共享目录,供编译代码使用,大多数研发人员将个人共享空间映射为pc的一个分区, 然后将代码下载到这个分区中使用SourceInsight进行编辑,然后ssh登陆到服务器上进行编译验证。 某一天研发编译服务器的硬盘出现故障,导致硬盘数据全部丢失,这时很多研发人员开发了很多天的代码都找不回来了。 如何避免以上类似问题: * 传统的方法是复制多个版本来保存,例如我一个同事,会定期的备份版本到另外一个磁盘中,但只能防止自己的误修改被覆盖或删除, 不能解决自己工作机硬件故障的问题。 * 另外一个方法是代码及时提交。每天提交代码。这种情况在多个研发人员同时开发时,会相互影响。 * 最佳方法,提供私有的工作空间(CWS), 即通过svn创建一个分支来提交代码,这样这个分支由研发人员单独控制,按需提交,即解决了代码保存的问题, 也不影响到其他研发人员的开发。 上上一个项目的最终代码找不见了 ------------------------------- 遇到情况: * 上上一个项目的最终代码找不见了,是两年前的项目。 * 线上遇到了问题,代码版本很多,无法确定对应线上版本的代码。 原因: * 或许是硬盘故障导致代码全部丢失。 * 或许是项目结束时未创建基线,导致分不清最终版本代码。 如何避免: * 至少结项时或移交时创建基线,并刻盘永久保存,一般项目的每一个阶段均需形成基线。 * 需要建立产品库,交付时以产品库中的版本进行交付,产品交付时记录,并保存一个唯一的版本号,项目最终代码及资料刻盘保存。 * 代码进行版本编号,形成产品时均需唯一编号。另外在进行产品编译时,需要在二进制文件中内置一个版本号,这样就能区别线上版本。 配置管理的开源软件subversion采用了版本编号,编译时间,代码库号三个维度来区分版本,这可以保证每次发布都是唯一的版本。 而且每个人的每次编译都会不同,其中版本编号就是在svn_version.h文件中定义版本编号和代码SVN号, 其中版本编号又采用三个以点分割的数字表示。分别为SVN_VER_MAJOR(大版本号), SVN_VER_MINOR(小版本号), SVN_VER_PATCH(补丁编号)。 编译时间通过编译宏定义__DATE__, __TIME__来实现,其中__DATE__表示编译日期,__TIME__表示当天的具体时间。 例如我们输入 svn --version 会有以下输出: :: $ svn --version svn, version 1.9.7 (r1800392) compiled Mar 28 2018, 08:49:13 on x86_64-pc-linux-gnu $ svn --version svn, version 1.9.7 (r1800392) compiled Mar 28 2018, 08:49:13 on x86_64-pc-linux-gnu Copyright (C) 2017 The Apache Software Foundation. This software consists of contributions made by many people; see the NOTICE file for more information. Subversion is open source software, see http://subversion.apache.org/ The following repository access (RA) modules are available: * ra_svn : Module for accessing a repository using the svn network protocol. - with Cyrus SASL authentication - handles 'svn' scheme * ra_local : Module for accessing a repository on local disk. - handles 'file' scheme * ra_serf : Module for accessing a repository via WebDAV protocol using serf. - using serf 1.3.9 (compiled with 1.3.9) - handles 'http' scheme - handles 'https' scheme The following authentication credential caches are available: * Plaintext cache in /home/zhang/.subversion * Gnome Keyring * GPG-Agent * KWallet (KDE) 有的Bug忘了改 ------------------ 有的Bug忘了改,到了最终交付截止日期发现了几个必须修改bug还没有提交。 解决方法:项目资源时有限的,有限的资源应当投入到最重要的工作中 1,bug划分优先级,优先分配人力来解决最重要的bug. 2,所有问题均统一跟踪,提交到缺陷管理系统中(Jira或Bugzilla),并分配到人。 3,将问题划分为子任务或child issue。这样只需跟踪parent issue。 改了的BUG在新版本上还存在 ----------------------------- * 代码合并失误导致代码未提交到最新版本,例如提交到1.1,未提交到1.2 。 * 张三使用旧版本开发,覆盖了李四的代码。 解决方法: * 采用同一个代码库,减少可能代码合并的问题。例如如果研发和基线采用两个svn库,在合并时就不能使用svn merge来进行合并 * BUG修改需指明修改的版本。 * 分支策略明确,BUG修改代码均需合并新版本上。 * 采用基线代码开发,分支仅可能的晚创建,这样就会减少合并冲突的次数。 测试发现的Bug程序员那里看不到 ----------------------------- 现象: 测试发现的Bug程序员那里看不到。 可能原因: * 集成的编译链接环境与步骤与开发不同。 * 测试环境与开发调试环境不同。 解决方法: * 统一编译环境,测试环境。 编译脚本和启动脚本也属于配置项,也需提交到代码库中。 * 一键编译,例如维护一个自动构建系统,例如openoffice开源社区使用buildbot来实现自动编译。 曾经加入一个项目,项目采用开源软件实现,有多个模块,每次编译时均需每个模块单独编译,这样每个程序员在开始研发时均需按照文档 来逐个编译,而且还会遇到误操作等编译不过的问题,后来我花费时间写出编译脚本,以后就很少出现类似的编译问题,也提高了工作效率。 同一个Bug,多个版本来回改(相似的内容重复开发) ----------------------------------------------- 适当的分支策略-将变更集独立,生成patch,便于修改集成, 例如layer7-包过滤功能采用patch方式进行发布, 在内核发新版本时如果需要该功能,只需使用patch命令将改补丁打入即可,不用手工进行合并代码。 不建议维护多个产品版本。例如VisualBox社区仅同时维护两个版本,一个主线版本用于新功能开发,一个产品版本用于fix bug. * 使用分支来支持历史版本和功能特性版本。 * 产品划分功能组件。即通用功能划分为组件,单独开发,供项目组共用。 集成瓶颈 --------- 现象: * 集成经常加班,瓶颈在集成。 曾经一个项目使用winmerge进行代码合并,团队大约有30余人,研发总监亲自来合并代码,研发人员将代码邮件发个研发总监。 研发总监进行winmerge比较,然后进行代码合并。研发人员平均每周均有代码提交,这样研发总监平均每天进行好几次的代码合并, 每次合并均需重新编译代码验证,每次整体全部编译大约7小时,研发总监配置最好的笔记本进行合并及编译验证,每天晚上 带到家里进行工作。这个项目采用非常原始的方法,非常辛苦还不能保证软件质量。 问题根源及解决办法: * 使用自动的合并工具,例如使用diff/patch或svn merge来代替简单的winmerge合并。只有发生冲突时时才需集成人员介入。 * 另外需要提交的源代码符合质量标准,代码需要基于基线进行开发。 * 是否经常集成,是否是多重集成,如果单人集成不能满足要求,可以分组集成,分模块集成,集成通过后再进行总集成。 * Build是否是自动的,是否足够快(提高机器配置),笔记本毕竟配置较低,后来采用服务器来编译,整体编译时间只需大约4小时。 非发布版本可以采用增量编译。 * 防止维护过多个分支。一般集成维护两个分支,一个开发分支,负责新功能开发;一个产品分支,功能完成之后的维护修改bug。 足够的人力资源来用于配置管理和集成。如果很多分支就需要多人来进行维护。 本地改动的第三方源代码无法升级或升级困难 ----------------------------------------- 遇到情况: * 自己对开源代码的改动经过一段时间无法分清是自己增加,还是开源本身原有的代码。 * 第三方升级时,自己跟着升级非常困难。 解决方法:将第三方代码单独建立vendor分支进行管理。每一个第三方代码修改均提交在这里,自己如果使用到再拷贝到相应位置。 如果要修改,在自己的目录进行修改。 效果: * 可以重现第三方代码的先前版本。 * 可以了解自己团队对第三方代码做过的修改。 * 合并开源的新版本非常快。 两地开发,没法控制版本 --------------------------- 两地开发,没法控制版本。 * 经常同步和集成,以一地为中心,创建代码库,另外一地建立代码镜像库,方便读取。提交时均提交到主库中。 * 采用分布式版本控制工具。 * 适当分工,同一模块由位于同一地点的团队负责。 曾经一个项目,某公司整体均设在北京,为了开拓市场及降低研发成本需要,创建了新的跨地域的研发团队(成都研发中心),北京研发中心定位 为设计,即每一个功能根据需求形成设计文档,成都研发团队负责根据北京研发团队的设计文档编写代码,最后以失败为结束。 因为设计和编写代码之间的界限不明确。 还有一个公司,部门划分为,架构,设计,开发及实现,集成四个部门,最终也是以失败告终,设计部门的设计依赖于编写代码才能完成, 最终为设计写完代码验证正确,才交给开发。开发部门的代码直接提交给集成部门,架构部门的架构规划并未得到保证。 典型的团队划分以功能模块来划分,或者以产品,研发,测试来划分比较合理和高效。 git分支代码找不见了 ------------------------ 遇到的情况: git库的某功能分支代码找不见了,该分支从未被合并过,开发人员也离职了,能否通过技术手段找回来。 解决方法: * 这种情况如果已经删除分支,分支将会被git回收,代码是找不回来的,因此只能采用管理方法以后避免这种情况。 * 功能分解尽可能较小,以便代码可以尽快合并到主干。 * 优化分支合并策略,将有用的代码均被及时合并,即时现有版本不使用,也可通过功能开关将其关闭,但代码需要集成到主干。 * 工作交接问题,交接应当明确交接内容,接收人应当进行基本的验证工作。 知识点: * Git和subversion 的存储机制不一样,subversion 只要提交了,则数据永远在服务器保存,而 Git 删除了的分支,没用的commit id会被回收, 即该数据被释放。