原副标题:从Ruby到Node:改写Shopify CLI,提高合作开发新体验
译者 | Pedro Piñera
翻译者 | 武川
策画 | Tina
责任编辑起初发布于 Shopify 工程建设网志。
Shopify CLI(配置文件介面)是合作开发者在 Shopify 网络平台上构筑和布署 Theme、App、Hydrogen 门店时的重要辅助工具。它提供更多了按照最差课堂教学建立新项目的工作流,实现了与合作开发网络平台的软件系统,并能将产品钻孔分发送给店家。我的项目组,即 CLI Foundations,负责管理为结构设计和构筑 Shopify CLI 的最差课堂教学和核心理念机能长远目标。他们知道,合作开发者在合作开发 Shopify App 时能大量加进终端产品,而他们采用 CLI 时并不常常能够获完全一致而融洽的新体验。因此,他们已经开始采用 Node 全盘改写 Shopify CLI 2(那原先是用 Ruby 撰写的),并在今年冬天面世了 Shopify Editions。在这篇昌明中,我将如是说下他们项目组以后为何作出了改写的重大决策和当时所做的取舍,他们在那个捷伊插值中所遵从的准则,和他们先期要消除的考验和积极探索的设想。
词汇重大决策简述
在 Shopify CLI 以后,Theme 合作开发者用的是他们的另两个 CLI——ThemeKit。他们从 2014 年 10 月就已经开始保护它。它是用 Ruby 撰写的,如前所述他们在外部 CLI 和服务项目中采用的一些 Ruby gems 构筑,譬如 cli-kit、cli-ui 和 theme-check 等。
当他们在 2018 年 12 月已经开始合作开发第两个 Shopify CLI 来协助 App 合作开发者时,考虑到他们已近的 Ruby 天然资源和科学知识,选择 Ruby 是合情合理的。使用者需要两个自上而下的 Ruby 加装就可以采用 CLI,但他们通过为大部份受支持的作业系统(Windows、Linux 和 macOS)提供更多旧版本化解了那个问题。2020 年 12 月,他们将 ThemeKit 分拆到 Shopify CLI 中,迈进了将大部份合作开发集中在两个 CLI 中的第二步。
2020 年 6 月,他们加进了 UI 扩充,让合作开发者能采用自己的 UI 扩充网络平台的某些区域,CLI 已经开始依赖 Node 辅助工具来转译和打包扩充代码。系统要求越来越高,这不是使用者所希望的。不过,生态系统正朝着用编译式词汇(如 Go 和 Rust)实现 Java 辅助工具的方向发展,因此他们希望能摆脱对 Node 的依赖。但这种事情并没有发生。尽管像 ESBuild 这样的辅助工具(他们用于打包扩充)是可移植的二进制文件,但它们的可扩充性依赖于在 Node 运行时上动态求值的插件。
此外,Hydrogen 项目组已经在 Node 上构筑了一些辅助工具,他们已经开始考虑构筑两个捷伊 CLI,而不是将 Hydrogen 工作流构筑到 Shopify Ruby CLI 中,这样他们的使用者就不需要在自己的系统中加装 Ruby 运行时。Hydrogen 合作开发者希望 npm install 命令能够解析他们在项目中需要的大部份依赖项。如果将 Ruby 作为两个依赖项,这种思维模式就会被打破,他们就很容易遇到 CLI 因为需要额外的步骤而拒绝运行的问题。另建两个 CLI 会破坏他们始于将 ThemeKit 分拆到 CLI 的统一工作。这可能会导致网络平台不同区域的 CLI 新体验不完全一致。
最后但同样重要的是,Shopify 越来越依赖于 Web 技术和标准,其中 Java 和 Node 运行时在天然资源、辅助工具和科学知识方面更有优势。
大部份这些都促使他们思考 Ruby 是否是最适合 CLI 的词汇,所以他们简述了那个重大决策。他们需要一种技术:
系统要求尽可能少(例如,不需要加装多个运行时); 让他们能够提供更多一流的合作开发新体验; 外部项目组很容易作出贡献。最终,他们决定用 Type 改写 CLI,以便在 Node 运行时上运行。
从 Ruby 迁移到 Node
在 Shopify 采用的大部份编程词汇中,Ruby 是大多数合作开发者都熟悉的词汇,其次是 Node、Go 和 Rust。采用它们都可以构筑出一流的合作开发新体验,这要归功于生态系统提供更多的丰富软件包化解了常见的问题。从这些选项中,Go 和 Rust 都能轻松地发布运行时不依赖运行时的静态二进制文件。这一点,Node 和 Ruby 也能通过将源代码和运行时依赖项(又名 vendoring)打包在一起来实现,但设置更复杂,并且可能有一些作业系统不支持。
他们选择 Node 有几个原因。Go 和 Rust 允许分发静态二进制文件,但代价是 Shopify 的人由于不熟悉词汇很少能作出贡献。这并不理想,因为 Shopify 希望外部项目组能为 CLI 贡献捷伊设想。他们只能选择 Ruby 或 Node。
在构筑 CLI 方面,Node 有两个与 Ruby 不同的特性:它的模块系统和它所支持的可扩充性。与 Ruby 不同,Node 的模块系统允许同两个传递包有多个版本,而且不会相互冲突。这就让他们能构筑两个模块化的架构,将网络平台的不同功能域封装在 NPM 包中,而它们都如前所述两个包含共享机能的包构筑。需要注意的是,虽然 Hydrogen 和 App 合作开发者只需要两个运行时(Node),但 Theme 合作开发者现在还需要两个:Ruby 和 Node。不过,他们已经已经开始着手消除 Ruby 依赖,他们的目标是在今年晚些时候完成这项工作。
构筑卓越的终端产品新体验
他们作出了技术重大决策,但他们还得做一些最差课堂教学、代码架构、模式和约定方面的重大决策。这是对他们从不同项目组习得的经验和他们构筑 Ruby CLI 的经验的一次综合运用。我将与大家分享他们在构筑卓越的终端产品新体验的过程中对他们影响最大的 7 个决定。
1. 为实现完全一致性奠定基础
Ruby CLI 的贡献完全一致性较差,而且是松耦合的(与他们所期望的高度完全一致的松耦合状态相反),导致内外部分化,进而导致了糟糕的新体验。在 Node 版本中,他们必须做一些不同的事情。他们需要一种方法来使贡献保持完全一致。他们通过:
代码模式 :建模命令的业务逻辑。在如前所述框架(如 Rails)的项目中,框架(如 MVC)通常会支持这些模式,但他们没有框架。因此,他们必须合作开发自己的模式和机制,并保证合作开发者遵从它们。 UI 模式和组件 :他们在 Ink 上结构设计并构筑了两个结构设计系统,以确保大部份命令的新体验都和 Shopify 类似。 约定 :便于合作开发者浏览他们的项目和命令。 准则 :创造卓越的新体验,助力合作开发者取得成功。上述内容体现在两个共享 NPM 包 @shopify/cli-kit 中,大部份机能域(Theme、App 和 Hydrogen)都以它为基础构筑,还有一套通用的准则,用于 CLI 和任何与网络平台合作开发者交互的介面(例如,文档和合作伙伴仪表板)。像 ESLint 这样的静态分析辅助工具成为他们构筑自动化的网络平台,用于保证贡献与 CLI 的基础和方向相完全一致。他们实现了像 command-flags-with-env 这样的自定义规则,以支持通过环境变量设置命令标志。
。
constsession = awaitensureAuthenticatedAdmin(storeFQDN)文件 idiomatic_API_example.js,托管在 GitHub 上
2. 确保支持跨作业系统
在 MacOS 环境中合作开发时,确保代码更改支持 macOS、Windows 和 Linux 是两个繁琐的过程,会导致测试被跳过并出现回归。Node 运行时能使问题加剧,因为已知有些 API 在不同作业系统上的行为不完全一致。社区正在用 NPM 包消除这些问题。例如,pathe 规范了跨作业系统的路径。为了防止同样的事情再次发生,他们采取了三个策略:
他们在 @shopify/cli-kit 中提供更多了环境交互(如 IO 操作)模块,并确保它们的 API 跨作业系统兼容。如果他们检测到作业系统不兼容的情况,就会一次性修复它。 他们的测试套件混合了单元测试、软件系统测试和端到端(E2E)测试,这些测试通过持续软件系统(CI)在大部份支持的作业系统上运行。它会在分拆前在 PR 中暴露问题。他们为与环境存在契约关系的模块(如提供更多 Git 交互实用辅助工具的模块)撰写软件系统测试。 他们提供更多了在 MacOS、Linux 和 Windows 环境中测试更改的指令。3. 迁移到 Monorepo
Conway 定律在他们的组织中得到了体现,他们的存储库中包含了 CLI 的不同组件(如模板和外部 CLI)。Multirepo 设置不会给使用者带来什么价值,却使得外部贡献和自动化测试更加麻烦。他们决定以改写为契机改变这种局面,将大部份组件放入同两个存储库 shopify/cli 中。Monorepo 设置允许跨多个包和模板原子地贡献更改。
4. 拥抱函数式编程
Ruby CLI 命令的业务逻辑是有状态的,有许多假设,并且在命令生命周期中会产生多种副作用。这增加了代码推理、贡献和测试的难度。对于 Node CLI,他们采用了不同的方法。
他们在逻辑结构设计时尽可能地函数化,并且只要可能,就将副作用集中在命令已经开始的部分。例如,命令所做的第一件事是在内存中加载和验证项目。这类似于 Web API 在接收请求时所做的事情;在将其传递到可能产生级联效应且处于无效状态的系统以后,它将对其进行验证。他们对函数范式的运用并不是教条式的,但他们的目标是把逻辑变成传递状态的函数的组合。
他们采用 Java 对象和函数作为组合单元。他们默认建立对象的副本,而不是改变传递的实例。只有少数情况下,为了符合词汇要求,他们才诉诸于类,如错误类型。他们引入了两个与函数组织有关的软约定,类似于模型 – 视图 – 控制器(MVC)架构模式:
模型(Model) :是用来对状态建模的 Type 接口,例如 App 项目、项目配置和会话的外部表示。 命令(View) :是使用者进行交互的介面,使用者在调用 CLI 时能传递参数和标志。它们的职责仅限于解析和验证参数及标志,并提供更多协助菜单的内容。 服务项目(Controller) :是业务逻辑的封装单元。大部份命令都有两个包含命令业务逻辑的服务项目,有些服务项目没有绑定到特定的命令。除了上面提到的,他们还有提示符,它包含通过标准输入提示使用者的函数,和将一组函数分组到特定域的实用程序。两个例子是与 Shopify GraphQL API 交互的大部份函数。
5. 实现端到端测试策略
采用函数式编程和最小化副作用简化了单元测试的撰写。为了定义和运行它们,他们采用了 Vitest,它在他们已经开始合作开发 Node CLI 前数周才刚刚发布。他们决定采用 Vitest,因为它完全支持 ES 模块(他们采用的模块系统)。尽管在辅助工具成熟的过程中,起初会有一些问题,但他们对它提供更多的新体验和与 Jest API 一对一的映射感到满意。
单元测试给了他们信心,相信他们的函数在不同的场景中完成了它们应该做的事,但这还不够——单元测试套件成功运行的结果并不意味着像“app build”这样的工作流在最近建立的项目中成功运行。因此,他们决定投资两个采用 Cucumber 的端到端测试套件,以确保各种工作流可以端到端工作。Cucumber 为他们提供更多了描述、运行和调试这些测试的辅助工具和 API。你可能知道的,E2E 以保护麻烦和可能引入古怪行为而闻名。不过,在 CLI 中不会那样,因为这里的设置更简单。执行能隔离,并将范围限定在测试场景中,防止自上而下状态泄漏到其他测试中导致它们表现异常。下面是他们的两个测试示例:
Scenario: I createandbuildan app withextensions Given Icreatean app named MyTestApp withpnpm asthe packagemanager AndI createan extension named TestPurchaseExtensionoftypepost_purchase_ui WhenI buildthe app The The extensions arebuilt文件 example_test_gherkin.txt,托管在 GitHub 上
6. 利用 Type
Type 的类型系统和编译器让他们能相信,代码单元和外部依赖关系之间的契约是匹配的。CLI 依赖的许多 NPM 包和 @shopify/cli-kit 中提供更多的模块提供更多了类型定义,极大地改善了对存储库做贡献的新体验。例如,他们正在实现两个为 CLI 结构设计的新结构设计系统的组件,他们广泛采用 Type 来确保合作开发者以正确的方式采用组件。
7. 构筑经过社区测试的基础
在早先一次与 Shopify 之外的 CLI 合作开发者的对话中,oclif 作为两个出色的、采用 Node 构筑 CLI 的辅助工具和 API 框架出现在他们的视野中。例如,它诞生于 Heroku 的 CLI,用于支持其他 CLI 的合作开发。在决定采用 Node 之后,他们更全盘地研究了 oclif 的特性集,构筑了小型原型,并决定如前所述它们的 API、约定和生态系统构筑 Node CLI。事后看来,这是个好主意。
Oclif 为他们提供更多了用于声明 CLI 接口的惯用 API,并提供更多了出色的默认值自定义机能。例如,协助文档是从代码内的声明自动生成的。此外,它还通过插件系统内置提供更多了可扩充性,他们已经利用插件合作开发了 App、Theme 和 Hydrogen。它允许他们将项目组织成边界和职责分工明确的模块。他们利用了 oclif 的 hooks API 来防止 @shopify/cli-kit 通过依赖倒置获得依赖插件的信息。插件和 @shopify/cli-kit 实现依赖于接口。
Node CLI 展望
Node CLI 极大地改善了合作开发新体验:他们统一并简化了 App 合作开发,带来了全面的完全一致性,并新增了扩充机能,如函数。不过,他们还有很长的路要走,还有很多东西要学。
他们希望 Theme 合作开发新体验与 App 和 Hydrogen 的合作开发新体验保持完全一致。目前,Theme 命令仍然在 Ruby 实现中运行,为使用者提供更多 Ruby CLI 新体验,合作开发者需要在他们的环境中加装 Ruby 运行时,这种情况并不理想。
他们还将继续插值 App 合作开发新体验,为合作开发者提供更多一些实用的命令,用于建立、开发 App 并布署到网络平台。自从宣布为合作开发 App 提供更多更好的合作开发新体验以来,他们已经收到了许多宝贵的反馈,并且正以此为基础进行插值,如从 Multirepo 设置迁移到统一 App 模型的一些难点。在构建新设想的原型方面,他们的项目组也有两个很好的基础。未来,他们会很高兴分享他们的进展。
关于可扩充性,还有很多内容能分享,但这是先期昌明的主题。
Pedro Piñera Buendía 是 Shopify 的一名高级合作开发者。
原文链接:
https://shopify.engineering/overhauling-shopify-cli-for-a-better-developer-experience
编程已死,AI 当立?教授公开“唱反调”:AI 还帮不了程序员
抗拒采用 GPT-4 和 Copilot 写代码,拥有 19 年编程经验的老程序员“面试”被淘汰
马化腾称“收紧队形”,腾讯回应;微软发布自己的Linux发行版;OpenAI回应GPT-4 变笨 | Q资讯
向量数据库?不要投资!不要投资!不要投资!