内容简介:有赞电商移动代码 VCS 的演进
我们有幸在一个毫无疑问以 git 作为 VCS 的开发时代,git 为我们提供了太多想象力,解放了我们许多的生产力。
有赞使用自搭 git 服务器的方式为所有的项目提供版本管理,而我们现在的产品——微商城/微小店/有赞买家版,都是基于我们的 git 仓库进行管理的。
开天辟地
随着公司规模和产品的发展,我们的仓库变得越来越大,feature 越来越多,2016 年我们团队在评估现有的代码之后,决定开始模块化的改造。
模块化首当其冲的就是对 VCS 的需求产生变化,一个看上去非常简单的 repo 可能已经不再满足我们的需求,因为我们需要不同的模块能足够产品化,能够进行独立维护,能够为我们的新需求提供强有力的支持,顺便还能帮我们快速定位到问题转到相关负责人的手中,这是我们的愿景。
我们为模块化做的第一件事(以 Android 为例),就是在当前的项目中,为不同的业务模块,新建好不同的文件夹(Project),把不同业务的代码,从一个巨大的代码库中,慢慢剥离开,一点一点的落地到相应的 Sub Project 里面,好让我们对各个业务的边界有明确的认识。
莱克星顿的第一声枪响
在这个时候,我们花了很大的时间完成这项工作,在第一阶段完成之后,看见清晰的目录结构不禁沾沾自喜,但是,挖坑的弊端接踵而至——首先,Gradle 编译的时间大大的加长了,一次编译完成的时间足够你去喝一杯热气腾腾的咖啡。每一次的产品迭代中,产品一个新需求,我们会使用 Git Flow 的标准新建一个新的 feature
分支,在 feature
分支下实现新需求,写完代码,等待编译,安装到手机上,自测,然后改 Bug,再循环。
没错,在没有 TDD,暂没办法进行自动化测试的条件下,我们活的非常艰难,实现业务很像是在浪费生命,我们的时间如此值钱,怎么能荒废在天书…啊呸, compile 里面?于是我们渴望把我们的生产力继续解放,不能为了头脑清楚而捆绑了手脚。
同时,我们的仓库在业务模块分支的开发中,分支表现的混乱不堪,经常需要一堆人聚在一块解决合并的时候模块的冲突的问题,现在这个样子,好像根本没有解决问题嘛。
巨大仓库的改造
我们这时候维护了一个非常巨大的仓库,每一次的分支提交,都有潜在的可能对对方造成影响。你可能在这个分支上“不小心”改了某一行别人分支的代码,这并不是符合预期的(unexpected),结果在合并代码的时候,就得问对方,这块是不是你改过的,我应该选择哪一
块的代码,这样的分支合并,在比较小的项目里,可能问题表现的不明显,因为就算变动,也是有限的几行代码,但是在代码数量级高许多的项目中,它就有可能是一种灾难了。我们这个时候希望把仓库拆出来,这样使用 VCS 去统一管理各个模块,而不是让他们都寄宿在一个大 repo 里。
在这之前,我们已经了解过 git submodules 的优缺点,如果使用 git submodules 进行改造的话,成本的确是非常小的,它的整个模型如下:
但是我们知道,git submodules 是在 父 repo
中维护一个对 submodules
的一些指针,如果子 module 代码发生了更改,除了父 module 提交代码外,还需要对子 module 的指针进行更新,这种 contains 的操作在我们的场景里,无疑对项目增加了许多的复杂性,经过一些综合的考虑,我们最终放弃了使用 submodules
的方式,使用 repo
( https://gerrit.googlesource.com/git-repo/)进行管理。
repo 的使用
首先,非常推荐微店的梁志涛在知乎上关于 【为什么android使用repo而不是直接使用git管理工程呢】的回答 ,感谢他的一些技术指导,给我们对 repo 和 git submoudle 的认知提高了好多个档次。
repo 的一些特性可以让你在没有插件化之前,就能用上它,用上它之后,我们现在的模型是这样的
app 壳工程和业务模块工程并行了,更新各个模块的代码再也不会对其他工程有影响。如果把业务模块转换成坐标依赖,我们还可以选择性地把需要的代码拉到本地,不需要的代码不用去动,连 compile 的时间都省了好多,我们的愿望有多么的美好,那么现实就会有多么的残酷。
首先,按照 Android 的目录结构来看,如果我们不进行较大的配置的话,我们许多的文件,必须放到外部工程的根目录下。
大概像这样
为了图中红色字文件的正确路径,我们一开始把这些文件打入了一个叫 wsc
的 repo 里,repo 下拉代码的时候,会在根目录下写入 wsc
这个 repo 里的所有的文件,且在根目录下面,继续加入其它模块,这样我们发现,其它模块又变成了 wsc
的子模块了,虽然没有 git submodule
恶心,但是整体的组织结构还是很奇怪,为了保证其它模块不被打入 wsc
仓库,我们只好在这个 repo 下面的 .gitignore 中,把其他模块的管理都去掉了。
.gitignore 如下:
# 省略其他 # 业务模块的 ignore wsc_login wsc_customer wsc_shop ....
我们可以看到,gitignore 居然和业务耦合在了一块,也就是说,我再抽出一个业务,如果我忘了在 wsc
里面把这个业务文件夹 ignore 掉,就会被 push 到仓库里,这不和 git submodule 一样了么?我们使用 repo 不是就是要解决这样的问题么?
于是我们参考了 Android Source
提供的方案,看看它是怎么管理这种文件的。
我们可以看到,这里面有两个非常有用的指令就是 linkfile
, copyfile
,给我的启发就是,我们可以创建一个包含构建文件的 repo,用这个 repo 去管理 Make
相关的逻辑,同时,repo 的颗粒度要足够小,让各个 repo 各司其职,这样 repo 之间的互相耦合就更小了,我们把这个 repo 取名为 gradle_files
,本来想取名叫 build
,但是可能会和 Gradle
生成出来的文件夹冲突,所以只好换了一个名字,名字解决后,我们整个文件夹的结构就是这样的:
带箭头的都是软连接。截图里没有把其他业务模块拉下来。如果我们需要更改业务代码,就把 app 下的 build.gradle
中改成 project
依赖,否则使用坐标依赖。
使用 repo 的出发点,就是为了我们后续的快速开发,模块代码级的分离,和更标准化的打包流程。
目前痛点
在现在这个阶段,我们暂时解决了模块间的版本管理问题和编译速度的问题,我们秉承一条原则:不要过度设计,不要一开始就想着完美,出发比思考更重要。
因此,正因为不完美,我们的整个解决方案还有许多的改进空间,目前的痛点还有如下:
- 打包系统功能暂不完整,离我们的设想还有一段距离。
- 模块的发布尚未标准化,我们目前依赖于清除本地 Gradle Cache 的方式,让开发中的代码进行更新。
- 打包和 Code Freeze 需要人工去介入。
- 对于 TDD 和 BDD,得益于模块的解耦,可以开始探索,但是尚未出成果。
总结
使用 repo 算是一种走出舒适区的尝试,我们热衷于把我们的基础设施建设得更加现代化和标准化,我们所做的一切,都期望我们自己能更专注于业务,把我们从痛苦的打包和版本管理中解放出来。幸好,一切都开始了,并没有踌躇不前,革命尚未成功,同志仍需努力。
以上所述就是小编给大家介绍的《有赞电商移动代码 VCS 的演进》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
C语言算法速查手册
程晓旭、耿鲁静、张海、王勇 / 2009-10 / 49.00元
《C语言算法速查手册》用C语言编写了科研和工程中最常用的166个算法,这些算法包括复数运算、多项式的计算、矩阵运算、线性代数方程组的求解、非线性方程与方程组的求解、代数插值法、数值积分法、常微分方程(组)初值问题的求解、拟合与逼近、特殊函数、极值问题、随机数产生与统计描述、查找、排序、数学变换与滤波等。同时结合这些算法列举了将近100个应用实例,对其进行验证和分析。 《C语言算法速查手册》适......一起来看看 《C语言算法速查手册》 这本书的介绍吧!