【问题标题】:About Uncle Bob's clean architecture inversion of dependencies and Node.js关于 Bob 大叔干净的架构倒置依赖和 Node.js
【发布时间】:2020-08-24 23:29:54
【问题描述】:

我目前正在阅读 Bob 叔叔的“清洁建筑”一书。到目前为止,这是一本很棒的书,我学到了很多东西,但有些东西我没有掌握。

依赖反转与 Node.js 等脚本语言的相关性有多大

根据我的理解,依赖关系的反转允许较低级别代码中的更改对较高级别代码没有影响,只要保留接口即可。这反过来允许在无需重新编译整个应用程序的情况下部署模块。

但是在 Node.js 中,无论是在我的应用层中导入我的数据库实现模块还是它的接口,例如,如果我的数据库架构发生变化,那么我仍然必须更改该数据库实现模块文件并重新部署整个应用程序。

我错过了什么吗?

【问题讨论】:

  • 不确定你是否将依赖倒置与微服务混为一谈,但我从未听说过热部署是依赖倒置的主要驱动力?
  • 这个问题与领域驱动设计有什么关系?
  • @plalx 如果模块 A 需要模块 B 并且模块 B 被修改,那么模块 A 和 B 都需要重新编译。如果依赖倒置,那么修改 B 不需要重新编译 A

标签: node.js architecture domain-driven-design


【解决方案1】:

免责声明:我将为此答案排除 Typescript,仅讨论动态 javascript

Node js 是一种解释型语言,没有编译,所以它的运行时不同于 Java、C# 等编译型语言。

另一个非常重要的区别是 javascript 是一种弱类型语言,因此您会遇到的大多数错误都发生在运行时,这与编译后的强类型语言不同。

编译的强类型语言需要了解你使用的是什么(类、接口、方法参数等),以及它在编译时的样子。

动态脚本语言没有这个问题。在那里,你看到的是 runtime 检查你调用的东西(例如一个函数),如果它不存在就会抛出一个错误。

话虽如此,在 Node 中,您进行更改时不必重新编译应用程序,但您确实需要重新部署新的更改。

在编译语言中,您确实需要重新编译受更改影响的应用程序的某个部分,并且您还部署了该更改,因此两者都需要重新部署,但这个也需要重新编译。

通常,这些应用程序被分成单独的二进制文件,有些是库,有些是可执行文件,因此您只需重新编译二进制文件的子集。

在编译语言和解释语言中,当您更改代码的一部分时,依赖它的其他部分将受到更改的影响。现在你想要的是将受影响的代码部分最小化。

当您重新部署时,您确实需要重新启动正在执行您的应用程序的进程。在 Node 中,您需要重新启动它才能开始运行您的新代码。

在编译语言中,您需要重新启动可执行文件,以便它运行您的新代码,所以它几乎相同。

解释型和编译型语言都具有动态加载库 (dll) 或 javascript 模块的机制,它们只是文本文件,因此无需重新启动进程。

仅仅因为您在 Javascript 中没有像在 Java 或 C# 中那样的显式接口,并不意味着您没有绑定和依赖接口。如果您的代码调用对象上的函数,则此代码预计该函数将存在,因此它是对象接口的一部分。您可以更改此函数的实现,而无需更改调用代码,因为它取决于函数的名称和参数,而不是实现。

依赖倒置也可以应用于Node,只是你有隐式接口而不是显式定义的接口。您只需要从抽象的角度进行思考,并以不受任何实现细节约束的方式定义接口。

如果更改接口,实现和客户端代码都会受到影响。如果仅更改实现,则接口的客户端不受影响。这适用于弱类型和强类型语言,无论这发生在编译时的运行时。

是否需要重新编译是特定于语言的,是否可以在不必重新启动进程的情况下进行重新部署是另一回事。最大的问题是“你要改变什么,接口还是实现?”

您提供的数据库示例需要有关更改内容的更多详细信息。您的架构可能会更改而不会影响接口,只会影响实现。它可能会发生变化,因为应用程序的其余部分发生了重大变化,这会影响它的某些部分。

如果您只更改实现,而不更改接口(函数名称、定义等),您只更改 DB 模块,因此不影响更高级别的代码。依赖倒置有效,高层代码不受影响。

确实,使用具有显式接口的 C# 和 Java 语言更容易理解它,并且还有另一个步骤,涉及编译。很难想象 javascript 中的 隐式接口 是一样的,但在抽象层面上是一样的,只是机制不同。在这两种类型的语言中,如果您更改界面,代码中断,就差不多了。

这就是为什么您应该定义抽象和接口并控制对它们的更改,这样您的代码就不会中断。当然接口也需要改变。当他们这样做时,您需要更新客户端代码。这也适用于这两种语言。

【讨论】:

    【解决方案2】:

    我的意思是,在编译语言中,您可能只编译一个 DLL 或 .jar 文件并部署它。

    话虽如此,我现在意识到,实际上,这与语言无关,而与部署方法更相关。

    虽然我从未见过,但实际上只要尊重接口,即使在 JS 中也可以只部署特定模块。

    此外,我已经意识到接口为代码可维护性提供的其他好处,即使这是唯一的好处,也可以证明使用它是合理的。

    当我回答我自己的问题时,我会将这个帖子标记为已回答,谢谢。

    【讨论】:

      猜你喜欢
      • 2016-05-14
      • 2018-04-03
      • 2023-03-05
      • 1970-01-01
      • 2015-07-04
      • 2012-04-21
      • 2019-08-03
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多