3 ms·
singleton are just the one service where DI would often not be required (in Js/Ts), but there are more scopes. I.e. you would want to scope creation/deletion se
by littlecranky67 5y ago
singleton are just the one service where DI would often not be required (in Js/Ts), but there are more scopes. I.e. you would want to scope creation/deletion services i.e. to a session (lifetime across http connections per single user) or http scope (lifetime of the http request from incoming request to outgoing response. In other languages like C# you might also want different "singletons" that either live in the same thread or the same process (or specifically outside of those) etc. Compared to C#, JS is not a prime candidate for DI patterns as JS has neither threads, shared memory model, nominal typesystem/interfaces or destructors (that would allow service lifecycle and cleanup).
On the other hand, in C# (and AFAIK Java too) interfaces are named and versioned, and if any of your code wants to interact with those interface implenentations, they need a reference to that interface type at compile time. In JS or Typescript, you just have to pass a type that is structurally identical (which does also not allow for versioning at the language level).
- rektide 5y agoThis is a good statement on the core benefit of DI itself. Additioanlly there being well defined object lifecycles, with pluggable/hookable lifecycle points, has also been a really interesting capability that DI systems often offer. This usually goes hand in hand with a plugin system, that allows for modification of the various steps- it's easy to add logging, perhaps to wrap some behaviors in transactional or persistence concerns, or to attach some additional context to objects, all without having to modify/wrap/compose your original providers directly. I think of DI as providing a better repository of "how we make things", and a better toolkit for working with how we make things. Which enables a host of aspect-oriented programming ideas. This is not so much from DI itself, but from the systems that usually power it. There is a management of providers & objects across time & lifecycles, which makes first class something that is usually embedded implicitly in our procedural code. Surfacing these bring-up/handling/tear-down systems makes consistent, makes visible & makes malleable a wide amount of the glue-code we have to work with. Just ran across Injex the other week, which is a pretty decent looking Typescript DI library. It has a pretty minimal set of hooks (no object tear-down for example, but also almost never dealt with in js generally), but still is a good reference. It has hooks like "beforeCreateInstance" or "afterModuleCreation", to pick some random ones. These are enough to start modifying & altering behaviors of providers. https://www.injex.dev/docs/plugins#container-hooks https://www.injex.dev/docs/plugins#container-hooks An example use is their Express plugin, which allows for a kind of Python Flask/Java JAX-RS ish-ish way of writing services/endpoints. There's some nice annotations to declare what route it wants to handle. Then the plugin system deals with registering all the routes with the express server. It's all very pat, dry, & repeatable. https://www.injex.dev/docs/plugins/express/#get-post-patch-put-del https://www.injex.dev/docs/plugins/express/#get-post-patch-p... The managed repository of factories & objects has some interesting uses. In Spring, for example, there are a variety of *Aware interfaces, for watching the state of the IoC system, for seeing what objects there are, for seeing what's happening. I used this a long time ago in a EVE Online mapping application, to walk through all the things we had injected into the UI, reading out the values from the UI, and dumping them into an XML file. Then, at startup, I looked for that dump and injected all those saved values into the container. The result: the state of the UI was automatically saved at shut-down & reloaded at start up. It took some futzing around with Spring.NET but I didn't have to think about our code at all to do this: I just got spring to tell me what it had injected already, saved it to a file, and injected the file as configuration at start up. Spring made it easy.