刚用 NestJS 完成一个项目,开发体验一般, JS 模块添加依赖注入,个人感觉必要性不强

2022-07-14 09:50:16 +08:00
 newghost
JAVA 里用依赖注入因为定义的都是 class ,想要共享实例只能注入。但 JS 模块导入即单例与 JAVA 机制完全不同,个人感觉必要性不强。
比如在文件开头的 import 语句,其实可以已经体现了依赖关系,这时你完全可以把 service/controller/dao 实例或方法 import 进来,其实已经可以算作完成了依赖声明,为什么还要 module 中重新注入一次依赖关系?
其次在构造函数中把 service/dao 实例变成参数传进来,个人感觉复杂了不少,可维护性降低。

大家觉得用 typescript + express 再分层会不会更简洁一些?
6195 次点击
所在节点    Node.js
22 条回复
lovedebug
2022-07-14 09:52:00 +08:00
JS 没有自省,没办法。
Nest.js 在 Node 工程化上的探索还是不错的。
newghost
2022-07-14 09:55:07 +08:00
@lovedebug
Nest.JS 还一个不好的点是调用一个 serivce 依赖,test case 也要更新,更个接口之间偶合度太高,维护性起来体验感比较差。
wunonglin
2022-07-14 09:56:34 +08:00
module 的话这个你需要看 angular 的设计,https://angular.io/guide/ngmodules
doommm
2022-07-14 09:58:12 +08:00
我个人理解,模块可以拿来做单例,但不是好的实践。IOC 可以做的事情更多
newghost
2022-07-14 09:58:16 +08:00
@wunonglin
嗯,一处依赖要在 module/import/构造函数弄三次声明,跟以前写 java 的感觉一模一样。
doommm
2022-07-14 09:59:03 +08:00
@doommm 应该说是 DI
newghost
2022-07-14 09:59:23 +08:00
@doommm
构架看上去不高级,体现不出水平倒是真的
lovedebug
2022-07-14 10:00:25 +08:00
@newghost 嗯,是的。Nestjs 基本理念来自 Angular 和 Spring ,这些问题两者都有。目前就是在工程化上的妥协,不引入框架,项目代码真的比较难以维护,就怕放飞自我。
mxT52CRuqR6o5
2022-07-14 10:01:24 +08:00
虽然说在 js 上搞依赖注入可能看上去有点多此一举,但做成接近 spring 的方案可以减少学习成本啊
newghost
2022-07-14 10:03:06 +08:00
@mxT52CRuqR6o5
有点道理,NG,Spring 过来一看,太亲切了,太熟悉了
doommm
2022-07-14 10:09:44 +08:00
@newghost 个人理解,单例应该是基于 app 应用生命周期的,而不是基于模块的。在 app 只会有一个实例的情况下,使用 DI 看起来会显得多余,但我认为这是明确代码职责的一种方式
walpurgis
2022-07-14 10:47:46 +08:00
为什么要在 module 里定义依赖关系,因为依赖的是接口而不是实现,只不过一般图省事直接把实现类作为接口传进去了,就像 Spring 里面依赖项直接写了某个类而不是接口一样
可以看下这章 https://docs.nestjs.com/fundamentals/custom-providers ,providers: [CatsService] 只是 providers: [
{
provide: CatsService,
useClass: CatsService,
},
] 的简写,provide 属性是 IoC 容器用于寻找实例的 key ,不一定是一个具体的类,碰到需要多个实现的场景,一般定义个抽象类作为 provide ,useClass 就可以根据情况注入不同的实现类了

本质是要把依赖交给容器管理,让使用方不知道用的是哪个实现,如果直接 import 进来用就绑死了具体的实现了
dudubaba
2022-07-14 10:49:02 +08:00
强约束性,比其他框架 service 满天飞好多了
lzgshsj
2022-07-14 11:11:57 +08:00
就像 #12 说的一样,大多数人是跳过了写接口这个阶段,直接依赖的实现类。所以看着的结果就是同一个东西在 module 和 import 里重复导入。
providers: [CatsService] 也可以写成
providers: [{provide: AnimalsService, useClass: CatsService}]
这里的 AnimalsService 就可以是个接口,而 useClass 又可以改成 useValue ,useFactory ,useExisting...等等灵活的实现。
这种做法可能在很多 orm 测试用例里会见到,因为测试往往用的不是真的数据,如果要 mock 的话,这时就可以使用 MockService 作为实现。
mxT52CRuqR6o5
2022-07-14 11:32:07 +08:00
@walpurgis 但其实 99.99%的业务代码用到倒闭也不会有替换 Service 的需求,也就测试时这个不绑死实现的特性有点用,但在 node 里也提供了能力去对 require 的结果进行 hook ,像 jest 不需要依赖注入一样可以替换 requre 、import 的东西
newghost
2022-07-14 13:38:08 +08:00
@walpurgis
@lzgshsj
我们使用的就是接口,这玩意更不实用,只有一个类,都用接口代替,平白多了 一层。而且 DEBUG 时很麻烦,点击方法都跑到了接口文件,每次还要手动去搜这个类。

TS 原写模块一般都会有一个 index 文件,只需要改用接口类型声明,如果真有类替换,在 index 中替换掉这个 modlue 的 export 实例即可,不更简单?
wu67
2022-07-14 13:45:06 +08:00
强约束性, 前端仔表示, 看了一周文档, 看不下去, 跑了.

自己写个破接口 mock 一下, express 真香.
lzgshsj
2022-07-14 13:58:50 +08:00
@newghost #16
1.实际情况是 99.99%的项目都不需要接口,所以你直接使用类也完全 ok ,框架也很灵活没有限制死,甚至 provider 就是默认你不写接口模式了。说到 debug 跳转,至少我用的 webstorm 是可以跳转到接口实现类的,没有要搜索的情况。

2.index.ts 的确是一个好东西,在 ng 里叫做 barrel files 。但是使用不当可能会造成循环应用。https://docs.nestjs.com/fundamentals/circular-dependency#circular-dependency

3.如果你想的是通过修改 index.ts 的 export ,来修改对应导出,那就是完全硬编码的方式了。还不如一步到位把所有你可能用到的 provider 全部 export 来得更方便?

4.技术没有银弹,本质上 nest.js 这套还是学的 ng 和 spring ,关于过度设计接口抽象的话题网上比比皆是。我的看法是,结合自身和团队情况,程序不报错,那条条大路通罗马。
pengtdyd
2022-07-14 14:29:41 +08:00
nestjs 最大的好处就是可以不招后端,只招前端就可以了,人力成本省了一大笔,这对于创业公司或者新项目是巨大的收益
newghost
2022-07-14 16:58:56 +08:00
@wu67

NestJS 的 Controller 其实设计的不错,可以省掉每个 url 的前辍像 /api/v2 这种,还能省掉 app.get/app.post 重复定义。如果只用 express ,controller 代码看上去有点脏

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/866056

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX