写点什么

这样才是代码管理和 Commit 的正确姿势! | 研发效能提升 36 计

作者:阿里云云效
  • 2022 年 2 月 10 日
  • 本文字数:3400 字

    阅读完需:约 11 分钟

这样才是代码管理和 Commit 的正确姿势! | 研发效能提升36计


专栏策划|雅纯

志愿编辑|张晟


软件交付是以代码为中心的交付过程,其中代码的作用有几点:第一,最终的制品要交付成什么样,需要通过代码描述清楚;第二,代码定义了系统和软件是怎样工作的;第三,代码定义了系统的运行环境是怎样的。所有这些都是围绕代码。

那我们的代码管理和软件配置管理应该怎样做呢?


我们先看一个例子。下图是某个团队的代码组织结构,这样的代码组织结构会有什么问题呢?



问题 1:代码组的命名方式混乱


我们发现在最上层的目录中叫 risk-managenment,这是一个系统,这个系统是风险管理。但是子目录写的是叫“qinglong”,那“qinglong”是应用还是团队,我不知道。然后下面还有一个玄武,下面还有一个 aTeam,中英文混杂,这样的命名方式是很混乱的。


问题 2:用代码块存储外部二进制文件


在 android-sdks 里面会存放很多 sdk 文件,这些文件是很大的,这个代码库存储很多外部二进制文件,我们知道在代码库直接存这样的大文件,对整个代码库的资源消耗是非常大的。


问题 3:同一归属的代码保存在不同的代码组


在 aTeam 目录下有一个 data-model,但是其他相关的文件都在玄武下,就是 data-console、data-task、data-ui,我们不知道它具体是什么,但是我们知道这几个大概率是同一个应用或者是同一个产品,所以它在两个不同的层级也是不合理的。


问题 4:公共库保存在子代码组里


再下一个是 common-lib,通过名字来理解就是公共库,但是这个公共感觉只给玄武这个子代码组使用。

问题 5:应用的文档(或测试)与应用分开存放


最后还有一个 docs 目录下有 risk-docs 和 data-docs,一个是针对风险控制的系统,一个是针对数据地系统。那这个里面文档也是一个代码库,文档代码库和测试代码库,它和应用是分开存放的,这也是不合理的。

好的代码库组织形式是怎样的?


问题:假设所有的代码都保存在一个代码库,且所有人均可访问,代码库应该怎么组织?


我们认为代码库是可以分组的,代码组(+子代码组)+代码库=大库。


基于这个逻辑,我们再看看刚才那个例子里合理的代码组的结构应该是怎样的。


如上图所示,整个代码库是一个系统,这个系统有两个应用,一个是 risk,一个是 data。每个应用下面是有很多的服务和文档。它们有一个公共的 Model,叫 common-lib,这是被所有的应用所依赖的。所以我们把属于同一个应用的 Git 仓库放在一起,让 common 放到该有的地方去。不是按照团队,而是按照应用组划分,这样划分,结构就更加清晰了。这里我们稍微总结了一些实践的建议。


  • 代码库的内容:


-软件的源代码(ProductionCode);-将文档(和测试)的 git 库放到其相关应用组下;-不要将制品(如系统二进制包)保存在代码库中,如果确实需要,以 LFS 或类似方式存放;(小编推荐:云效代码管理 Codeup 为企业提供免费不限容量的 LFS 存储)


  • 代码库的组织结构:


-按照系统、应用和模块的层次来组织代码库;-同一个系统/应用层级的所有内容位于同一个代码组下;


  • 代码库的可见性:


-通用代码库放在其通用级别都可以访问的位置;-除核心算法等少数代码库外,建议对代码库的访问在同一系统/应用下对所有相关人员公开;


代码组织完了以后,开发者就可以围绕代码库来进行协作。整个代码库的协作过程就是:一切皆 Commit。无论是 rebase 还是 merge,都是 Commit。


那对于 Commit,我们有什么要注意的呢?

什么是好的 Commit


我们总结了 3 点建议给到大家:


1.Samll


Git 库要尽可能地小。尤其是目前的基础设施现状下,虽然你的一个仓库里可以放多个应用,但是维护起来的成本会很大的。还有管理方面,不要在 Git 上存储构建产物和其他二进制文件。把构建产物放在构建仓库上,虽然给别人方便了,却很难知道这个构建产物是现在的代码产生出来的还是之前产生出来的,这是很难去追溯的。对于二进制文件,如果确有必要(例如游戏的素材),建议使用 LFS 的方式来保存。


2.Linear


避免无意义的 merge,尽量用 rebase 操作。其次是避免无效 commit,有很多代码库 commit 记录很长,但是里面 80%都是无效的,例如都是 fix1、fix2 这样的 commit,都却不知道它具体做了些什么,这种显然是不合理的,对于这种冗长的 commit 列表,有时候可以在 merge 的时候 squash 一下。


3.Atomic


原子性,指操作的原子化。原子性有什么好处呢?一个 Commit 解决一个特定的问题,比如说我就是修复一个 UTcase,或者是加一个 UT 或者是加一个功能,或者是加一个 API,这些明确的问题对应到一个 commit,很容易追溯。解决的问题不能很大,不能写了 2000 行代码解决了一个 feature,一起提交,这是非常危险的。作为开发者,做的好的应该是快速有阶段性的成果,并且持续地有反馈,持续地贴近目标。反之,开发者的体验不好,相关协作者的体验也不好,因为别人不知道你做了多少了,很有可能跟你发生 mergeconflict。


下面列举一些 Commit 的反模式:


1.无效的 commit


如 Mergebranch'develop'of https://codeup.aliyun.com/abc/xyzintodevelop第一个问题,在几乎所有公司里面都是随便拉开一个代码,本地和远程都有这种情况,本来一个 rebase 搞定的事情,这样做会导致很多无效的 commit,甚至对 commit 追溯能力会产生很大地影响。


2.巨型 commit


一个 commit 里面包含了大量的代码变化,且属于多个实现目的,就像 codereview,有些人提的 mergerequest,一下子过来 3000 多行代码,作为 reviewer,你完全不知道他做了什么,这是非常危险的。


3.半成品的 commit


如包含有基本语法问题或实现错误的代码的 commit 半成品的 commit。例如,到饭点了,不管了,先提交一把。这样的代码连编译都过不了,这个显然是不好的,没有任何意义。


4.分支间的互相 merge


最后一个是分支间的互相 merge。从 develop 合到 master,又从 master 合到 develop,互相合来合去,一旦这种合并多了以后,commit 就会很难追溯,因为不知道源头在哪。我们建议代码库应该有一个唯一的主干,单向往主干 merge,尽量避免反向 merge 的情况。


(小编推荐:云效代码管理 Codeup 的主干开发模式,就提倡轻量的 commit 评审 和主干研发,帮助企业避免分支间的复杂合并~)

软件配置管理


问题:软件配置经常被修改,被发布,它属于代码吗?


软件配置其实是另外一种形式的代码。有可能大家在实际工作中配置不是存在 Git 仓库里面的,可能是在一个配置中心或者其他类似系统里面,但无论在哪里,本质上,我们可以把配置等同于某种类型的代码。

下图是大家常见的静态配置和动态配置,或者说启动相关的配置和运行相关的配置。



启动相关配置


  1. 启动相关配置是构建到镜像中或者作为启动参数传进去的。

  2. 启动之后不再修改了,不需要去动态监听它的变化。

  3. 对这类配置的修改,一般需要重新创建或者重启容器。


以此类推,哪些配置是启动相关的呢?比如 DB 连接串、容器 CPU 规格、启动模式等(比如有的压测应用启动的时候区分 master 模式和 worker 模式)。其它像 DNS 服务地址等,诸如此类的我们都认为是启动相关的配置。


运行相关配置


  1. 通常是通过监听某个服务或文件来获取和更新的。比如说我要看一下我的白名单是什么,我去读一下白名单。

  2. 配置的更新是不需要修改容器和 Pod。

  3. 运行中的容器需要持续监听配置的变化,当有变化后自动生效、无需重启。


我们举一下场景实例说明一下:


  1. 大促时期调整日志级别,只记录 ERROR 级别的日志。

  2. 服务的黑白名单,为了限制某些 IP 的访问,将其列入黑名单。

  3. 特性开关,通过开关打开或关闭某个 feature。

  4. 监控采样频率,由每分钟采样一次调整为每 5 分钟采样一次。

这些配置不需要也不应该每次修改都重新部署应用,他们都属于运行相关的配置。

我们再来看一个 demo 示例里面哪些是启动相关的,哪些是运行相关的。我们列举一下:



这是启动的时候就会需要的一个参数。



我们将 secret 文件注入到 Deployment 中,应用自动从文件感知 secret 的值,无需重启,因此它是运行时的配置。越内层的配置,修改成本越高。



从另外的角度看一下配置,它有不同的层次,代码、镜像、Pod 和系统。代码中的配置位于最内层,修改成本是最高的。因此,如果是编码级别的修改,要经过所有的阶段才能上线。如果运行阶段的话,我是不需要动前面的部分。


最后,留一个问题给大家:运行环境相关的配置是属于哪一种?欢迎大家在评论区留言互动。


软件交付的终态是提供稳定可预期的系统,要做到这点,需要确保:1.运行环境的一致性;2.软件制品的一致性。所以下篇,我们将开始分享如何保证运行环境的一致性,以及环境中大家常见的痛点和应对方案。敬请期待!


阅读上篇:构建制品不一致,后续工作都是白费


点击下方链接免费使用云效代码管理 Codeup


https://www.aliyun.com/product/yunxiao/codeup?channel=yy_rccb_36



发布于: 刚刚阅读数: 2
用户头像

还未添加个人签名 2021.11.05 加入

云效,云原生时代一站式BizDevOps平台,支持公共云、专有云和混合云多种部署形态,通过云原生新技术和研发新模式,助力创新创业和数字化转型企业快速实现研发敏捷和组织敏捷,打造“双敏”组织,实现 10 倍效能提升

评论

发布
暂无评论
这样才是代码管理和 Commit 的正确姿势! | 研发效能提升36计