6 ms·
That is not really a good argument as you can also easily mock imported singletons in node. It is a bit dirtier but totally possible. Dependency injection was
by Sytten 5y ago
That is not really a good argument as you can also easily mock imported singletons in node.
It is a bit dirtier but totally possible.
Dependency injection was developed for languages that could not easily do that (like Java). It is just a design pattern that isnt that useful in python or js. You can decide to follow it if you think it will make your code cleaner/more readable.
- lhorie 5y ago> languages that could not easily do that (like Java) It's interesting that you bring up Java, which compiles things into class files. You can technically "mix and match" things there to achieve mocking semantics by carefully constructing jars. The point of DI is to bring composability into the realm of the language. In JS, sure you can use complex machinery to get jest to mock out imports during a hidden compilation phase, but there's no contractual relationship between the mock and the API consumption deep in your unit. E.g. I could "mock" moment.js, but if the implementation switches to date-fns, then the mock is still a valid thing, but it's no longer useful/applicable. Whereas, if there is a contract that can be enforced via types/API/DI, then switching date util implementations will trigger compile errors.
- jitl 5y agoWell said. Another reason passing dependencies as a parameter is great is to enforce constraints for a functional call. Say you have a database service that pools connections to your database. If you want to call some general function loadPermissionRecords(services, id) and be sure it only uses one connection for this invocation, you can wrap the database service with a facade that implements your resource constraint when calling it, eg loadPermissionRecords({ …services, database: database.withConnectionLimit(1) }, id) Sure, you could add the connection limit as a parameter to loadPermissionRecords, but you’ll also have to pass it down to every other function in the call graph beneath loadPermissionRecords…
- williamdclt 5y agoYou wouldn't inject Moment though, you'd inject an instance of a class (`DateManager` or whatever). You can absolutely write a mock for it that implement the same interface to enforce the same contract (`class DateManagerMock implements DateManager`), and use Jest mocking. Is it simpler/cleaner than DI? Arguable
- lhorie 5y agoWhat you inject is up to you. In Angular.js you could inject setTimeout's interface. I've injected fetch (for automatic anti-CSRF header inclusion). Etc. Facades are good if you're not sure if the API/semantics are set in stone. For moment.js, one typically only cares to mock specific calls related to things like current time, so it often makes more sense to refactor towards turning currentness into an explicit input, either by mocking the hard-coded moment.js call inside a convoluted unit, or more ideally, by making the value an input argument by design in the first place. The latter is harder to get to if you already have the code written, so mocking moment.js calls could be an acceptable alternative. You don't need to bring the whole OOP factory manager baggage if you just want simple contracts.
- ptx 5y agoWhat other patterns do you prefer in Python? Patching feels a bit messy, and if you patch out some imported module "mymod" in the implementation, it breaks when "import mymod" is changed to "from mymod import myfun", which should be an implementation detail. You could do something tricky with the import system to substitute modules, I suppose? It seems like this should solve some of the same use-cases as DI, but I haven't seen a clear and straight-forward description of how to go about it in a clean way.