24

These days a question popped out in my mind:

Does the way we Javascript go against almost everything that is considered a good practice in traditional Software Development?

I have a series of question/observations related to this statement, but in order to respect StackExchange's format, it will be better if I split them into different questions.

Module requiring

Standard Javascript code nowadays looks like:

const someModule = require('./someModule')

module.exports = function doSomethingWithRequest() {
  // do stuff
  someModule.someFunc()
  // do other stuff
}

Advantages

  • Encapsulation: the module works standalone and know everything it need to perform its functions.
  • As a colorary, it's easier to clients to use the module.

Disadvantages

  • Poor testability: this is standard when not using DI, but in dynamic languages, such as Javscript it can be circumvented* by modules like mockery or rewire.
  • It certainly violates the DIP -- not to be confused with Dependency Injection. -- since I can only import concrete modules.
  • It probably violates the OCP -- for example, imagine that I have a log module that writes to the file system (through fs module). If I want to extend this log module to send it to the network, it would be very hard.

* This might work with CommonJS or even AMD modules since they are implemented mostly in the user-land. However, I'm not sure how this could be possible with ES6 import syntax.

Dependency Injection

Using dependency injection, it would be more like:

module.exports = function doSomethingWithRequest(someModule) {
  // do stuff
  someModule.someFunc()
  // do other stuff
}

Advantages

  • Increased testability: now it's easier to stub/mock someModule, even using the ES6 syntax.
  • It's possible to honor the DIP: not necessarily though, as the client module can still be programmed to the implementation and not an interface.

Disadvantages

  • Broken encapsulation: the main question remaining is:

    Ok, then who will create/require the dependencies?

  • Doing that in every client of the module seems very WET.
  • This would probably require me to use a DI Container in order to be feasible in a real project.

So, the real question here is:

Why Javascript developers tend to lean towards the first approach?

Is this just "the Javascript way"?

I myself write code like this most of the time. I've had my fair share of test setup using mocking libraries, but it always felt kind of wrong doing so.

Am I missing something?

  • As a .Net guy who's recently become interested in NodeJs, I've been struggling with this too. I have found monkey patching dependencies with Proxyquire (much like ReWire) to be okay for testing purposes, but sometimes you legit need multiple implementations of a dependency... – RubberDuck Nov 28 '16 at 0:00
6

I am mainly a PHP programmer, but have been in contact with 4 JavaScript teams for the past year or so.

As an object-oriented programmer the dependency injection principle would seem the best way, however I have been told otherwise by few JS developers. JS is a whole different world.

Because JavaScript allows you to monkey patch anything and everything using very simple techniques, JavaScript developers learned to adapt a different technology on how to build larger scale JavaScript applications. Most of these are build as sets of self-contained modules, which expose funcionality through public exports, hiding internals of the module as not to allow others to rewrite the functions on which you rely.

The usual approach usually is to even go as far as to not expose a constructor what so ever but rather expose constructing of an object using a factory wrapper - for the exact same reason: if you give someone access to an object they can instantiate directly they are allowed to change anything.

By taking advantage of the modular design you deny others to fiddle with your functions you expect to work, but you still have the ability to test your modules - through the public API of the required file, the API you created.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.