典型问题及最佳解方案

这里收录我遇到的或者朋友遇到的软件工程中配置管理相关的问题,其中大多是管理问题,有些是技术问题和管理问题交织在一起。

我写的源代码不见了

开发过程中的代码不见了

  • 修改代码导致正确代码被覆盖或删除,很多开发人员会遇到这类问题,编写代码时进行验证,并在功能全部完成之 后再提交代码。

例如大约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会被回收, 即该数据被释放。