1 构件的集成原则
1.1 生产者与消费者
不同构件的开发者之间通常处于一种生产者与消费者的关系,即生产者交付工件提供给消费者使用。生产者交付的工件类型有:原始(Original)工件(源码、构建脚本、配置文件等),中间(Derived)工件(Obj文件、lib库等),最终产品(Product)工件(可执行文件、Dll库等),其它临时(Temporal)工件(编译器产生的临时文件等)。消费者将使用这些工件。C++项目中这种消费关系包含:编译引用他方的公开(public)头文件、链接他方的静态库文件(或Obj文件)、以及生成的最终执行文件调用他方的动态链接库等。
除了原始(Original)工件,其它派生工件都可以通过构建过程来自动生成,为了简化生产者与消费者的依赖关系,保持派生工件对原始工件版本的一致性,并减轻配置管理的开销,生产者应尽量只向消费者提交原始工件,消费者则依靠构建脚本生成他们需要的派生工件(出于效率考量,在构建开销较大时,消费者也可以直接使用生产者构建出的最终产品工件,其后果是版本冲突的风险变大,配置管理的开销增加)。
为了满足只提交原始工件的需要,编制自动化程度很高和高质量的构建脚本变得格外重要,如果构建过程增加了消费者的负担,或者出现了构建失败的情况,消费者将更倾向于直接从生产者手中拿到构建后的产品工件。
理想情况下,生产者可能在消费者开始使用前就交付了其依赖的工件,但通常团队会采用并行开发模式,消费者必须在生产者完成交付前就开始工作,因此开发替代的桩(Stub)代码,甚至为了调试方便而专门开发摹仿(Mock)代码,成了家常便饭。根据实际需要,替代代码可以由生产者自身或消费者来开发。针对这种状况,在编写构建脚本时,应提供相应的编译、链接选项,使得消费者可以自由选择将交付代码或桩(Stub)代码编译、链接到他的构造工作版本中,同时集成员还可以利用这些选项来开展增量式的迭代集成。
1.2 源码目录组织原则
开发目录组织结构从来就是关系到项目健康成长的关键因素。开发(产品)目录提供了项目团队进行开发、管理等活动的统一共享场所,它需要满足不同涉众(角色),在不同的阶段,对不同类型工件进行访问的多种场景需求。因为项目的编码实施、集成等活动相互间的依赖关系远比其它文档编写类活动要复杂,协同整合更为困难,使得合理的源码组织结构变得极为重要,构架师和配置管理员必须投入更多精力关注开发(产品)目录中的源码组织部分。
源码目录组织的首要原则是目录结构的统一,项目中应当采用统一的分类方式、同一的风格、一致的命名格式来创建所有构件的源码目录。本项目中涉及到第三方库、项目构件、子系统、系统四类构件,其源码目录结构采用同一的基础目录结构,并根据各自需要做了相应的扩展。
开发(产品)目录的组织应当尽量在同一级的目录中采用同一种分类标准。目录分类标准有:按照工件类型(src/bin/lib/doc/mdl/script/web/xdoc),按照工件功能或用途(build/test/interface/example),按照活动组织(plan/requirement/design),按照归属关系(第三方库3rd Lib/基础构件Components/子系统Subsystem),等等。
如下图所示,本项目中,第一级目录按照归属关系来划分,源码构件的第二级目录按照构件设计包结构来划分,源码构件的第三级目录则按照工件类型并结合工件用途来划分。
开发(产品)目录应当面向团队协作,既要做到实施员在私有空间开发时相对独立,不受他人工作的影响,又能保证与他人的工作成果同步,并顺利地实现集成。这将依赖软件配置管理工具的支持,方能较好地达成上述目标。
开发(产品)目录本身可以看作是项目的一个工件,随着项目的进展也在不断地调整和演进,代码需要经历重构,目录结构也不例外。在项目初期就完全固定目录结构是不现实的。当前支持对目录进行版本控制,并能方便修改目录结构的配置管理工具不多,其中以ClearCase为主要代表,这也是本项目选用ClearCase的原因之一。