在 TypeScript 中管理依赖边界

在处理大型项目时,开发人员倾向于遵循有助于管理复杂性的某些原则,即架构,使应用程序更易于理解和扩展。 虽然管理架构的方法有无数种,但一些流行的示例包括 模型-视图-控制器 (MVC) 和 六边形 架构模式。

在这些模式中,抽象被设置为高级系统设计或架构蓝图,描述每个模块的职责以及它们之间的关系及其依赖关系。 正确的架构选择将取决于系统的上下文、要求以及您是否需要实时数据处理或单片 Web 应用程序。

使日常开发与架构蓝图保持一致可能具有挑战性,尤其是在您的项目或组织快速发展的情况下。 虽然拉取请求审查、指导、文档和知识共享可能会有所帮助,但仅靠这些可能还不够。

在本文中,我们将讨论 TypeScript 上下文中依赖项的重要性。 我们将回顾未检查依赖项时的潜在缺陷,并提出一种解决方案,以使我们的代码与架构依赖项保持同步。 让我们开始吧!

  • TypeScript 中的依赖项

  • 未经检查的依赖管理的缺点

  • 使用栅栏添加显式依赖项

  • 依赖边界:一个实际的例子

TypeScript 中的依赖项

在 TypeScript 中,变量如 functions, objects, 和 values可以使用 ES6 模块 语法在文件之间导入或导出。 用注释的变量 export将被导出并可以使用 import句法:

// constants.ts
export const USER = "Alain";
​
// logic.ts
import { USER } from "./constants";
export const greet = (): string => `Hi ${USER}!`;
​
// ui.ts
import { greet } from "./logic";
const html = `<h1>${greet()}</h1>`; // <h1>Hi Alain!</h1>

使用此功能,您可以将应用程序的功能分解为模块,您可以按照架构蓝图进行组织。 需要注意的是,可以导入本地文件和本地或远程包,就像通过 npm 提供的一样。

这种模块语法具有很大的灵活性,对您可以导入和导出的内容没有任何限制。 依赖关系图是在整个应用程序中隐式定义的。

上面示例的依赖关系图

但是,随着项目的发展,隐式依赖图可能会变得不受控制,从而导致一些问题。

未经检查的依赖管理的缺点

未经检查的依赖关系的缺陷之一是任何程序模块都可以导入并创建对代码库中导出的任何方法的依赖关系。 私有和辅助方法可以从它们的模块中引用,因此保持模块的公共 API 需要不断的手动监督。

导入第三方包带来了另一个权衡。 第三方模块很棒,可以提高您的开发速度并防止您重新发明轮子。 然而,另一方面,由于包过时、包之间的冲突和巨大的包大小,过多的依赖项会使项目面临安全问题。


超过 20 万开发人员使用 LogRocket 来创造更好的数字体验 了解更多 →


第三个也是主要问题是无法以编程方式强制执行或验证代码是否遵循架构的依赖规则。 随着时间的推移,蓝图和实现可能会变得越来越不同,以至于参考架构不再有效,从而使架构的内在特征失效。

例如,在 MVC 中,我们可以失去视图和控制器之间的分离,其中包含业务逻辑,这使得测试变得困难,并降低了在不破坏业务逻辑的情况下迭代 UI 的能力。

在下一节中,我们将学习如何使我们的依赖项显式化,以便模块内部保持私有,第三方依赖项保持在控制之下,并且架构与代码保持同步。

使用栅栏添加显式依赖项

为了使模块之间的依赖关系明确并设置限制性依赖规则,我们将使用 good-fences 包。 good-fences 使您能够在 TypeScript 项目中创建和实施边界,它可以显着帮助减轻上述陷阱。

让我们通过一个例子来学习如何使用 good-fences 包。 我们将使用 good-fences 提供的栅栏的概念,以确保项目的实施匹配并随着时间的推移维护计划的依赖关系图。

栅栏定义了一个模块如何与其他模块和栅栏目录交互。 我们可以通过添加 fence.json文件到 TypeScript 目录。 栅栏仅限制通过它们的内容,例如导入、导出和外部依赖项。 在受保护的目录中,没有模块导入限制。 您还可以标记栅栏,以便其他栅栏配置可以标记它们。

依赖边界:一个实际的例子

此示例的完整代码可在 以下 repo 中找到。 我们将使用一个简单的 React 应用程序,它遵循商店驱动的 UI 架构,类似于 React 的展示组件模式 。 该应用程序提供 斐波那契数 列或 佩尔 数列的第 n 个数的计算。 就像我说的,这是一个简单的应用程序。

UI 无法访问应用程序中的业务逻辑方法,因为它们是在商店后面抽象出来的。 此外,业务逻辑代码不依赖于任何 UI 代码,因此 UI 可以在不触及业务逻辑的情况下进化。

下面是模块之间的依赖关系图。 请注意,模块之间的依赖关系用箭头标记。 内部模块为灰色,外部封装为蓝色。

青柠海报设计App,图像自媒体设计软件,已解锁所有VIP功能!

为了实现上面的模式,我们将创建三个不同的围栏目录, math, store, 和 ui. 每个目录都映射到架构中的一个模块。

为了防止其他模块或任一模块的类型进入实现细节,每个受保护的目录只允许从 index.ts文件。 只要在 index.ts文件没有被修改。

此外,为了防止循环或不需要的依赖关系,如 ui取决于 logic直接地,每个栅栏都被标记,定义它可以从哪些其他栅栏导入。

最后,为了缓解未经检查的第三方进口的问题,每个围栏都会明确声明哪些第三方包允许进口。 要添加新包,您必须修改 fence.json文件以使这些依赖项显式。

我们项目的栅栏配置如下:


来自 LogRocket 的更多精彩文章:

  • 不要错过 The Replay 来自 LogRocket 的精选时事通讯

  • 了解 LogRocket 的 Galileo 如何消除噪音以主动解决应用程序中的问题

  • 使用 React 的 useEffect 优化应用程序的性能

  • 之间切换 在多个 Node 版本

  • 了解如何 使用 AnimXYZ 为您的 React 应用程序制作动画

  • 探索 Tauri ,一个用于构建二进制文件的新框架

  • 比较 NestJS 与 Express.js


// ./math/fence.json
{
  "tags": ["math-module"],
  "exports": ["index"],
  "imports": [],
  "dependencies": []
}
// ./store/fence.json
{
  "tags": ["store-module"],
  "exports": ["index"],
  "imports": ["math-module"],
  "dependencies": ["react-redux", "@reduxjs/toolkit"]
}
// ./ui/fence.json
{
  "tags": ["ui-module"],
  "imports": ["store-module"],
  "dependencies": ["react"]
}

有关栅栏配置选项的深入解释,您可以查看 官方文档 。

所有这些规则都可以通过运行 good-fencesnpm 包,指向 tsconfig.json项目的文件,即 yarn good-fences. 您现在可以将检查作为 CI/CD 管道的一部分或作为提交挂钩运行!

结论

正确的依赖管理和在实施过程中遵循架构设计是健康和可维护代码库的重要方面。

good-fences 不是解决这个复杂主题的灵丹妙药,而是一个很好的工具。 随着项目的发展,很容易自动化手动依赖规则检查,这鼓励团队有意识地关注依赖关系。 该代码可在 以下 repo 中找到; 随意更改并进一步探索。 快乐编码!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

pxr007

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值