Rich Hildred - Conestoga College

"Creative Active Individuals can only grow up in a society that emphasizes learning instead of teaching." - Chris Alexander

Read more about my learning interests below or proceed to a current course by clicking one of the buttons.

PROG3030   PROG1760  

JavaScript is events

Well of course JavaScript is a programming language, but it was designed for handling things that users do on web pages like filling out forms and clicking submit buttons.

click me

As a result more things in JavaScript are events than in many other languages. My morning class and I thought of a good metaphor for events and handling them that I want to share here. Think of the event of a newspaper landing on the sidewalk leading up to your house. What do you need to do for that event to happen? You need to subscribe.

newspaper arrival event

JavaScript events are similar in that they are published and subscribed to. The subscriber is sometimes called a listener, sort of like the faithful dog that listens for the arrival of the paper, and handles it by running outside and bringing the paper in to his master. In JavaScript that might look like:

jQuery("#sidewalk").on("paper arrival", function(paper){
    paper.bringToMaster();
}); 

The first thing that is happening here is that we are subscribing or listening to an event. That is the jQuery("#sidewalk").on("paper arrival" part of our code. The second part of this snippet is what to do when the event happens. In JavaScript there is an overseer or event loop that calls the dog handler to bring the paper to it's master.

function(paper){
    paper.bringToMaster();
}

The event subscription is through jQuery.on which in this case is taking 2 parameters, the name of the event and the handler to call to deal with the event. Often in JavaScript we have made to order events. Think of this as more like the sandwich shop.

sandwich

A common example in web application programming is getting something from a web server instead of a sandwich server.

jQuery.ajax({
    url: "cornBeefOnRye"
}).done(function(sandwich){
    eatSandwich();
}).fail(function(err){
    starve();
});

You might have noticed a problem with the handlers of both events. There is no reference to who eats the sandwich. If we have more than one sandwich eater or paper bringer we have a problem. The solution to this problem is to have sandwich eating objects, Tony in our diagram. Tony is a stomach with legs and exists in our example to eat sandwiches. He is also the context for the sandwich order. We can define a Tony Object like so:

var oTony = {
    name: 'Tony',
    state: 'famished`,
    eatSandwich: function(){
        this.state = 'replete for now';
    },
    starve: function(){
        this.state = 'deceased';
    }
}

If we have more than one sandwich eater in a system, we don't know which one's state is replete ... a big problem for Tony our walking stomach. The solution is to establish a context for who we call when an event happens. We do this like so:

jQuery.ajax({
    url: "cornBeefOnRye"
})
.done(jQuery.proxy(oTony.eatSandwich, oTony))
.fail(jQuery.proxy(oTony.starve, oTony));

that way when the message comes in it comes with it's context. You can think of the proxy like the little stand they hand you at Williams that makes you get your right sandwich.


Test Driven Development

Test Dummy - Brady Holt

Test driven development is a powerful idea for a number of reasons. The first reason I talked about when I spoke on specification by example. As a system grows and evolves over time, the tests and the code itself become the only reliable indication of its behavior. Consider the following code:

var getOntarioTax = function(nAmt){
    // Ontario tax is 7% sales tax plus 8% GST
    return (nAmt * 1.13).toFixed(2);
}

What has happened here? Likely this code was written a few years ago, and the tax rate has been adjusted since then, while the comment in the code remains from before. The following test:

var nIn = 10;
var nWithTax = getOntarioTax(nIn);
assert(nWithTax == 11.30);

makes sure that the tax rate is up to date, but also quickly tells us that the Ontario tax rate is not 15% as we would conclude from the comment.

The second reason that test driven development is important is because it leads to writing just enough code to do the job, which is important from a waste elimination perspective when writing code for a system but also when maintaining code for a system. If we make our getOntarioTax method be a getCanadianTax method by taking a second parameter for the province that defaults to Ontario, then we would start with the Ontario test that we have already written. To do another province we would add a second test:

var tests = {
    "Test of getTax with no province": function(){
        var nIn = 10;
        var nWithTax = getCanadianTax(nIn);
        assert(nWithTax == 11.30);
    },
    "Test of getTax for PEI": function(){
        var nIn = 10;
        var nWithTax = getCanadianTax(nIn, 'PEI');
        assert(nWithTax == 11.40);        
    }
}

When we implemented, just that additional functionality, we might do something like this:

var getCanadianTax = function(nIn, sProv){
    if(sProv == 'PEI'){
        return (nIn * 1.14).toFixed(2);
    }
    return (nIn * 1.13).toFixed(2);
};

Then as we implemented more provinces we would discover that there are a number of provinces that have a 13% tax rate and we might end up with code like this:

var getCanadianTax = function(nIn, sProv){
    if(typeof sProv == "undefined") sProv = 'ON';
    if(sProv == 'PEI'){
        return (nIn * 1.14).toFixed(2);
    }else if(sProv == 'NB' || sProv == 'NL' || sProv == 'ON'){
        return (nIn * 1.13).toFixed(2);
    }else if(sProv == 'NS'){
        return (nIn * 1.15).toFixed(2);
    }
    return (nIn * 1.05).toFixed(2);
};

which would be pretty much the minimum that is needed.

Finally test driven development makes sure that later changes don't break things that were working previously. For instance if we were to omit the test for an undefined second parameter in the previous method, the "Test of getTax with no province" will start failing. We can have confidence that we will write code that doesn't break something else.

To use the assert-runner npm module that I wrote to do test driven development myself you simply add the dependency to the package.json file in the root directory of your node project.

"dependencies": {
    "assert-runner": "*"
},

A simple passing first test requires the following code:

var assert = require('assert');
var TestRunner = require('assert-runner');

var tests = {
    "Test of assert": function(){
        assert(true == true);
    }
};

new TestRunner(tests).again(0);    

You say the test didn't pass???? Starting with a failing test is sometimes easier than you think. After you add the dependency to the package.json file, you will need to run a npm install inside your project directory.

So the basic pattern is

  1. Write a failing test (or a trivial passing one)
  2. Write the code under test and get the test to pass.
  3. Write another failing test ... write more code ....

You can see a complete example here.


Class Based Inheritance in the Style of BackBone.js

Shere Khan Suppose that I wanted to have a domain model that included different sorts of tigers!

I might start out with something like this:

var Animal = Toolbox.Base.extend({
    constructor: function (name) {
        this._name = name;
    },
    sayName: function () {
        return('Hi, my name is ' + this._name);
    }
});

Then I could make a Tiger sub-type of an animal something like this:

var Tiger = Animal.extend({
    constructor: function () {
        // all tigers are named Tony
        this._name = "Tony";
    }
});

But you can't call a Bengal Tiger Tony, so we need something like this:

var BengalTiger = Tiger.extend({
    constructor: function () {
        // you can't name a Bengal tiger Tony
        this._name = "Shere Khan";
    },
    sayName: function () {
        return('Hi, my name is ' + this._name + ' and I am the true lord of the jungle!');
    }
});

Seems like a user story for inheritance and polymorphism to me! JavaScript implements prototypical inheritance, which is fine but in this case I would like to be able to have class based inheritance like I might find in the BackBone.js library.

  var Router = Backbone.Router.extend({
    routes: {
      'lists/:id': 'openList'
    },

    initialize: function() {
    },

    openList: function(id) {
    }
  });

In fact it was BackBone.js that I drew my inspiration from. I am working on a large project, where I have a domain model that doesn't map completely to BackBone models views and Router. I was looking for something to carry the same style but that wasn't one of these things and came across this on the web. That js-toolbox is fine for browser based code, but didn't work with node where I really want to keep some domain logic so I made a npm for it. To enable a domain model using the BackBone style in node.js simply use npm install js-toolbox --save. You can see the code at my github.


Web Real Time Communications

Is your team more distracted together than working together? Web Real Time Communications (WebRTC) will turn group distraction ware into team learning ware. WebRTC, a technology for voice video and data communications in a browser and some recent studies on team learning and flow have the potential to send groupware products like Outlook and Notes the way of the rotary dial phone and the cubby-hole.

In 1990 I wrote an email client/MUA that was part of a groupware product that ran on Novell Netware. It was a character based interface, but had the metaphor of cubby-holes;

cubby-holes

to show whether a logged in user had mail, and to show if other users were out of the office. You don't hear much about cubby-holes anymore, but the basic premise of the most used groupware products, Outlook and Notes hasn't really changed since computers became standard on everyone's desk and pc based communications products took over from the previous generation of terminal based products. Other office tools like phones and conference bridges, while possibly having screen sharing haven't changed all that much in quite a while either.

The recent release of Web Real Time communications in the chrome and firefox browsers and a beef that I have about current offerings like Outlook, Notes and the Hub being too distracting from real life has drawn me to a new vision for teamware. To inform my vision with the most recent research about teamwork, team learning and the opposite of distraction, team flow I did a final MBA independent study project on the subject. I have learned some things writing that paper that will bring me closer to my dream of inventing something that will make our real lives as engaging as a video game.

Web real time communications is the enabling technology that can make a teamware that couldn't have existed until now and will make our online life an extension rather than a distraction from our real lives.