7 ms·
Why and how to use service injection in Node.js
- gkop 5y agoDo you get “intellisense” on the injected services?
- komon 5y agoAs long as the service container's members are typed you should
- gkop 5y agoThanks. I ask because at work we use this [0] “legacy” Node DI framework which utterly and completely breaks intellisense. [0] https://www.npmjs.com/package/dependable https://www.npmjs.com/package/dependable
- crooked-v 5y agoTake a look at tsyringe[1] instead. [1]: https://github.com/Microsoft/tsyringe https://github.com/Microsoft/tsyringe
- yasserf 5y agoYeah due to the Services and CoreServices functions being completely typed we have intellisense on everything in vramework. Down to the database tables and column names in queries (when using typed-postgres or typed-mysql libraries) https://vramework.io/design/#typescript-everywhere https://vramework.io/design/#typescript-everywhere
- ramesh31 5y agoCan anyone explain how this is better than just importing a singleton instance where it's needed? I've never really understood the point of dependency injection.
- pumpkinman 5y agoIt's not. But it makes you look smart, and helps you justify your salary to other engineers. Management don't give a toss, as long as you deliver value (features and fixes) on time.
- dimgl 5y agoThis is not necessarily true. Dependency injection allows you to provide your own implementations for unit testing. I'm surprised we're still talking about dependency injection in Node.js. I made a really crude dependency injection library for Node six years ago. https://github.com/divmgl/nwire https://github.com/divmgl/nwire
- pumpkinman 5y agoBut you can just mock the singleton
- lhorie 5y agoYou can mock injected entities in tests, instead of e.g. always connecting to the db
- knuthsat 5y agoWith JS, you can easily mock a whole module implementation so to use DI so that you can mock the injected entities during testing feels unnecessary.
- eyelidlessness 5y agoI assume you’re referring to mocking like that provided by Jest? If so… I’ll add a two big caveats: 1. The mechanism used (clearing or overriding the cache) isn’t available for ESM, where mocking is significantly more challenging. 2. That mechanism is also responsible for a lot of memory leaks when any modules are stateful.
- 0xcoffee 5y agoNitpick, but isn't this service lookup disguised as injection? Also somewhat considered an anti-pattern by some. Although I'm not sure how 'real' DI would work in Node, since it's requires knowledge of types to inject.
- ddek 5y agoMost node 'DI' is done using typescript decorators, which have access to the constructor. If you stick to this, you'll always be injecting implementations, which IMO kinda defeats the point of DI. You should be injecting behaviours, not implementations. The workaround is 'DI tokens', but they're a PIA. My node.js life improved dramatically when I stopped using the OO paradigms, and just wrote functions in native modules.
- williamdclt 5y agoIndeed. NestJS is one such framework that uses DI, it uses type reflection to inject implementations, or you can optionally use a DI token (with `@Inject(token)`). While I've never been a huge fan of this, it's also usually the least of my problems. On the plus side it makes dependencies between modules explicit which has raised some flags occasionally.
- crooked-v 5y ago> If you stick to this, you'll always be injecting implementations You could make abstract classes with error-throwing methods, then extend from those for the implementation. I think most Node people would think of that as extra boilerplate, though, since DI in Node frameworks usually exists as a side effect of other technical requirements rather than as a design goal in its own right.
- pan69 5y agoIn TypeScript that is what interfaces are for.
- yasserf 5y agoSo vramework tries to avoid using OO paradigms except for services. The thing I don't really understand about functions and long lived aspects (like a database connection for example) is that if you don't encapsulate it within a class, you end up with it being on the global scope, which in some way effectively treats the global scope as your class. How would you for example deal with having a single database pool that doesn't automatically connect on startup (when requiring a class)?
- yasserf 5y agoAdded a follow up blog entry here: https://vramework.io/blog/20211101-service-lookup-local-vs-cloud/ https://vramework.io/blog/20211101-service-lookup-local-vs-c...