Skip to content

Instantly share code, notes, and snippets.

@dmorgan-github
Last active August 29, 2015 14:04
Show Gist options
  • Save dmorgan-github/787fc3f1c237f505e9cd to your computer and use it in GitHub Desktop.
Save dmorgan-github/787fc3f1c237f505e9cd to your computer and use it in GitHub Desktop.

Loosely coupling in node.js

In JavaScript everything is an interface and nothing is an interface.

Or, conversely, everything is loosely coupled and nothing is loosely coupled. This doesn't mean distinguishing between contract and implementation goes out the window. Nor does it mean an application is instantly loosely coupled just by virtue of being a node app.

When a module loads its dependencies via the global require method it binds itself to a particular implementation from a particular location. Where you want to achieve loose coupling between components loading a dependency via require is probably not the way to go. Nevertheless, it is true enough modules can be swapped out simply by replacing the contents of the file. Obviously this would work but isn't particularly compelling.

The trick, then, is loading modules a little earlier in the execution of the application, for example at start up.

If your module exports a function that accepts an argument the value passed to the module when it is loaded (via require) could contain dependencies for the module to use.

For example, a login controller could be set up similar to this:

module.exports = function(app) {

    var loginService = app.services.loginService;
    var http = app.http;

    http.post('/api/users/login',
	    function login(req, res) {

		    loginService.login(req.username, req.password);
		    ...
	    }
    );	
}

Where the loginService and the web container are passed in to the controller instead of the controller including the loginService via a require statement.

Composition

This means the build up of dependencies happens at application start up time and can be centralized in one location. For example, an application entry point app.js could contain code similar to this:

var app = {
    services: {}
};
app.services.loginService = require('./services/LoginService');
app.http = require('express');

require('./controllers/login')(app);

etc..

Objects like services and repositories are initialized when the application starts up. An object graph is contstructed and made available to whichever modules require it. This also gets away from having global variables hanging around.

Testing

With dependencies injected into a module and JavaScript being both interface and implementation it is easy to mock those dependencies for unit testing.

flatiron broadway

broadway from flatiron (https://github.com/flatiron/broadway) is a nice component that provides a simple container for composing the dependent pieces of your application into a single container. The container also inherits from EventEmitter so it provides a nice way to register and listen for events throughout the application. It allows you to "attach" plugins or extensions to an object and provides a callback for ensuring all components have completed initializing.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment