编者按:作为阿里数据中台的核心产品,Quick BI 单一代码仓库源码已经突破了 100万行,正在向1000万行迈进。本文重点分享了单一代码仓库Monorepo选用前的思考,以及具体应用中的开发体验和经验。内容转载自「Alibaba F2E」。

近年来,阿里数据中台产品发展迅速。核心产品之 Quick BI 连续 2 年成为国内唯一入选 Gartner 魔力象限的国产 BI。Quick BI 单一代码仓库源码突破了 100万行。整个开发过程涉及到的人员和模块都很多,因为下文讲的一些原则,产品能一直保持在快速的开发状态。
先分享几个关键数据:

代码:TypeScript 82万行,样式 Sass+Less+CSS 18万行。(cloc 统计,去除自动生成代码)

协同:Code Review 12,111 次,Commit 53,026 次。

很多人会问,这么多代码,为什么不切分代码库?还不赶快引入微前端、Serverless 框架?你们就不担心无法维护,启动龟速吗?
实际情况是,从第一天开始,就预估到会有这么大的代码量。启动时间也从最初的几秒钟到后面越来越慢5~10分钟,再优化到近期的5秒钟。整个过程下来,团队更感受到 Monorepo(单一代码仓库)的优势。

这个实践想说明:

大的 Codebase 可能是好事情,大道至简。用极其“简单”的架构更容易支持复杂灵活的业务

要做到简单的架构,内部需要更明确的规范,更密切的协同,更高效的执行

能通过工程化解决的问题,就不要通过开发规范,能通过规范来解决的不要靠自由发挥

开工

2019年4月30号,晴朗的下午,刚好是喜迎五一的前一天,发挥集体智慧,投票选出满意的仓库名。同时借 Quick BI 和 FBI 底座融合的契机,项目开启。后来底座代码转正,把上层业务代码也吸纳进来。

commit 769bf68c1740631b39dca6931a19a5e1692be48d
Date:   Tue Apr 30 17:48:52 2019 +0800A New Era of BI Begins

Why Monorepo?

在开工之前,对单一仓库(Monorepo)和多仓库(Polyrepo)团队内做了很多的讨论。
曾经我也很喜欢 Polyrepo,为每个组件建立独立 repo 独立 npm,比如2019年前,单是表单类的编辑器组件就有 43 个:

本以为这样可以做到完美的解耦、极致的复用,但实际上:
每次 Babel、React 等依赖整体升级能让人脱层皮,所以自研了脚手架。造轮子都是被逼出来的,事情做了一点点,但写脚本能力直线上升。

每次 调试组件,npm link 一下。后来组件跨级,可以做 3 层 npm link,使用过的都知道这是多么糟糕的体验。

版本难对齐,每次主仓库发布前,组件间版本对齐更是考验眼力,稍有不慎触发线上故障。

方便别人复用的优势呢?最终支持自己业务都捉襟见肘,哪还敢让别人复用……

最终我们把所有这些组件都合并到一个仓库,其实像 Google/Facebook/Microsoft 这些公司内部都很推崇 Monorepo。

但我们不是原教旨主义的 Monorepo,没必要把不相关的产品代码硬放到一起。在实线团队内部,单个产品可以使用 Monorepo,会极大降低协同成本。但开始的时候,团队内还是有很多疑问。

关于 Monorepo 的几个核心疑问

单一仓库,体积会很大吧?
100 万行代码 的体积有多大?

先来猜一下:1GB?10GB?还是更多?

首先,按照公式计算一下:

代码的体积 = 源码的体积 + .git 的体积 + 资源文件(音视频、图片、其他文件)

  1. 我们一起来算一下源码的体积:

一般建议每行小于 120 字符,我们取每行 100 个字符来算,100 万行就是:

100 * 1000,000 = 100,000,000 B
转换之后就是 100 MB!

那我们的仓库实际多大呢?

只有 85 MB!也就是平均每行 85 个字符。

  1. 再来算一下 .git的体积:

.git里记录了所有代码的提交历史、branch 和 tag 信息。会很大体积吧?

实际上 Git 底层做了很多的优化:1. 所有 branch 和 tag 都是引用;2. 对变更是增量存储;3. 变更对象存储的时候会使用 zlib 压缩。(对于重复出现的样板代码只会存储一次,对于规范化的代码压缩比例极高)。

按照我们的经验,.git记录 10,000 次 commit 提交只需要额外的 1~3 个代码体积即可。

  1. 资源文件大小

Git 做了很多针对源码的优化,但视频和音频这类资源文件除外。我们最近使用 BFG 把另一个产品的仓库从 22GB 优化到 200MB,降低 99%!而且优化后代码的提交历史和分支都得到了保留(因为 BFG 会编辑 Git 提交记录,部分 commit id 会变化)。

以前 22 GB 是因为仓库里存放视频、发布的 build 文件和 sourcemap 文件,这些都不应该放到源码仓库。

小结一下,百万行代码体积一般在 200MB ~ 400MB 之间。那来估算下 1000 万行代码占用体积是多少?

乘以十也就是 2GB ~ 4GB 之间。这对比 node_modules随随便便几个 G 来说,并不算什么,很容易管理。补充个案例,Linux 内核有 2800 万行,使用 Monorepo,数千人协同。据说当时 Linus 就是为了管理 Linux 的源码而开发出 Git。

启动很慢吧?5分钟还是10分钟?
听到有些团队讲,代码十几万行,启动 10+分钟,典型的“巨石”项目,已经很难维护了。赶紧拆包、或者改微前端。可能团队才 3 个人却拆了 5 个项目,协同起来非常麻烦。

我们做法有3个:

按照页面来拆分多 Entry,每次只需启动一个 Entry

梳理子包间的依赖关系,追求极致的 Lazy loading,Tree-Shaking

Webpack 切换到 Vite

尤其是 Webpack 切换到 Vite 以后,最终项目冷启动时间由 2-5分钟 优化到 5秒 内。热编译时间由原来 5秒 优化到 1秒 内,Apple M1 电脑基本都是 500ms 以内。

代码复用怎么办?Monorepo 复用的时候是否要引入全部?
传统的软件工程思想追求 DRY,但并不是越 DRY 越好。

每写一行代码,都产生了相应代价:维护的成本。为了减少代码,我们有了可复用的模块。但是代码复用有一个问题:当你以后想要修改的时候它就会成为一个障碍。

对于像 Quick BI 这样长期迭代的产品,绝大部分需求都是对原有功能的扩展,所以写出易维护的代码最重要。因此,团队不鼓励使用 magic 的特技写法;不单纯追求代码复用率,而是追求更易于修改;鼓励在未来模块下线的时候易于删除的编码方式。

对于确实存在复用的场景,我们做了拆包。Monorepo 内部我们拆了多个 package(后面有截图),比如其他产品需要 BI 搭建,可以复用 @alife/bi-designer,并借助于 Tree-Shaking 做到依赖引入的最小化。

目前的开发体验

  1. 冷启动 5秒,热编译 1秒内。以前是 5~10分钟。

  2. 改一行代码能解决的问题,真正改一行且发布一次。而不是改 10+ 个项目,按依赖发布 N 次。

  3. 新人 10分钟搭建好环境,上手开发。以前每个组件一个 Repo,包赋权都要搞很久。

  4. 避免了版本不对齐的问题

对于 2C 产品,不需要多版本多主干分支,但多个 npm 依赖对齐版本也不容易

对于 2B 产品,由于多环境、多版本,会更加复杂,复杂度极高。Monorepo 通过分支来统一内部依赖的版本

  1. 工程化升级只需要一次。目前是基于 Lerna 开发的 Pri Monorepo 方案。

当然,这里提及的体验要保持并不容易,开发中还有很多问题要解决。

真正需要解决的问题

并不是把代码放到一起就完了,背后复杂的问题是协同、技术方案、稳定性。比如,如何避免一个人提交代码导致整个产品崩溃?

包依赖管理
内部拆分多个子包,每个子包是子文件,可以单独发布 npm,见下图:

内部包管理的核心原则是:

从左向右单向依赖,只能右边引用左边,避免循环依赖

规范还不够,开发插件来自动检测,如果左边依赖右边直接报错

对于开源 npm 的引入,应该更慎重。大部分 npm 的维护时长不超过x年,即使像 Moment.js 这样曾经标配的工具库也会终止维护。可能有 20% 的 npm 是没人维护。但未来如果你的线上用户遇到问题,你就需要靠自己啃源码,陷入被动。所以我们的原则是,引入开源 npm 要三人线下评审通过才行。

Code Review 文化
互相 Code Review 能帮助新人快速成长,同时也是打造团队技术文化的方式。

过去几年一直在团队内推行 100% CR,但这还不够。机械的执行很容易把 CR 流于形式,还要分场景来做。

Monorepo 有个风险是一旦有问题就可能是整体的问题。

目前我们的 Code Review 主要分为3个场景:

线上 MR Code Review【1对1】

主题式 Code Review【3-5个人】

大版本发布前集体 Code Review【All】

12,111 次 Code Review 的经验很多,主要是:

及时 Review,鼓励小颗粒度的 MR,不必等整个功能开发完成

代码是写给人看的,鼓励白话文一样的代码,而不是文言文

建立最佳实践(目录树结构、命名规范、数据流规范)。开发一个功能可以有 10 种方法,但团队需要选 1 种并推广

不鼓励炫技,为了未来可维护性。能用简单技术实现,不要用“高深”冷门的技术

强调开发洁癖,追求优雅代码的文化(命名是否易于理解、注释是否完整、是否有性能隐患等)

工程化建设
这个过程首先要感谢淘系前端 DEF 工程化团队的支持,在这么多代码的情况下,不断挑战极限升级 DEF 支持我们。

除了制定文档的规范之外,能够自动化工具检查的规范才是好规范。

检查器:ESLint、TS 类型校验、Prettier
语法检查器是推动规范落地的重要方法,ESLint 可以做增量,优化后 git commit 的 pre-hooks 依旧很快。但 TS type check 因为不支持增量就比较慢了,需要搭配 CI/CD 来使用。

Webpack vs Vite
发布使用 Webpack,开发使用 Vite。

开发环境使用 Vite 快速调试,生产环境依旧使用 Webpack 打包。

风险是开发和生产编译产物不一致,这一块需要上线前回归测试避免。

性能优化
对于数据产品而言,性能的挑战除了来自于 Monorepo 后资源包的变大,还有大数据量对渲染计算带来的挑战。

性能优化可以分为3个环节:

资源加载:精细化 Tree Shaking,难在精细。Webpack 本身的 Tree-Shaking 做的并不好,不支持 Class method 做 Tree Shaking,所以有时候需要修改代码。Lazy Loading 模块做到按需加载,尤其是图表、SQL 编辑器这类大组件。合理的接口预加载,不要让网络闲下来。

视图渲染:让组件渲染次数降到最低,表格类组件虚拟滚动优化,闲时预加载预渲染。

取数请求:资源本地化缓冲方案,移动端使用 PWA 将 JS 等资源文件和数据缓存到本地。

另外还有性能检测工具,定位性能卡点。计划做代码性能门闩,代码提交前如果发现包体积增大发出提醒。

数据化驱动架构优化
身在数据中台,我对数据的业务价值深信不疑。但对于开发本身而言,很少深度使用过数据。

所以 S1 重点探索了开发体验的数字化。通过采集大家的开发环境和启动耗时数据来做分析【不统计其他数据避免内卷】。发现很多有意思的事情,比如有个同学热编译 3~5 分钟,他以为别人也是这样慢,严重影响了开发效率,当从报表发现数据异常后十分钟帮他解决。

另外一个例子,为了保持线上打包产物的一致性,推动团队做 Node.js 版本统一,以前都是靠钉,钉多少次都无法知道效果如何。有了报表以后就一目了然。

目前整个数据化的流程跑通,初步尝到甜头。未来还有很多好玩的分析可以做。

更深层的经验

效率最高的方式就是一次做好
每行代码都会留下成本。长远考虑,效率最高的方法就是一次做好。

苏世民说“做大事和做小事的难度是一样的,两者都会消耗你的时间和精力。”既然如此,不妨把代码一次写好。代码中如果遗留 “TODO” 可能就永远 TO DO。客观来讲,一次做好比较难,首先是每个人认为的“好”标准不同,背后是个人的技术能力、体验的追求、业务的理解。

组织文化技术,相辅相成
技术架构和组织结构有很大关系,选择适合组织的技术架构更重要。

如果一个组织是分散的,使用 Monorepo 会有很大的协同成本。但组织如果是内聚的,Monorepo 能极大提效。

工程化和架构底座是团队的事情,靠个人很难去推动。

短期可以靠战役靠照搬,长期要形成文化才能持续迭代。

组织沟通成本高应该通过组织来解,通过技术来解的力量是渺小的。技术可以做的是充分发挥工具的优势,让变化快速发生。

简单不先于复杂,而是在复杂之后
对于一个简单的架构,总有人会想办法把它做复杂。踩了坑,下决心重构,成功则回归简单,失败就会被新的简单模式颠覆。踩坑本身也是有价值的,不然新人总是按捺不住还会再踩一次。做复杂很容易,但保持简单需要远见和克制。没有经历过过程的磨练,别人的解药对你可能是毒药。

架构不可能一成不变的,我们的图表最开始直接使用 D3、ECharts 很简单,后来定制很多逐渐复杂到难以维护,于是基于 G2 自研 bi-charts 后架构又一次变简单,前后的开发体验可能是差不多的,但背后的技术完全变了。

总结与展望

百万行代码没什么可怕,是一个正常的节点,仍然可以像几万行代码那样敏捷。

现在 Quick BI 已经向千万行迈进,向世界一流 BI 的目标迈进。以上内容更多是工程化相关,把工程化做好目的是想让开发者更专注于业务,没讲的业务挑战其实更多,因为数据分析天生就要与海量数据打交道,性能优化有长期的实践;洞察丰富异样的数据,有很多可视化及复杂表格方面的沉淀,可视化不仅是技术,也是业务本身;手机平板电视等多端展示,跨端适配的挑战。

未来还希望能够把数据分析打造成一个引擎,能够快速集成到办公和商业流程中。

目前的开发模式并不完美,在迭代的过程中,不可避免会产生技术债,架构的优化本质就是在保持可维护性和减少技术债。最近团队在酝酿一次 Redux-Toolkit 的引入,会对取数和数据流有大的升级,有进展再分享。(完)
阿里数据中台核心产品揭秘

阿里数据中台核心产品揭秘相关推荐

  1. 阿里数据中台建设之道,阿里专家10张图从理念到实践,干货解读!

    文| 技术领导力社区 编辑| Emma 阿里数据中台建设过程.方法论.主要核心的产品.技术架构等等,对技术圈来说一直非常神秘.并且,阿里已经将中台建设方法论形成了解决方案,向行业输出,这也导致了阿里中 ...

  2. 全面分析阿里数据中台,小白也能看懂 | CSDN原力计划

    扫码参与CSDN"原力计划" 作者 | yuanziok 来源 | CSDN原力计划获奖作品 数据中台被誉为大数据的下一站,由阿里兴起,核心思想是数据共享,2015年阿里提出&qu ...

  3. 直面最大挑战双11 阿里数据中台为商家带来确定性保障

    2020双11将成为史上最具科技含量的一届双11. 11月3日,在阿里巴巴双11技术沟通会上,阿里巴巴集团首席技术官程立公布了大规模运用于2020双11的十大前沿技术,既有基于数字技术的原生商业创新, ...

  4. 阿里数据总监分享《阿里数据中台建设实践案例》,PPT+语音讲解!

    戳蓝字"CSDN云计算"关注我们哦! 作者 |  技术领导力 责编 | 阿秃 本文整理自,阿里巴巴集团数据部商业应用总监列文,在"2019年阿里云(上海)峰会" ...

  5. 阿里数据中台大火,国外却在建设数据湖,这两者什么关系?

    不知道大家有没有发现,这几年的数据领域有好多的概念,例如:大数据.人工智能.物联网.边缘计算.数据治理.数据湖.数据中台.数据可视化--.这说明数据这个领域真的很"火",可谓是&q ...

  6. 很简单能看懂阿里数据中台分析

    数据中台被誉为大数据的下一站,由阿里兴起,核心思想是数据共享,2015年阿里提出"大中台,小前台"的策略.2018 年因为"腾讯数据中台论",中台再度成为了人们 ...

  7. 阿里数据中台底座的12年建设实践

    阿里巴巴数据平台发展的四大阶段 构建数据中台,一个强大的数据平台作为底座必不可少. 阿里巴巴数据平台发展的四个阶段,一定程度上其实也是阿里巴巴数据中台发展的四个阶段.这四个阶段里,你可以看到阿里巴巴对 ...

  8. 阿里数据中台OneID核心能力之ID-Mapping

    这篇文章是我的一个好友彭文华彭总写的, ID Mapping是阿里巴巴数据中台的核心能力之一.欢迎大家添加彭总微信:shirenpengwh ,一起探讨大数据相关技术. 网上  ID Mapping ...

  9. 企业中台最佳实践--阿里数据中台解读(十二)

    数据中台被誉为大数据的下一站,由阿里兴起,核心思想是数据共享,2015年阿里提出"大中台,小前台"的策略.2018 年因为"腾讯数据中台论",中台再度成为了人们 ...

  10. 企业中台最佳实践--阿里数据中台最佳实践(九)

    阿里业务中台架构图 基础设施服务,即IAAS层,提供硬件底层支持. 基础服务层,即PAAS层,包括分布式服务框架.分布式数据库.分布式消息.分布式存储.分布式事务.实时监控服务等等. 互联网业务中台, ...

最新文章

  1. 排版 项目 html,项目需求讨论: 文字显示排版— Html 格式
  2. Java Private、protected、public、以及无修饰符的可见范围
  3. 网站图片优化的小技巧分享
  4. officeopenxml excelpackage 需要安装excel嘛_使用ABAP操作Excel的几种方法
  5. javascript高程3 学习笔记(二)
  6. 信息学奥赛一本通(1021:打印字符)
  7. 三组划分//巧妙填数
  8. 在Windows系统中用nginx与mono搭建asp.net运行环境,附详细例图与代码
  9. Android性能全面分析与优化方案研究—几乎是史上最全最实用的
  10. 测试tf卡读写速度软件,U盘测速图文教程,优盘读写速度测试,移动硬盘TF卡SD内存卡测速...
  11. txt文本阅读器 html,TxT小说阅读器(TxTReader)
  12. (八)office2016-excel绘制斜线表头 双斜线和三斜线
  13. SQL Server select 英文区分大小写
  14. FC-SAN存储技术
  15. 弘辽科技:胡润研究院发布《2020胡润中国10强电商》榜单,第二名很意外
  16. Java分割PDF文件(itextpdf)
  17. vue 路由嵌套(二级路由)
  18. 移动端页面性能优化方案
  19. 杂七杂八,乱七八糟的大杂烩!
  20. 数字图像处理——第二章(数字图像基础)

热门文章

  1. 64位Oracle 11g 使用PL/SQL
  2. 微软2011年10月最有价值专家(MVP)名单 51CTO十三位用户当选
  3. 空间数据库学习笔记(四):空间引用标识符(SRID)
  4. Mybatis-学习笔记(3)mapper配置文件
  5. 面向对象课程第一次博客总结
  6. C++ 日期 时间
  7. 自动摘要学习计划(英语)
  8. java-线程同步问题
  9. 实验假设与分析方法(参数与非参检验)
  10. Atitit 数据库 负载均衡 方法总结 目录 1. 对称模型负载均衡 vs 非对称模型 2 1.1. 业务分离法 2 1.2. App + db分布式分离法 2 2. 负载均衡算法 2 2.1.