Monolithic Repos Are Evil

The following text is a partial translation of the original English article, performed by ChatGPT (gpt-3.5-turbo) and this Jekyll plugin:

我们都将我们的代码存放在Git仓库中。问题是,我们是否应该为每个新模块创建一个新的仓库,或者尽可能将所有内容放在一个所谓的“单体”仓库(或简称为“单体仓库”)中。像Facebook和Google这样的市场领导者主张采用第二种方法。我认为他们是错的。

让我们以以下JavaScript函数作为例子。它从Zold节点(使用jQuery)下载一个JSON文档,并将其内容的一部分放置在HTML页面上。然后,根据其值对数据进行着色。

相当明显,不是吗?只需要一个main.js文件,它可以完成我们所需的一切。我们只需将其添加到HTML中,它就能正常工作。

现在,让我进行重构。我将把它分为两部分。第一部分将加载数据,第二部分将是一个jQuery插件,根据其包含的数据对HTML内容进行着色。这就是插件的外观。

main.js 将会是这样的:

现在,不再是一个庞大的代码块,而是两个较小的代码块,它们必须一起加载到目标HTML中。

两个比一个更好吗?看起来GoogleDigital OceanMozilla并不这么认为。

为了说明我的观点,我将JavaScript函数提取到一个新的独立的jQuery插件中。我所做的如下:

  • 阅读说明

  • 研究了一些jQuery插件,学习了几个示例;

  • 发现大多数人使用Gulp,这是我从未听说过的东西;

  • 决定使用npm来进行JavaScript打包(当然啦,还有其他选择吗?);

  • 为npm创建了package.json

  • 当我发现npm包colorize已经存在时,我将GitHub仓库更名为colorizejs

  • 配置了.travis.yml文件以供Travis使用;

  • 创建了一个 README.md 文件,解释了如何使用和安装它;

  • 决定采用MIT许可证并创建了LICENSE.txt

  • 配置了PDD,以进行自动收集谜题;

  • 配置了 .rultor.yml 以供 Rultor 使用;

  • 尝试创建一个单元测试,但失败得很惨(经过整整一个小时的研究),因为我在JS单元测试方面几乎没有经验。

  • 在Stack Overflow上发布了一个问题

  • 仅有少数人在我提供赏金之后回答了这个问题。

  • @brian-lives-outdoors的答案是最好的,他甚至提交了一个包含单元测试的拉取请求,我已合并;

  • 发布了第一个版本0.0.1npmjs.com

  • 修改了代码,使其可以同时适用于类和颜色。

  • Implemented and released the next version 0.1.0;

实施并发布了下一个版本0.1.0;

  • 添加 到 Zold 前端,测试并发布了——在这里查看。

花了将近三个星期的等待和四个小时的工作,只是为了将一小段JavaScript代码移到一个新的存储库并单独发布。这样做值得吗?嗯,我认为是的。但是大多数其他我找到的博客文章作者都认为,将所有东西都保留在一个庞大的存储库中会更好,主要是因为这样对生产力更有利。例如,monorepos的优势Dan Luu撰写,单体存储库的优缺点(Google的一个案例研究)由Ciera Jaspan等人撰写,以及Tomas Votruba的开源中单体存储库如何拯救了我的懒惰由Tomas Votruba撰写。

还有一些关于两种方法的良好分析,例如Fabien Potencier在dotScale 2016的演讲单体存储库与多个存储库和Peter Seibel的Repo Style Wars:Mono vs Multi

简而言之,他们都声称,单体存储库的生产力更高,因为进行更改所需的操作数量较少。确实,在单体存储库中,将会有一个分支,一组提交,一个拉取请求,一个合并,部署和发布。同时,它将更容易进行手动和单元测试。连续集成更容易配置,依此类推。

所有这些“合理”的论点让我想起了当我宣扬对象分解并建议多个对象比一个大对象更好时听到的东西。想象一下一个有3000行代码的大类,它做很多事情,而且它们都非常紧密耦合。测试、进行更改、部署、审查等都很“容易”。因为一切都在一个文件中,对吧?我们不需要从一个类跳到另一个类来理解设计。我们只需要看一个屏幕,上下滚动,就可以了。对吧?完全错误!

我想我不需要解释为什么这是错误的。我们不再以这种方式设计软件。我们知道紧密耦合是一个坏主意。我们知道一组较小的组件比一个较大的整体更好。

为什么我们不能将相同的逻辑应用于存储库?我相信我们可以。当然,就像面向对象编程一样,细粒度的设计需要更多的技能和时间。看看我为这个小的jQuery插件所做的工作。我花了数小时编码和思考。我甚至不可能再使用GulpJasmine。但是我们从中获得的好处是巨大的。这是我列出的一些好处:

  • 快速构建。当一个仓库很小的时候,自动化构建所需的时间也很短。看一下 Travis 花费 在我的 jQuery 插件上的时间。只有 51 秒。速度很快。我们都知道,构建速度越快,对于生产力就越有利,因为使用构建作为开发工具会更加容易。

  • 准确的度量标准。我不知道你在项目中是否依赖于度量标准,但我们在Zerocracy确实关注数字,比如代码行数、代码命中次数、提交次数、类、方法、内聚性、耦合性等等。度量标准的准确性始终是个问题。计算大型代码库的代码行数没有任何意义,因为这个数字将包含完全不同部分的大量文件。而且还会涉及不同的编程语言和文件格式。假设一个库有20万行Java代码,15万行XML代码,5万行JavaScript代码和4万行Ruby代码。你能对这个库说出具体的信息吗?它是大型库吗?它是一个Java库吗?更重要的是,它能与其他代码库进行比较吗?实际上不能。它只是一个杂乱无章的文件存储库。

  • 同质任务。较小的代码库往往拥有较小的技术栈,意味着每个代码库只使用少量的语言和框架,或者(这是首选情况)—每个代码库只使用一种语言或技术。由于这一点,程序员的管理变得更加容易,因为任何工单/问题都可以分配给任何人。更容易使任务在大小和复杂度上保持一致。这显然意味着项目的可管理性更好。

  • 单一编码标准。如果仓库规模较小,更容易统一编码风格。当规模较大时,代码库的各个部分将会有不同的风格,要使所有人达成一致几乎是不可能的。换句话说,较小的代码库看起来比较美观。

  • 简短名称。每个仓库都会有自己的命名空间。例如,在我刚创建的JS仓库中,我只有两个文件:colorizejs.jstest-colorizejs.js。我对它们内部的命名并不在意,因为命名空间很小。我甚至可以使用全局变量。 更短的名称和较小的命名空间意味着更好的可维护性。

  • 简单测试。代码库越大,其依赖关系就越多,很难进行模拟和测试。非常大的代码库因为需要大量难以维护的集成测试而变得基本上无法测试。较小的库、框架和模块更容易保持在简单和快速单元测试的水平上。

因此,我相信存储库和模块越小越好。理想情况下,我会说,代码库的最大可接受大小是50,000行代码。超过这个界限的所有内容都是进行分解的完美候选项。

Translated by ChatGPT gpt-3.5-turbo/42 on 2023-12-15 at 07:04

sixnines availability badge   GitHub stars