Hey Dave,
Thanks for taking a look.
So basically, when I moved from OOP languages to NodeJS, I was creating classes like crazy. With DI and all the SOLID aspects.
I was DI fanatic, that I was injecting even the `request` module.
It was 3 years ago. As time went by, I moved towards functional programming, which I like more than OOP.
What I'm doing now, is I try to create small modules (I limit myself to 200 loc). But the average is around 100.
I do DI, only for objects that depend on IO. So for example I'd inject a MongoDB dependency to a Data Access Object/Function. And I'd inject this DAO to an Interactor.
As for business/domain logic, I don't do injections. I use NPM as my DI.
Most of my function signatures look like:
- function (state, cmd) which is the signature of reduce.
- function (dependency1, dependency2, state) with auto currying, which is the signature of map.
But I don't use it anymore, since the style of my coding have changed.
As I see it, an Interface is just a contract. That's all. So in the abstract level you do have Interface in JS. And ofcourse function signatures.
Another common signature that I'm using is:
function InteractorFactory(imports) {
// Validate contract of Imports
return function interactor(boundary, cb) { /*...*/ }
}
As of Imports, I inject sort of a master state object that would have most of my dependencies of the app. The Interactor can use whatever object it needs.
IMHO, it's clean to inject the application state into an interactor. It's not colliding with any of the SOLID principles.
Because the interactor expects to get and access to imports.getDogsList()
If imports looks like:
{
getDogsList: ...,
getCatsList: ....,
}
It still fufills the contract.
Another pattern I'm using, is the builder pattern, which builds the imports object and the application state on request.
It builds it incrementally in an immutable way....
Let's say I'm just initing the node. I'll build a state for the app.
Then, someone hits my web api. I need to pass it to my boundary... So I'll have a function that receives the appState and the request object from express, and builds a new state out of it.
You don't really need DI Container/framework when you work that way, because the application state builds itself incrementally.
And the best thing, is that all the functions are clean and testable.
Those are my 2 cents,
hope it helped.