<?xml version="1.0" encoding="GB2312" ?>
<?xml-stylesheet type="text/xsl" href="../../article.xsl" ?>

<article>

<title>没有使用版本控制的黑暗时代——版本控制心得（一）</title>

<author>晨光（Morning）</author>

<keywords>
  <keyword>版本控制</keyword>
  <keyword>软件开发</keyword>
</keywords>

<from type="原作"/>
<copyright/>

<paragraph>
在没有使用版本控制的开发团体中，我所熟悉的一种常用开发方式是：多个开发人员共同负责一个软件的开发，每个人在各自的机器上有整个软件的拷贝，并对之实施编码，分别完成各自任务之后，再通过文本比对工具将各自机器上的不同版本的软件整合到一台机器上。
</paragraph>

<paragraph>
本文就这样的开发方式，提出在软件开发中出现的几个和版本控制密切相关的典型问题（但未必全面），同样也是需要通过版本控制来解决的问题，它们来源于实际开发过程中的切身体会，并经过总结和整理。
</paragraph>

<paragraph name="1 软件代码的一致性">
软件的开发、维护和升级，往往是多个人共同协作的过程。不同人对同一个软件的不同部分同时做着修改，这种行为有时会出现彼此交叉的情况。由于同一软件在各自开发人员的机器上都有拷贝，软件的全部代码都暴露在每个开发人员面前，原则上他有权限可以不加限制地更改软件的任何部分。而当他们修改的内容属于公共部分，或者需要被其他人员所负责的部分调用时（软件各模块间的彼此依赖关系决定了这种情况是经常发生的），这种修改就属于交叉情况。此时，就有可能出现代码的不一致现象。比如：修改者在改动了某个公共函数的同时也修改了其调用接口，若其他人员没有得知此事，而在各自机器上仍调用原来版本的函数，则当整合时，就会出现错误。另一种更为严重的情况是，修改者决定废弃原有函数而另外编写一个新的函数，但他并未删除原有函数，这种情况即使最后的整合也可能不会被察觉，如果将这种一致性错误的纠正延迟到测试阶段，则会增加调试的难度，从而降低开发效率。为了始终保证代码的一致性，一种解决办法是，要求修改者每次修改后都通过某种方式告知同组其他人员，或者随时对软件做整合。但是这样，一方面会增加开发人员的负担，另一方面也降低了软件的开发效率。
</paragraph>

<paragraph name="2 软件内容的冗余问题">
软件在各自开发人员的机器上都有拷贝，并且同一个开发人员在不同时期也会在本机保留当时的软件版本，也就是说，一台机器上还可能不止一个版本。这类似于一种信息的冗余。对于不同版本而言，其差别有时可能并不很大，如果说不必要的占用存储空间是一个次要问题的话，那么另一个问题可能更重要。随着时间的推移，开发人员可能对自己机器上的不同版本间具体差异的了解变得模糊不情，甚至忘记了当时为什么区分这些版本的原因，这会给整合带来麻烦。而且，如果需要同时维护多个版本，则对某个版本的改动可能需要反映到其余版本的对应处，很难保证这一过程不会出差错。还有一点，作为开发人员，有时即使知道自己机器上软件的某个版本可能不会再使用了，他也不会去删除（生怕万一需要从那里获取点什么），但是通常也不会再去维护或查看它，因此久而久之，这种“僵死之物”会在多台机器上“蔓延”。
</paragraph>

<paragraph name="3 软件过程的“事务性”">
对于软件的某个版本，如果开发人员想要为其增添新的功能，或改善原有功能，而又担心会搅乱原来运行良好的软件。一种常用的办法，就是保留现有版本，另复制一个新的拷贝，并在新的副本上进行修改。这类似于一种事务处理，当将一系列操作做为一个事务时，如果中间某个操作出现偏差，则希望恢复到执行事务之前的状况。而当完成修改之后，开发人员该如何处理这两个副本呢？是在新的副本上继续新的开发，将之作为最新版本；还是将新的改动加入原有版本，删除新的副本。无论怎样，都可能会出现如下情况：如果软件运行正常，则出现2中提到的冗余情况；当删除修改前的版本后，又发现改动中有问题，但已无法恢复了；改动无误，将改动加入原有版本时，可能出现人为错误，导致软件运行出错；即使没有人为错误，这种做法也会给开发人员增加额外负担，一定程度的降低开发效率。重复上述过程则会出现多个类似的副本，此时，如何对待这些不同版本，将是开发人员需要面对的问题。而如果调试的过程中，发现确实有必要恢复到上一个版本，甚至上上个版本……，此时就不得不保留所有版本了。
</paragraph>

<paragraph name="4 软件开发的“并发性”">
由于是多人共同开发一个软件，期间出现多人修改软件的同一部分，尤其是同时修改，有时是不可避免的。对于前者，具有良好编程习惯的人员的一种通常做法是，对他人的源程序进行修改时添加必要的注释，写明修改人，修改原因，修改日期等。但实际情况是，当修改内容很零散或修改过程很复杂时，注释很难写，或者代码被注释分割得支离破碎影响正常阅读，或者注释无法详细说明实际情况。而且，这种做法也增加了开发人员的负担：他需要在考虑代码逻辑的同时，兼顾如何写注释；而对于注释和代码的一致性也是他需要随时留意的问题，不能疏忽。因此，我认为这种措施在实际开发中，并未取得实质效果，是不必要的，事实上代码本身（而非注释）是最能说明问题的，而修改的记录应该置于代码之外的某处。而且，不论是否是同时修改，都需要考虑1所提到的一致性问题，需要及时进行人工的差异比较和整合以便形成一个统一的新版本。
</paragraph>

<paragraph name="5 软件代码的安全性">
由于代码完全暴露于所有开发人员面前，任何人都可以增、删、改之。除了会造成1所提到的不一致问题外，从安全的角度来看，也是存在隐患的，这一点对于一个自主产权的长期开发的产品而言更是如此。即使是一般的项目开发，不同的人员其分工不同，允许别人可以不加限制地任意修改自己负责模块的代码（相当于所有人员都具有管理员身份），总是容易产生问题。对于共有模块更是如此，所有人都可以修改，一旦修改，则波及全体。
</paragraph>

<paragraph name="6 软件的整合">
    在软件的整合过程中，一般比较可靠的做法是使用文本比对工具辅助完成的。这种措施，有以下缺点：
<list>
    <li>可靠性，整合中的人为错误会影响软件的可靠性，有时这种错误很难察觉，可能编译没有问题，而在测试时却发现了问题。这种潜在的错误发现的时间越晚就越难以纠正。</li>
    <li>效率，对于纯手工的整合即使熟练操作的人也是需要时间来完成的，而有些整合只是将两段代码拼接在一起，这一过程完全可以借助于某些自动机制。这可以大大节省时间，使开发人员可以专注于后续的开发任务。</li>
</list>
</paragraph>

<paragraph>
注：本文已在csdn上贴出，查看相关评论请到<link href="http://www.csdn.net/develop/article/15/15468.shtm">这里</link>
</paragraph>

</article>