序
支持基于任务单元/活动(Task/Activity)的开发是当代(第三代)配置管理工具的重要特征。它所带来的益处有大量文章介绍,在此不一一赘述。但是,当前的主流配置管理工具在支持基于任务单元/活动的开发方面颇有限制。例如,在一些工具中,如果某个工程师在Release2.0上的某个关于修正缺陷的任务单元是在该工程师在该Release上的某个关于功能改进的任务单元之后完成的,并且这两个任务单元涉及同一个文件,那么,修正缺陷的所做的修改不能单独被复制到Release1.1上去,尽管这两个任务单元对同一个文件的改动互不相干。
究其原因,是这些工具对任务单元的支持尚不充分。本文提出一个增强的任务单元模型,以使基于任务单元的开发得以充分发挥它的效力。
模型:任务单元
任务单元对应一个具有整体逻辑意义的变更,比如修复了一个缺陷。另一方面,这个任务单元又对应于对多个文件/目录的具体修改,因为是这些修改实现了那个具有整体逻辑意义的变更。那么,如何记录和表述对多个文件/目录的具体修改呢?
是否可以通过记录每一个相关文件/目录的变更后版本来实现呢?这样做,初看起来不错,但是这是有问题的。变更后版本中的内容不仅仅是这个任务单元引入的,还有过去的其它任务单元引入的。因此,当把这个任务单元提交的时候,或者把它从一个Release复制到另一个Release的时候,容易带入与这个不相干的内容。另一方面,当我们回顾某一个任务单元的时候,如果只看变更后版本,我们不能了解,在这个任务单元中我们究竟做了哪些改动。
记录一个任务单元,要记录每一个相关文件/目录的变更后版本,还要记录每一个相关文件/目录的变更前版本。而变更,就体现在变更前版本和变更后版本的差异。记录变更前和变更后两个版本,就以一种简单的方式,完全记录了变更。见下图:
![](images/2006062618.JPG)
图中,上面的顶点代表某文件/目录变更前的版本,下面的顶点代表某文件/目录变更后的版本。由这两个版本,就能确定所发生的变更。而如果只用下面的顶点,不能描述所发生的变更。
要注意到变更前版本和变更后版本并不总是同时存在。当在一个任务单元中增加一个文件/目录时,该文件/目录只有变更后版本,而变更前版本不存在。当在一个任务单元中删除一个文件/目录时,该文件/目录只有变更前版本,而变更后版本不存在。当在一个任务单元中修改一个文件/目录时,该文件/目录的变更前版本和变更后版本都存在。
还要注意到,不仅仅是文件可能有修改,目录也可能有修改。这里所说的目录,不是关于这个目录包含哪些文件和子目录的信息列表,而是指目录的具体内容,包括其所包含的文件和子目录的具体内容。在任务单元中,要记录相关目录的修改前版本的全部内容,和修改后版本的全部内容。这是最简单和清晰的方法。当然,在工具具体实现的时候,可以有一些优化。
不论是文件,还是目录,都充当作任务单元的入口点(Entry Point)。一个任务单元包括对若干文件/目录的变更,这是第一层。而进入每个入口点后,变更还可以进一步细分,到子目录,文件,直到文件中的内容块。
模型:任务单元的迁移
任务单元会从其诞生的工作空间,迁移到相似的工作空间。例如,当我们完成了一个任务单元,我们要把它提交到公共的公共空间。我们在Release1.1中的改动,可能要迁移到Release2.0的最新的工作空间上去。那么,任务单元如何迁移呢?
先考虑简单的情况:如果当任务单元中某个文件/目录的变更前版本,与要迁移到的工作空间中的相应文件/目录的版本,其内容相同,那么是比较好处理的。我们只需要用任务单元中该文件/目录的变更后版本来覆盖工作空间中的相应文件/目录就可以了。具体情况见下图:
![](images/2006062619.JPG)
左上角是变更前版本。左下角是变更后版本。它们之间有一些变更。右上角是工作空间中的当前版本,它与变更前版本相同。右下角是在接受了变更后,工作空间中的内容。它应该与左下角相同。也就是与任务单元中的变更后版本相同。
但是,并不总是这样的简单情况。有的时候,任务单元中某个文件/目录的变更前版本,与要迁移到的工作空间中的相应文件/目录的版本,其内容并不相同。也就是遇到了以下情形:
![](http://www.uml.org.cn/pzgl/images/2006062620.jpg)
从图中可以看到,由于左上角和右上角的内容并不相同,我们不能直接把左下角的内容复制到右下角去。我们说,这时候,存在着冲突。
解决的办法是,我们对任务单元中的内容进行变形,在保证所代表的变更本身不改变的情况下,改变变更前版本和变更后版本的内容,使新的变更前版本与要迁移到的工作空间中的相应文件/目录的内容相同:
![](images/2006062621.JPG)
图中,任务单元中的文件/目录的变更前版本从左上角的内容变化为右上角的内容。而任务单元中的文件/目录的变更后版本也从左下角内容变化为右下角内容。而不变的,是变更前版本和变更后版本之间的差异:图中左边所代表的差异和右边所代表的差异是相同的。
在任务单元完成自身的变形后,事情就变得简单了。这时,任务单元中文件/目录的的变更前版本与要迁移到的工作空间中的相应文件/目录的版本,其内容相同,因此变成了简单的情况:
![](images/2006062622.JPG)
在这样的情况下,右上角和左上角的内容相同,因此右下角的内容应该和左下角的内容相同。我们只需要用任务单元中该文件/目录的变更后版本来覆盖工作空间中的相应文件/目录就可以了。
基本应用:提交工作
程序员在完成了一个任务单元,提交到公共工作空间的时候,就可能会遇到冲突。公共空间里的文件/目录可能已经被别的任务单元修改,而不再与这个任务单元中的更改前版本相同。如果发生这样的情况,就要先对任务单元变形,然后再推入到公共工作空间。
程序员可能会一次提交多个任务单元。为保证未提交的任务单元都被提交,而曾提交过的任务单元不会再被提交,可以采用如下算法:
找到程序员私有的工作空间与公共工作空间的最近的共同祖先基线。找到私有的工作空间中所有在该基线之后的任务单元。逐一考察这些工作单元,剔除那些已经存在于公共工作空间中的。这样,就得到了所有本次应该提交的工作单元。
基本应用:更新本地工作环境
程序员也需要将其它程序员完成并提交的任务单元下载到本地,以更新自己的工作空间。在下载和更新的过程中,同样可能碰到冲突。私有工作空间里的文件已经被程序员自己的任务单元修改,而不再与下载的任务单元中的更改前版本相同。如果发生这样的情况,就要先对任务单元变形,然后再推入到私有工作空间。
为保证未下载过的任务单元都被下载和推入到程序员私有工作空间里,并保证曾推入过的任务单元不会再被推入,可以采用如下算法:
找到公共工作空间与程序员私有的工作空间的最近的共同祖先基线。找到公共工作空间中所有在该基线之后的任务单元。逐一考察这些工作单元,剔除那些已经存在于私有工作空间中的。这样,就得到了所有本次应该下载和推入的工作单元。
一般来说,应该同时存在两个公共工作空间。其一是接收程序员提交任务单元的工作空间。如果程序员更新本地工作环境时也从这个公共工作空间里下载任务单元,那么程序员将拿到最新提交的任务单元。
而另一个公共工作空间是最新的基线。也就是说,这个公共工作空间是被冻结的,不可更改的。并且,它通过了系统集成员的编译和粗略测试。如果程序员更新本地工作环境时是从这个公共工作空间里下载任务单元,那么程序员将拿到最新的稳定的工作成果。
高级应用:多Release并行开发
在发布了产品的Release 1.0之后,你可能一边做维护工作,例如修正缺陷,以产生Release 1.1;一边在开发下一个Release:Release
2.0。这样,在产品的版本树上,就出现了分支。我们需要解决的问题是,将Release 1.1分支上的维护工作的成果也反映到Release
2.0分支上去。偶尔,我们也需要把Release 2.0分支里的少量工作成果带回Release 1.1分支。
基于任务单元的开发方法及增强的任务单元模型在这时显示出了优势。程序员可以有选择的把Release 1.1里的任务单元(一般来说是绝大部分)迁移到Release
2.0的公共工作空间中去。同时有选择的把Release 2.0里的任务单元(一般来说是少量)迁移到Release 1.1的公共工作空间中去。在此过程中,尽管任务单元内的文件/目录的变更前版本可能与将迁移到的工作空间中的对应内容不相同,也仍可以将变形后的任务单元推入另一个的工作空间。
高级应用:相似项目并行开发
与多Release并行开发这种情形不同,一些软件公司不得不面对并行的相似项目。例如,给客户A做的,给客户B做的,等等。这会导致管理上的种种复杂和困难,不仅仅是在配置管理上。
为了降低这种复杂度,我们应该尽可能的减少不同项目间的区别。尽可能提供一个标准产品,每一个项目跟它没有区别或者只有很少的区别。这里所说的很少的区别,则可以被一组任务单元所表达。当标准产品产生新的基线,并且项目产品需要依此升级时,我们把这一组任务单元加到新的基线上,就得到了关于某个项目产品的升级版。
高级应用:出差与离线工作
可以看到,应用本文所述的增强的任务单元的模型,并不需要知道任务单元中所包含的版本与目标工作空间中对应内容之间的关系。不需要知道它们在版本树上的位置。不需要一个神秘的中央数据库来存储各个版本的内容。因此,离线工作时,计算机无需与服务器连接,即可在本地新建任务单元,在任务单元中工作,记录任务单元的内容。离线工作时,可以完成多个任务单元。
另一方面,每个任务单元的内容可以用一个简单的目录记录,因此可以方便的将它打包压缩,通过网络或其它形式传输。接收方收到后,可以简单的把它推入到目标工作空间中。
高级应用:多重集成
有时候,一个开发小组,为实现一个新的功能紧密合作。这时最好让他们和组外的开发有适度的隔离,直到他们做出点什么。不然,他们可能会把一些尚不稳定的东西带到更大的开发团队里来。
于是,这个小组的成员不再直接向公共区域提交任务单元,而是向小组的组长提交任务单元,并且从他那里得到小组之外的任务单元。
高级应用:地理上分布的开发
有些时候,如果让所有的程序员都往一个公共工作空间提交任务单元的话,显得不是很方便。例如,他们可能分布在全球若干个开发地点。最好是让程序员能够从所在的开发地点就近下载其他人或其它开发地点的任务单元,并且只需要将任务单元提交到所在的开发地点。
可以考虑建立一个虚拟开发地点作为中心站。而其它真实的地点作为卫星站。从较高层面上看,一个卫星站就好像一个程序员,而中心站就好像是供程序员(实际上是卫星站)下载和上传的公共区域。
这既涉及到了出差与离线工作,也涉及到了多重集成。
工具
大多数配置管理工具还不支持基于任务单元的开发方法。
一些大型商用配置管理工具在一定程度上支持基于任务单元/活动的开发方法。
Flooda是一个开源免费的配置管理工具。它从底层结构设计上支持基于任务单元的开发。它使用增强的任务单元模型,从而可以充分发挥基于任务单元的开发方法的优势。你可以通过它来研究基于任务单元的开发方法,也可以在实际工作中运用它。
|