I'm currently facing a conundrum: What is the right way to wire together 2 javascript objects?
Imagine an application like a text editor with several different files. I have some HTML page that represents the view for the notebook. I have a file notebook.js that contains class definitions for NotebookController and Notebook View.
NotebookControler object responsible for performing business logic on the Notebook like "Save Notebook," "Load Notebook," "New Notebook." NotebookView is responsible for managing the HTML that is used for presentation. It does low level stuff like "get/set notebook body" "get/set notebook name." It also listens for DOM events (onClick) and fires business events (saveNotebook). This is my attempt at the Passive View pattern.
I want my javascript client-side code to be object-oriented, separated concerns, and unit-testable. I want to test NotebookController with a mock NotebookView and vice versa. This means that I can't just instantiate a NotebookView inside the NotebookController. So do I
Put some logic in my notebook.js that wires the 2 together
Have a global function in my application that knows to instantiate one of each and wire them together
Use Dependency Injection, either a home-grown one or something like SquirrelIoc
In Java, the choice is a natural one: use Spring. But that doesn't seem very JavaScript-y. What's the right thing to do?
Dependency injection is probably your best bet. Compared to Java, some aspects of this are easier to do in JS code, since you can pass an object full of callbacks into your NotebookController. Other aspects are harder, because you don't have the static code analysis to formalize the interface between them.
Thanks for the insight. I ended up writing a simple JavaScript dependency injection utility. After debating for a while and your comments, it occured to me that DI was really the right answer because:
It totally separated the concerns of wiring from the business logic while keeping the wiring logic close to the things being wired.
It allowed me to generically provide a "you're all wired up" callback on my objects so that I could do a 3 phase initialization: instantiate everything, wire it all up, call everyone's callbacks and tell them they're wired.
It was easy to check for dependency missing problems.
So here's the DI utility:
var Dependency = function(_name, _instance, _dependencyMap) {
this.name = _name;
this.instance = _instance;
this.dependencyMap = _dependencyMap;
}
Dependency.prototype.toString = function() {
return this.name;
}
CONCORD.dependencyinjection = {};
CONCORD.dependencyinjection.Context = function() {
this.registry = {};
}
CONCORD.dependencyinjection.Context.prototype = {
register : function(name, instance, dependencyMap) {
this.registry[name] = new Dependency(name, instance, dependencyMap);
},
get : function(name) {
var dependency = this.registry[name];
return dependency != null ? dependency.instance : null;
},
init : function() {
YAHOO.log("Initializing Dependency Injection","info","CONCORD.dependencyinjection.Context");
var registryKey;
var dependencyKey;
var dependency;
var afterDependenciesSet = [];
for (registryKey in this.registry) {
dependency = this.registry[registryKey];
YAHOO.log("Initializing " + dependency.name,"debug","CONCORD.dependencyinjection.Context");
for(dependencyKey in dependency.dependencyMap) {
var name = dependency.dependencyMap[dependencyKey];
var instance = this.get(name);
if(instance == null) {
throw "Unsatisfied Dependency: "+dependency+"."+dependencyKey+" could not find instance for "+name;
}
dependency.instance[dependencyKey] = instance;
}
if(typeof dependency.instance['afterDependenciesSet'] != 'undefined') {
afterDependenciesSet.push(dependency);
}
}
var i;
for(i = 0; i < afterDependenciesSet.length; i++) {
afterDependenciesSet[i].instance.afterDependenciesSet();
}
}
}
I would say, just wire them together:
function wireTogether() {
var v = new View();
var c = new Controller();
c.setView(v);
}
But then of course another question raises - how do you test the wireTogether() function?
Luckily, JavaScript is a really dynamic language, so you can just assign new values to View and Controller:
var ok = false;
View.prototype.isOurMock = true;
Controller.prototype.setView = function(v) {
ok = v.isOurMock;
}
wireTogether();
alert( ok ? "Test passed" : "Test failed" );
There is also a framework for dependency injection for JavaScript: https://github.com/briancavalier/wire
I have a inversion of control library for javascript, I'm pretty happy with it. https://github.com/fschwiet/jsfioc. It also supports events, so if you want to have a startup event thats fine. It could use more documentation...
http://github.com/fschwiet/jsfioc
Another (newer?) option, which has better documentation and support, is requireJS (http://requirejs.org/).
I'll try to take a stab at this, but it will be a little difficult without seeing any actual code. Personally, I've never seen anybody do such a specific attempt at (M)VC with JavaScript or IoC for that matter.
First of all, what are you going to test with? If you haven't already, check out the YUI Test video which has some good info on unit testing with javascript.
Secondly, when you say "the best way to wire up that aggregation" I would probably just do it as a setter w/the controller
// Production
var cont = new NotebookController();
cont.setView( new NotebookView() );
// Testing the View
var cont = new NotebookController();
cont.setView( new MockNotebookView() );
// Testing the Controller
var cont = new MockNotebookController();
cont.setView( new NotebookView() );
// Testing both
var cont = new MockNotebookController();
cont.setView( new MockNotebookView() );
But this makes some big assumption on how you've designed your controller and view objects already.
Related
I'm running against a wall here, maybe it's just a small problem where I can't see the solution due to my inexperience with NodeJS.
Right now I'm constructing a BT device which will be controlled by a master application and I have settled for the prototyping on a Raspberry PI 3 with NodeJS using the Bleno module.
So far everything worked fine, the device gets found and I can set and get values over Bluetooth. But to separate the different "programs" which the device could execute from the Bluetooth logic (because of loops etc.) I have opted to extract these into external NodeJS files.
The idea here was to use the NodeJS fork module and control the starting and stoppping of those processes through the main process.
But herein my problems start. I can fork the different JavaScript files without problem and these get executed, but I can't get them to stop and I don't know how to fix it.
Here's the code (simplified):
var util = require('util');
var events = require('events');
var cp = require('child_process');
...
var ProgramTypeOne = {
NONE: 0,
ProgramOne: 1,
...
};
...
var currentProgram=null;
...
function BLEDevice() {
events.EventEmitter.call(this);
...
this.currentProgram=null;
...
}
util.inherits(BLELamp, events.EventEmitter);
BLELamp.prototype.setProgram = function(programType, programNumber) {
var self = this;
var result=0;
if(programType=="ProgramTypeOne "){
if(programNumber==1){
killProgram();
this.currentProgram=cp.fork('./programs/programOne');
result=1;
}else if(programNumber==2){
...
}
self.emit('ready', result);
};
...
module.exports.currentProgram = currentProgram;
...
function killProgram(){
if(this.currentProgram!=null){
this.currentProgram.kill('SIGTERM');
}
}
There seems to be a problem with the variable currentProgram which, seemingly, never gets the childprocess from the fork call.
As I have never worked extensivley with JavaScript, except some small scripts on websites, I have no idea where exactly my error lies.
I think it has something to do with the handling of class variables.
The starting point for me was the Pizza example of Bleno.
Hope the information is enough and that someone can help me out.
Thanks in advance!
Since killProgram() is a standalone function outside of the scope of BLELamp, you need to call killProgram with the correct scope by binding BLELamp as this. Using apply (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/apply) should resolve it. The following I would expect would fix it (the only line change is the one invoking killProgram):
BLELamp.prototype.setProgram = function(programType, programNumber) {
var self = this;
var result=0;
if(programType=="ProgramTypeOne "){
if(programNumber==1){
killProgram.apply(this);
this.currentProgram=cp.fork('./programs/programOne');
result=1;
}else if(programNumber==2){
...
}
self.emit('ready', result);
};
As a side note, your code is kind of confusing because you have a standalone var currentProgram then a couple prototypes with their own bound this.currentPrograms. I would change the names to prevent confusion.
Hopefully this question won't be flagged as too subjective but I'm newish to OOP and struggling a bit when it come to sharing data between parts of my code that I think should be separated to some extent.
I'm building a (non-geo) map thing (using leaflet.js which is superduper) which has a map (duh) and a sidebar that basically contains a UI (toggling markers both individually and en masse, searching said marker toggles as well as other standard UI behaviour). Slightly confused about organisation too (how modular is too modular but I can stumble through that myself I guess). I am using a simple JSON file for my settings for the time being.
I started with static methods stored in objects which is essentially unusable or rather un-reusable so I went for nested constructors (kinda) so I could pass the parent scope around for easier access to my settings and states properties:
function MainThing(settings) {
this.settings = options;
this.states = {};
}
function SubthingMaker(parent) {
this.parent = parent;
}
SubthingMaker.prototype.method = function() {
var data = this.parent.settings.optionOne;
console.log(data);
this.parent.states.isVisible = true;
};
MainThing.prototype.init = function() {
this.subthing = new SubthingMaker(this);
// and some other fun stuff
};
And then I could just create and instance of MainThing and run MainThing.init() and it should all work lovely. Like so:
var options = {
"optionOne": "Hello",
"optionTwo": "Goodbye"
}
var test = new MainThing(options);
test.init();
test.subthing.method();
Should I really be nesting in this manner or will it cause me problems in some way? If this is indeed okay, should I keep going deeper if needed (maybe the search part of my ui wants its own section, maybe the map controls should be separate from DOM manipulation, I dunno) or should I stay at this depth? Should I just have separate constructors and store them in an object when I create an instance of them? Will that make it difficult to share/reference data stored elsewhere?
As regards my data storage, is this an okay way to handle it or should I be creating a controller for my data and sending requests and submissions to it when necessary, even if that data is then tucked away in simple JSON format? this.parent does really start to get annoying after a while, I suppose I should really be binding if I want to change my scope but it just doesn't seem to be an elegant way to access the overall state data of the application especially since the UI needs to check the state for almost everything it does.
Hope you can help and I hope I don't come across as a complete idiot, thanks!
P.S. I think the code I posted works but if it doesn't, its the general idea I was hoping to capture not this specific example. I created a much simpler version of my actual code because I don't want incur the wrath of the SO gods with my first post. (Yes, I did just use a postscript.)
An object may contain as many other objects as are appropriate for doing it's job. For example, an object may contain an Array as part of its instance data. Or, it may contain some other custom object. This is normal and common.
You can create/initialize these other objects that are part of your instance data in either your constructor or in some other method such as a .init() method whichever is more appropriate for your usage and design.
For example, you might have a Queue object:
function Queue() {
this.q = [];
}
Queue.prototype.add = function(item) {
this.q.push(item);
return this;
}
Queue.prototype.next = function() {
return this.q.shift();
}
var q = new Queue();
q.add(1);
q.add(2);
console.log(q.next()); // 1
This creates an Array object as part of its constructor and then uses that Array object in the performance of its function. There is no difference here whether this creates a built-in Array object or it calls new on some custom constructor. It's just another Javascript object that is being used by the host object to perform its function. This is normal and common.
One note is that what you are doing with your MainThing and SubthingMaker violates OOP principles, because they are too tightly coupled and have too wide access to each other internals:
SubthingMaker.prototype.method = function() {
// it reads something from parent's settings
var data = this.parent.settings.optionOne;
console.log(data);
// it changes parent state directly
this.parent.states.isVisible = true;
};
While better idea could be to make them less dependent.
It is probably OK for the MainThing to have several "subthings" as your main thing looks like a top-level object which will coordinate smaller things.
But it would be better to isolate these smaller things, ideally they should work even there is no MainThing or if you have some different main thing:
function SubthingMaker(options) {
// no 'parent' here, it just receives own options
this.options = options;
}
SubthingMaker.prototype.method = function() {
// use own options, instead of reading then through the MainThing
var data = this.options.optionOne;
console.log(data);
// return the data from the method instead of
// directly modifying something in MainThing
return true;
this.parent.states.isVisible = true;
};
MainThing.prototype.doSomething = function() {
// MainThing calls the subthing and modifies own data
this.parent.states.isVisible = this.subthing.method();
// and some other fun stuff
};
Also to avoid confusion, it is better not to use parent / child terms in this case. What you have here is aggregation or composition of objects, while parent / child are usually used to describe the inheritance.
I'm trying to figure out what MV* framework of many existing can give me what I need...
I am using multipage ASP.NET web application, so I don't want to use routers.
It must be very small...something like Backbone.js, currently I don't want to use something huge like Ember.js or Angular.js.
I will have "modules or controllers" that actually are "single instances" that will get their "data" from server as JSON objects (sometime will be AJAX and sometime embedded in HTML). It's important to be able to use inheritance for modules, so would like to be able to do something like this (pseudo code):
App.Module1 = SomeFramework.create({
model: null,
init:function(data){ this.model = data }
});
App.Module2 = SomeFramework.create(App.Module1, {
config: null,
init: function(data, config){
this._super(data); this.prop = data;
}
});
//Later I will use one of this modules
App.Module1.init(data); /* OR */ App.Module2.init(data, config);
I will have different models that can have many instances.
Modules/Controllers should be able to detect "model changes".
I like Backbone, but it misses some of the things, like creating "single modules" that are able to be inherited and Backbone does not have "controller" because now it's router and it make instances based on URL.
There's nothing smaller than writing plain vanilla javascript, that would be my advice.
And add a couple of micro libraries for DOM manipulation and ajax if you need.
You want to observe your models, but data-binding might be heavy, magic comes at a cost. Why not just use a pub-sub library to communicate to the modules that a model data has changed? It is simple, small and safe.
I'm going to give you some examples with something that I know, the framework soma.js. It is very lightweight, doesn't have a router (I usually advice to use director.js). It provides dependency injection, an event-based observer system, as well as basic OOP such as inheritance. It is very much focused on avoiding highly-coupled code so modules are maintainable and reusable. Vanilla javascript is the key which is possible dependency injection.
Funny, someone thought I was coming from a .NET background with that framework, maybe it appeal to you.
For the ajax part, strip out jquery so there's only the ajax stuff (so it is small), or use something like reqwest.
Here is a quick overview of what you can do.
Inheritance
// create "super class"
var Person = function(name) {
this.name = name;
};
Person.prototype.say = function() {
console.log("I'm a Person, my name is:", this.name);
}
// create "child class" that will inherit from its parent
var Man = function(name) {
Person.call(this, name); // call super constructor
}
Man.prototype.say = function() {
// Person.prototype.say.call(this); // call super say method
console.log("I'm a Man, my name is:", this.name);
}
// apply inheritance
soma.inherit(Person, Man.prototype);
// create Person
var person = new Person("Doe");
person.say();
// create Man
var john = new Man("John Doe");
john.say();
Try it out
Here is another example with some shortcuts.
// create "super class"
var Person = function(name) {
this.name = name;
};
Person.prototype.say = function() {
console.log("I'm a Person, my name is:", this.name);
}
// create an "extend" shortcut
Person.extend = function (obj) {
return soma.inherit(Person, obj);
};
// create "child class" and apply inheritance using an "extend" shortcut
var Man = Person.extend({
constructor: function(name) {
Person.call(this, name); // call super constructor
},
say: function() {
// Person.prototype.say.call(this); // call super say method
console.log("I'm a Man, my name is:", this.name);
}
});
// create Person
var person = new Person("Doe");
person.say();
// create Man
var john = new Man("John Doe");
john.say();
Try it out
Modules
The frameworks makes you able to vanilla javascript so it is very reusable.
Here is what a Model, or Module, or anything else could look like (vanilla javascript):
(function(clock) {
'use strict';
var TimerModel = function() {
};
TimerModel.prototype.update = function() {
// update something
};
TimerModel.prototype.add = function(callback) {
// add something
};
TimerModel.prototype.remove = function(callback) {
// remove something
};
TimerModel.prototype.dispose = function() {
// destroy model
};
clock.TimerModel = TimerModel;
})(window.clock = window.clock || {});
Dependency injection
The framework provides dependency injection, which makes you able to use named variable to get your instances in other modules.
An injection rule could look like that:
injector.mapClass("myModel", Model);
To get your model somewhere else, just use the "named variables", the injector will take care of everything (also very good to solve nested dependencies):
var Module = function(myModel) {
// myModel has been injected
}
Try an example
More information
Communication (pub-sub, Observer Pattern)
A event-based tool (interchangeable with a DOM node for high decoupling) is available to communicate: the dispatcher. You also get it with injection:
var Module = function(myModel, dispatcher) {
// myModel and dispatcher have been injected
}
Dispatch an event:
this.dispatcher.dispatch('do-something');
Listen to an event:
dispatcher.addEventListener('do-something', function(event) {
// react to an event
});
Template
You can use a very powerful plugin as a template engine (real non-destructive DOM manipulation) called soma-template.
Or any other template engine of your choice.
Build an application
Here is an article that make you build an scalable and maintainable application:
http://flippinawesome.org/2013/07/15/soma-js-your-way-out-of-chaotic-javascript/
That's not it, the framework also provide Mediators and Commands to make your code reusable. Check out the site, it has tons of demos.
I hope all this is helping you.
I'm used to write very bare bone application that run fast on mobile, so please ask me precise questions about what you need so I can maybe help.
Romu
Yes, Backbone does not have module driven development or rather Backbone does not follow modular pattern. You can use require.js for Modular pattern. It is a very small library and syncs up well with Backbone.
I have module pattern done like this:
var A = (function(x) {
var methodA = function() { ... }
var methodB = function() { ... }
var methodC = function() { ... }
...
...
return {
methA: methodA,
methB: methodB
}
})(window)
This code let's me call only methA and methB() on A which is what I want and what I like. Now the problem I have - I want to unit test it with no pain ot at least with minimal efforts.
First I though I can simply return this but I was wrong. It returns window object.(can someone explain why?).
Second - I found solution somewhere online - to include this method inside my return block:
__exec: function() {
var re = /(\(\))$/,
args = [].slice.call(arguments),
name = args.shift(),
is_method = re.test(name),
name = name.replace(re, ''),
target = eval(name);
return is_method ? target.apply(this, args) : target;
}
This method let's me call the methods like this: A.__exec('methA', arguments);
It is almost what I want, but quite ugly. I would prefer A.test.methA() where test would never be used in production code - just for revealing private methods.
EDIT
I see people telling me to test the big thing instead of the small parts. Let me explain. In my opinion API should reveal only the needed methods not a bunch of internal functions. The internals because of their small size and limited functionality are much easier to test then test the whole thing and guess which part gone wrong.
While I may be wrong, I would still like to see how I could return references to all the methods from the object itself :).
Answer to your first question(you return this, but it returns window, not the object you wanted): in javascript this inside the function returns global object unless this function is a method of the object.
Consider next examples:
1) this points to the global object ():
function(){
return this;
}
2) this points to the object:
var obj = {
value: "foo",
getThisObject: function(){
return this;
}
}
Your case is example #1, because you have a function, that returns an object. This function is not a method of any object.
The best answer to your second question is to test only public methods, but if
that is so important for you, I can propose next:
create your modules dynamically on server side.
How it works:
create separate scripts for functionality you want;
create tests for these separate scripts;
create method that will combine scripts into one however you want;
to load script, reference to the combining scripts method.
Hopefully, it can solve your problem. Good luck!
Why not use namespaces to add your modules and public methods to js engine. Like this:
window['MyApp']['MODULE1'] = { "METHOD1" : {}, "METHOD2" : {}};
I write modules like this Sample module in JavaScript.
And test it like this: Simple unit testing in JavaScript
The use of eval() is generally not good idea.
What, in your opinion, are the advantages and disadvantages of dependency-injecting non-instantiable objects in JavaScript?
Some context you may want to explore are:
Unit-testing
Is it worth dep-injecting it? After all, you can overwrite the non-instantiable "static" dependency to a fake object for each test even without dep-injection.
Refactoring
Will it become more difficult to locate & refactor the non-instantiable dependency?
Readability
Which implementation is easier to follow? Is the implicitness or explicitness important to you?
File-size
Code
Non-instantiable object:
WindowFactory = {
buildWindow: function() {
return {};
}
};
Dependency-Injected:
(House = function(windowFactory) {
this.windowFactory = windowFactory;
}).prototype = {
build: function() {
var window = this.windowFactory.buildWindow();
}
};
var house = new House(WindowFactory);
vs. The Non-Dependency-Injected variant:
(House = function() {
}).prototype = {
build: function() {
var window = WindowFactory.buildWindow();
}
};
var house = new House();
Context
My primary goal is to make the code above testable. I've gotten into a
habit of externalizing instantiable dependencies (e.g var window = new
Window(); var house = new House(window);). This helps when unit-
testing instantiable objects (e.g. House), since instead of the real
dependencies (Window) I can instantiate the object with a fake (var
fakeWindow = {}; var house = new House(fakeWindow);), and not have to
worry about redundantly testing the dependencies while testing my
object. (This form of dependency-injection is also useful when testing
objects that depend on some data being retrieved via XHR, DOM-events,
sessionStorage, or cookie.)
Now, when the dependency is an instantiable object itself, the
benefits are clear to me; but when the dependency is a non-
instantiable object (e.g. WindowFactory in the code above), I have
second thoughts about the usefulness.
If you get some gain in unit-testing, that might be more than enough for me. You'll be able to cleanly test the functionality without depending on global/external state. The added bonus then becomes the readability; you clearly show which global state/api you depend on in the arguments of your function.
Being able to change the static methods in the setup/teardown of the tests is a workaround for the problem, but I personally find it to be error-prone and a chore doing it.