代码管理
上文讲的是人员和团队,提出要将团队划小管理,那具体到开发层面,我们如何建立与之对应的工程结构及版本管控呢?
在我们传统架构下一个项目一般对应于一个或几个版本库(服务端一个、几个大前端,如Android、IOS、Web),很少有项目会将服务端代码按服务域或子系统拆分到不同的版本库中。但微服务因其服务多且服务间由不同团队开发,无论从代码安全及上文讲的团队独立等因素我们在设计工程结构时都应该充分考虑服务间的隔离。
版本管理最优选择必定是Git,我们可以用Git的Submodules实现上述要求。一份笔者常用的工程结构,一个工程对应一个Git库如下:
各个工程都对应于一个独立的Git库,Git库分四类:
源码库(对应于sources目录下) 存放所有的源代码,可细分成:全局父工程(sources/basics/parent),这是除终端外所有源码的父POM,全局公共工程(sources/basics/common),这是除终端外所有源码都依赖的包,对于各服务组件还有全局公共服务工程(sources/basics/common-service),它定义了包含公共启动文件、Domain、DTO等所有服务组件都需要的代码。服务组件指的就是一个个微服务(sources/services/...),也是一个个独立的Git工程。所有终端代码也可被统一管理,要注意的是这里整体使用Maven,但IOS、Wechat都不是java工程,所以需要在这些工程中加一个只标记用于管理的POM文件(只有maven核心定义,不需要dependencies、build等),如果我们的项目是服务平台类型,那么多半会需要对外提供SDK,所以需要有相应的SDK工程。
文档库(对应于docs目录) 推荐使用Asciidoc,使用asciidoctor-maven-plugin 生成HTML、PDF等文档格式。
📖 Asciidoc是一种标记文档格式,比Markdown语法更丰富,非常适合写复杂的文档,被Spring Cloud、HBase等众多开源框架所使用。
环境配置库(对应于env目录) 用于存放各环境的配置文件,将配置文件放到Git是比较好的选择,Spring Cloud、Vert.x都支持这一形式,后面我们会有独立章节探讨,统一的配置管理非常重要,可参见上一章节的相关介绍。
构建库(对应于根目录) 用对将各个独立的工程聚合管理。
❓ 为什么文档库及配置库是整体项目独一份的?
上文我说过自由是相对的,基础的规范要统一,这里的文档库是包含项目的概要设计、各服务的详细设计、发布规范、编码规范、技术选型规范、降级流程等,统一的文档库能让项目整体上更统一也更利于管理,配置库的统一可方便运维管理及配置依赖管理。
我们有了这么多独立的Git工程,看起来各工程都拆开了、独立了,但怎么有效的管理呢?这时我们就需要Git的Submodules了。上文提到的构建库正是用于这个目的。
📖 Submodules是Git用于组织多个Git工程的一种方案,详见此处。
Submodules的核心是.gitmodules文件,它定义了不同Git工程的组织方式,示例如下:
有了这份文件后我们就可以通过如下命令完成整体项目的检出:
git clone --recursive <Build工程的Git地址> <project name>
,--recursive参数会遍历此Git库中的Submodules定义并clone下各个子模块工程。
build.git工程包含了所有工程源码,多用于项目的整体管理,权限持有人为项目管理人员或总架构师,我们会为不同的团队设置不同的build工程,不同build工程包含不同的Submodules。如给短信团队的sms-build.git,它的.gitmodules如下:
我们看到,短信团队只要组装几个基础工程外加一个短信服务就可以了。
Git的Submodules对分支支持不是很友好,目前需要手工checkout到指定分支,我们可使用 git submodule foreach
来批量操作,如 git submodule foreach 'git checkout master'
。在子模块修改及多模块提交上可通过IDE以简化操作。以IDEA为例,如下图:
IDEA可以感知到项目中的所有Git工程并询问是否加入到版本控制中,上图为我们的build工程,其它的为各个子模块。在我们修改任何被纳入IDEA管理的子模块时都可以一并被提交,提交时还可以选择哪些子模块是否提交:
通过拆分各块到不同的版本库及使用Git的Submodules,我们可以很方便地管理众多的服务,非常推荐微服务团队采用,它所能带好的好处总结而言如下:
效率提升 各团队不需要获取完整的项目代码,只要拉取自己团队所要关注的工程即可,开发中可以更聚焦,也加快了编译构建的速度
安全可控 同样由于上面的原因,我们可以尽可能细粒度地控制代码的可见性,只给需要的人以权限
流程敏捷 一般而言在发布之前我们都要做分支合并(参见不同的版本flow模型 ),发布分支只有特定人员才能合并,在不分工程的情况下大家试想下分支的合并场景, 我们需要会花很大的精力在Code Review及冲突解决上,在CI流程下如使用特定的分支用于测试那会导致非常频繁的触发自动构建,当我们拆分工程后一切都会变得简单,各团队负责人执行各自工程的分支合并,测试也会基于独立的分支进行
Last updated