1

I'm trying to employ SOLID principles learnt from strongly-typed languages in a Node.js application, and implement dependency injection through the constructor in my modules.

Without a compiler to help me, I've found myself impulsively writing type-checking and null-reference checking logic to make sure dependencies of the correct type are being passed in.

var _ = require('lodash');

var ExampleModule = function(dependencies) {
    var app, express, http;

    if(_.isUndefined(dependencies) || typeof dependencies !== 'object') {
        throw new ReferenceError('No dependencies object passed to the constructor. Actually passed: ' + typeof dependencies);
    }

    if(_.isUndefined(dependencies.express)) {
        throw new ReferenceError('The express module must be passed as the \'express\' property in the constructor.');
    } else {
        express = dependencies.express;
    }
    // Tempted to add a type check for dependencies.express here

    if(_.isUndefined(dependencies.http)) {
        throw new ReferenceError('The node http module must be passed as the \'http\' property in the constructor.'); 
    } else {
       http = dependencies.http; 
    }
    // Tempted to add a type check for dependencies.http here

};

module.exports = ExampleModule;

This feels fundamentally wrong for two reasons

  • Constructors filled with many conditional statements; likely to increase in size as more dependencies are needed.
  • Many extra unit tests are written to check the type-checks and null-reference checks are working

I don't want to spend half my time maintaining type-checking logic, but I also don't want to spend half my time debugging errors when the wrong type of a dependency is passed in.

What design pattern am I missing that would solve this problem?

glcheetham
  • 973
  • 8
  • 23

2 Answers2

2

small, but important clarification: the SOLID "D" is not dependency injection. it is dependency inversion.

for a better understanding of SOLID as it pertains to dynamically typed languages, watch this presentation from Jim Weirich: http://confreaks.tv/videos/rubyconf2009-solid-ruby

it's about Ruby, but all the principles are the same when applied to JavaScript.

there's also my own SOLID JavaScript presentation I did a few years ago: https://sub.watchmecode.net/episode/solid-javascript-presentation/

...

your own answer talks about require as dependency injection, but this isn't correct.

the require call is a module loader, not a dependency manager. the difference is subtle, but important.

the call to require only loads code from another file. it does not supply the dependency to your other code. you have to either call the code w/ the loaded module, or use another tool such as wire.js to supply the dependency for you.

...

regarding your dependency injection question: "it depends" is the only viable answer.

i rarely use type checking like this, when dealing with the internals of my applications.

however, if you're building an API that is called from third parties, it is often necessary to do what you have done, to make sure the API is called correctly.

Derick Bailey
  • 72,004
  • 22
  • 206
  • 219
0

Consider using typescript or flow. This will allow typing checking like most strongly typed languages.

function typedCheckFunction(x: string): string{
    return x
}

typedCheckFunction(5) // would error at compile time

I prefer typescript because of the support for atom, but they are mostly the same.

  • I have looked into typescript for this, but I'm leaning towards vanilla JavaScript solutions. I want to understand *JavaScript* more, not adapt JavaScript to work like what I'm used to. Good contribution. however. – glcheetham Mar 26 '16 at 13:04