4 ms·
Nitpick, 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
by 0xcoffee 5y ago
Nitpick, 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)?
- deleted 5y ago[deleted]
- yasserf 5y agohey! Thanks for replying! I just looked up the service lookup pattern and your right! I'll need to update the documentation accordingly. Would you mind sharing your thoughts on why it's an anti-pattern? Multiple companies I have worked with have all come up with their own solution for the issue of swapping out different services without requiring to touch the implementation code itself.
- 0xcoffee 5y agoSorry for late answer. I can give my perspective only from C# OOP perspective, which is my primary language. Dependency injection for me means, the constructor determines the dependency, and the injector will resolve what the constructor requires. The advantages of this are: 1. Writing unit tests, I know exactly what I need to mock, enforced by the compiler. I don't ever run tests and get an error because I forget to setup a service. 2. (In my opinion) It provides hints that a class has too many responsibilities and should be broken up. I can run a linter based on amount of constructor parameters that it is probably doing too many things. I strongly hold the opinion that the constructor defines everything needed by a class. At my company we use a mix of DI and service lookup because 'thats how its always been done', and it really makes testing unnecessarily harder. They decided when a constructor had over 3 services, to remove all the parameters and just pass a service locator because it 'looks nicer'. So that is my experience.
- yasserf 5y agoThanks for the input! Makes a ton of sense. Services themselves are passed in other services on the constructor. The reason it isn’t done in the APIFunction is because of a uniform use / functions are called via a fixed interface. However I think there’s a decent middle ground with typescript where it can figure out what objects are being used and then only require your tests to mock those. That way you get better typescript safety. Thank you for the feedback!