V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
newghost
V2EX  ›  Node.js

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

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

    大家觉得用 typescript + express 再分层会不会更简洁一些?
    22 条回复    2022-07-18 16:34:19 +08:00
    lovedebug
        1
    lovedebug  
       2022-07-14 09:52:00 +08:00
    JS 没有自省,没办法。
    Nest.js 在 Node 工程化上的探索还是不错的。
    newghost
        2
    newghost  
    OP
       2022-07-14 09:55:07 +08:00
    @lovedebug
    Nest.JS 还一个不好的点是调用一个 serivce 依赖,test case 也要更新,更个接口之间偶合度太高,维护性起来体验感比较差。
    wunonglin
        3
    wunonglin  
       2022-07-14 09:56:34 +08:00
    module 的话这个你需要看 angular 的设计,https://angular.io/guide/ngmodules
    doommm
        4
    doommm  
       2022-07-14 09:58:12 +08:00 via Android
    我个人理解,模块可以拿来做单例,但不是好的实践。IOC 可以做的事情更多
    newghost
        5
    newghost  
    OP
       2022-07-14 09:58:16 +08:00
    @wunonglin
    嗯,一处依赖要在 module/import/构造函数弄三次声明,跟以前写 java 的感觉一模一样。
    doommm
        6
    doommm  
       2022-07-14 09:59:03 +08:00 via Android
    @doommm 应该说是 DI
    newghost
        7
    newghost  
    OP
       2022-07-14 09:59:23 +08:00
    @doommm
    构架看上去不高级,体现不出水平倒是真的
    lovedebug
        8
    lovedebug  
       2022-07-14 10:00:25 +08:00
    @newghost 嗯,是的。Nestjs 基本理念来自 Angular 和 Spring ,这些问题两者都有。目前就是在工程化上的妥协,不引入框架,项目代码真的比较难以维护,就怕放飞自我。
    mxT52CRuqR6o5
        9
    mxT52CRuqR6o5  
       2022-07-14 10:01:24 +08:00 via Android
    虽然说在 js 上搞依赖注入可能看上去有点多此一举,但做成接近 spring 的方案可以减少学习成本啊
    newghost
        10
    newghost  
    OP
       2022-07-14 10:03:06 +08:00
    @mxT52CRuqR6o5
    有点道理,NG,Spring 过来一看,太亲切了,太熟悉了
    doommm
        11
    doommm  
       2022-07-14 10:09:44 +08:00 via Android
    @newghost 个人理解,单例应该是基于 app 应用生命周期的,而不是基于模块的。在 app 只会有一个实例的情况下,使用 DI 看起来会显得多余,但我认为这是明确代码职责的一种方式
    walpurgis
        12
    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
        13
    dudubaba  
       2022-07-14 10:49:02 +08:00
    强约束性,比其他框架 service 满天飞好多了
    lzgshsj
        14
    lzgshsj  
       2022-07-14 11:11:57 +08:00   ❤️ 1
    就像 #12 说的一样,大多数人是跳过了写接口这个阶段,直接依赖的实现类。所以看着的结果就是同一个东西在 module 和 import 里重复导入。
    providers: [CatsService] 也可以写成
    providers: [{provide: AnimalsService, useClass: CatsService}]
    这里的 AnimalsService 就可以是个接口,而 useClass 又可以改成 useValue ,useFactory ,useExisting...等等灵活的实现。
    这种做法可能在很多 orm 测试用例里会见到,因为测试往往用的不是真的数据,如果要 mock 的话,这时就可以使用 MockService 作为实现。
    mxT52CRuqR6o5
        15
    mxT52CRuqR6o5  
       2022-07-14 11:32:07 +08:00
    @walpurgis 但其实 99.99%的业务代码用到倒闭也不会有替换 Service 的需求,也就测试时这个不绑死实现的特性有点用,但在 node 里也提供了能力去对 require 的结果进行 hook ,像 jest 不需要依赖注入一样可以替换 requre 、import 的东西
    newghost
        16
    newghost  
    OP
       2022-07-14 13:38:08 +08:00
    @walpurgis
    @lzgshsj
    我们使用的就是接口,这玩意更不实用,只有一个类,都用接口代替,平白多了 一层。而且 DEBUG 时很麻烦,点击方法都跑到了接口文件,每次还要手动去搜这个类。

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

    自己写个破接口 mock 一下, express 真香.
    lzgshsj
        18
    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
        19
    pengtdyd  
       2022-07-14 14:29:41 +08:00
    nestjs 最大的好处就是可以不招后端,只招前端就可以了,人力成本省了一大笔,这对于创业公司或者新项目是巨大的收益
    newghost
        20
    newghost  
    OP
       2022-07-14 16:58:56 +08:00
    @wu67

    NestJS 的 Controller 其实设计的不错,可以省掉每个 url 的前辍像 /api/v2 这种,还能省掉 app.get/app.post 重复定义。如果只用 express ,controller 代码看上去有点脏
    humbass
        21
    humbass  
       2022-07-15 18:31:53 +08:00
    用 nextjs 、或者 java 的创业公司基本都死光了, 有 使用 Spring 的耐心和实力,直接上 java 不香吗?

    框架搞成这样,其实跟 Nodejs 没有多大关系了,跟 JS 更没啥关系了。
    zhennann
        22
    zhennann  
       2022-07-18 16:34:19 +08:00
    实现 IOC 控制反转主要有两种策略:依赖注入和依赖查找。由于 js 缺乏 java 命名空间的概念,所以实现依赖注入必然会非常繁琐。而 CabloyJS 基于依赖查找的策略实现的 Bean 容器和控制反转,不仅代码简洁,而且还可以方便的实现后端代码的打包编译,保护知识产权。
    参见:Bean 容器与控制反转: https://cabloy.com/zh-cn/articles/bean.html
    CabloyJS 全栈框架:从入门到精通:013 bean 容器与依赖查找: https://www.bilibili.com/video/BV1iN4y1M7Y7/
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   1909 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 30ms · UTC 16:18 · PVG 00:18 · LAX 08:18 · JFK 11:18
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.