View on GitHub

Getting started with hilary.js

In this example (check out the source), we implement the same dependency injection pattern as the other examples, using only AMD (Asynchronous Module Definition). Namely, require.js.

We have a single Model View Controller structure that is composed by a Composition Root. We also mock jQuery ajax, to get data into the model without going to the server, to demonstrate the ease of testing modules using dependency injection and unit-of-work (UOW) patterns.

output from the example:

::

I'm not going to get into what Compsition Root is, but if you are unfamiliar with the term, Mark Seeman and his book, Dependency Injection in .NET should be your goto reference.

In a single page app (SPA), it makes sense to have a single Composition Root file. In a transactional app, each page might have a Composition Root, although it may be easier to maintain if you also use a single Composition Root and something along the lines of a feature-flag pattern (which I'm not going to get into).

Let's take a look at the Composition Root for this example, to figure out how it works:

require(['jquery', 'ko', 'mock-ajax', 'viewModel', 'view', 'controller'], 
function( $,        ko,   mockCtor, viewModelCtor, viewCtor, controllerCtor) {
	"use strict";

	var mocker, ajax, viewModel, view, controller;

	mocker 		= mockCtor.init($);	// create a singleton mocker
	ajax 		= mocker.makePromise([	// create a mock jQuery ajax signature
		{ id: 1, name: 'Hilary Page' }, 
		{ id: 2, name: 'Ole Kirk Kristiansen' }], 
		40 /**/);
	viewModel 		= viewModelCtor.init(ko); // create a singleton viewModel
	view 	   	= function() { return viewCtor.init(ko); };	// create a parameterless view factory
	controller 	= controllerCtor.init(ajax, viewModel, view); // create a singleton controller
	
	controller.action(); // call an action on the controller (i.e. this would load the page content)
});

So this app is made up of a model, a view and a controller. It depends on jQuery and knockout. We created four service modules: viewModel.js, view.js, controller.js and mock-ajax.js. Each of those services opts to declare it's dependencies in an init function, rather than using require's auto-resolution.

In Composition Root, we not only resolve the services that we intend to use, but also inject appropriate dependencies. We compose (i.e. construct or initialize) our services into singletons (the view being an exception) that are used to compose the services that depend on them. The view returns a parameterless contstructor, so the controller doesn't need to know anything about it's dependencies, and also so the view does not maintain state in the event that the same action is called multiple times with different parameters (i.e. usersController.getUser(1) and usersController.getUser(5)).

By taking this approach, it is easy to swap out services for new ones. This can be useful in testing, refactoring, reuse, etc. The controller service uses jQuery ajax, but because we passed in a mock service that satisfies the signature, we are able to isolate behavior by changing a single module: compositionRoot.js.

Another benefit of this pattern, with respect to how require.js loads the JavaScript files, is that it allows the browser to optimize loading, rather than require.js. This is because, after we load compositionRoot.js, the rest of the files are queued up all at once. If we declare the dependencies in each module, then the files are queued up n-times, depending on how deep the rabbit hole goes.