“Mejh” Dev Log – Part 3

I decided it was time to start getting the Mejh to look around and guess their positions. That got messy pretty fast – I want to be able to swap out the “find the closest stuff to you” part very quickly, which meant creating a World class for the Mejh to live in, and a “Finder” interface, which has a “findNearbyMejh” method. If I need to optimise to a quad tree or something, it should be rather simple, success!

Unfortunately, this is where the success starts to run out. Because the next feature I wanted was to be able to hover over a Mejh, and have nearby Mejh glow. As much as I trust my tests, I do like to see this progress on the screen, and this is a stepping stone to having an interactive sort of game. So I go in and start writing tests for the renderer to have interactivity.

When a circle is clicked it appears selected

And I’ve already hit a wall, which is d3.js. I either haven’t found out how to test it easily yet, or it’s a difficult API to write tests for. Or both. See, d3.js works by selecting a bunch of elements, binding them to data, and specifying behaviour for the nodes, with special cases for entering nodes and exiting nodes. So the rendering code of last week was:


Renderer.prototype = {
    render: function() {
        var allMejh = this._world.allMejh();
        var selection = d3.select(this._canvas)
            .selectAll('circle')
            .data(allMejh, function(m) { return m.id; });

        selection.enter().append('circle');
        selection.exit().remove();

        this._formatter.format(selection);
    }
};

Formatter.prototype = {
    format: function(selection) {
        selection
            .attr('r', 3)
            .attr('cx', function(m) { return m.position().x; })
            .attr('cy', function(m) { return m.position().y; });
    }
};

Pretty simple code. Pain in the butt to test though, because you have to consider the case where a node is entering, where one is exiting, and that each one is formatting. While the implementation is about 15 lines of code, the tests take up 55 or so. Of course, lines of code aren’t a good way of measuring quality or anything, but it just felt *wrong*.

Updating for hover code was simple, but writing tests for it first proved even more difficult, as the mouse events are bound to the d3 selection, and it’s all very d3-selectiony, not DOM elementy, and gets confusing fast.

So I thought to myself, let’s try out something that’s NOT d3.js. I hit up http://angularjs.org/

Angular JS

In brief AngularJS provides a way of specifying views using markup, and having it bind to a model (ish), with a controller floating around there to give it all some behaviour. It’s fairly impressive I have to admit. egghead has some fantastic video tutorials on it.

So I watched a few videos, did some dodgy demo apps with ridiculously simple models and repeat sections and thought “yes, let’s go!”. I had trouble doing it in SVG, so I just used divs with text displaying the model position – I figured I could switch out the rendering easy enough. And that WAS easy enough – it just worked. Well, as long as I made sure my application attached the world onto some global scope because angular didn’t play nice with InjectJS. I figured I could work on DI integration later, global scope was fine while researching this stuff. And it’s just the world, not a big deal, right?

Next was the hover behaviour, and I realised I also had to expose my finder – since what I wanted to do is find the Mejh that are close to the clicked node, and add them to a list of ‘nearby’ Mejh (or mark them as nearby some other way). That’s 2 in the global scope, but it worked well enough. I didn’t attempt testing just now – still just researching and seeing if it’s worth pursuing)

Time to work on SVG support. I wire up the same repeat infrastructure, but with circles instead of divs, and run it. Woo! There they are, a circle for each Mejh. Just for posterity, I put in 2 more repeats – one for the highlighted one, another for the ‘nearby’ ones. Bam, they show, the click events work, too easy!

But, I don’t want 3 repeats. I want 1 list of Mejh, and the format of it dependant on whether it’s selected, nearby, or neither. Which means a directive – <mejh-circle>. Test it in HTML, all good, do it in SVG. Nothing. I inspect the DOM using Chrome’s dev tools, all the circle elements are there with perfect markup, why isn’t it showing?

Fast forward half an hour or so, turns out my directive makes HtmlUnknownElement instead of SvgCircleElement. Because that’s what happens when you use strings to build SVG – something that Angular wasn’t really designed for (understandably). So I have to throw Angular out for this project, too painful.

Ahh well, live and learn. I think what I’ll do is make a view model for the world, test the view model, and not test the bit that actually makes DOM elements out of the view model. Stay tuned!

“Mejh” Dev Log – Part 2

I’ve done my first chunk of code, and TDD has blown me away yet again.

So I created a class for my Mejh dudes, a “placer” to just randomly put them all over the bounding area for now, a renderer to create SVG elements for each of them, and a formatter to give the SVG elements what they need (radius, position, etc.). And an application to tie it all together.

Once the application was finished, and I had 100% code coverage and DI everywhere, I created an index.html, set up the DI container how I wanted it, and it worked (well, not quite – I forgot to set cx and cy attributes of the circles, so they all appeared at 0,0). What’s more, the container setup only required 3 manual registrations – everything else was automatic.

It may not seem like much – a handful of classes which, when put together, do nothing more than display a bunch of random dots on the screen – but having any app “Just Work” feels damn good.

Here’s the libraries I’m using to do the bits:

  • InjectJS: DI Container for Javascript. Written just last week by a coworker, it’s brilliant. Highly recommended.
  • d3js: Library to bind data to DOM elements. Chose this one because I knew it, and it works well.
  • Basil, ChaiJS, SinonJS: Trinity of Javascript testing, I talk about these enough so I’ll leave it at that

And to finish it off, some things I’ve learnt

Dependencies

When everything is tested, the list of scripts in test.html match exactly to the list in index.html. The only difference in the real version is the instantiation and starting of the Application. Maybe I should be testing my container setup/initial resolve?

Testing the DOM is very fiddly

I’m using d3 to render the svg circles, and so all my rendering tests have to be integration tests – I can’t feasibly mock that thing. It makes it quite painful to test, especially since pulling attributes out of Svg elements return animated strings, so the easiest way to assert on them is with d3.select(el).attr(“r”).should.equal(“3″). Of course, .attr always returns strings, not numbers… I’m glad I won’t have much render code!

Slowdowns

My environment is slowing me down a lot. Manually making class methods instead of just pressing alt+enter takes time. Not having the tests Autorun takes time (I really need to update that chrome extension…). Not being terribly familiar with WebStorm’s keyboard shortcuts takes time. Heck, even not knowing d3/sinon/chai/injectjs off the top of my head slows me down plenty (not to mention the bits and bobs of missing functionality, like array matchers in chai – .deep isn’t the answer)! Hopefully I’ll get faster, and nut a lot of this down, but right now, it’s annoying.

So what’s next? I think I’ll get the Mejh guessing their positions now. This will mean adding neighbour discovery, and what I think will be a visitor pattern for the Mejh to add different guessing behaviours, not certain yet. Going mejh.Visit(this._positionGuesser) just seems sensible, and sets me up for adding movement later.

I’ll also spend some time on configuring the IDE to do more stuff for me.

Until next time!

“Mejh” Dev Log – Part 1

I was talking with a coworker the other day, and we lamenting about how bad GPS is in the city – what with all the buildings and reflections messing everything up. We came to the realization that there are a tonne of phones all around, each with a pretty-good-but-not-perfect idea of where it’s located. So we got all excited about the idea of creating an app which uses all the clients to build mesh-based location service for phones with that app. It’s like bittorrent, for GPS!

We figured it would only take a few ‘seed’ nodes (that is, nodes with 100% certainty of their location) to stabilize a large mesh of nodes with fairly-certain distances to neighbouring nodes, and low certainty of its own location.

Of course, it will be damn difficult to get the distances to neighbouring nodes. Bluetooth is too low range, wifi signal strength is not very accurate, tone measuring will be ridiculously annoying and GPS cannot be considered – or we wouldn’t need a mesh at all!

Which makes me want to test the idea in a game. The idea will be a community of “Mejh” (the jh being pronounced as the ‘g’ in ‘genre’), where each member:

  1. Does not know their own location
  2. Can make a guess at their location, with a certainty level (or error margin)
  3. Knows the rough distance and (maybe) direction of nearby Mejh friends
  4. Can communicate with nearby Mejh to get their calculated positions

There will also be some sort of oracle-Mejh, which has 100% certainty of location, but must remain stationary.

The goal of the game will be to expand your colony as large as possible. Find resources, have the Mejh workers mine them and take them back home, in order to build more Mejh (and oracles), to find more resources, ad infinitum.

I think it’s a fairly innovative idea, so we’ll see how it turns out! The main thing I like about this idea is it isn’t dependent on a highly skilled graphics or sound person – I can really get away with some nicely themed dev art for it – think Darwinia.

Not yet sure if I’ll throw the code on GitHub, or keep it all to myself, but I’ll certainly be keeping this up to date with how development is going. I’m leaning towards having it open, though.

As for development, here’s a bunch of details about my approach, and some rules I’m setting myself:

  • 100% browser based. No server component at all (at least, until I want multiplayer or high score tracking)
  • Frequent releases, possibly continuous deployment when I figure out how
  • 100% DI. In my 80ish lines of JS at the moment, I have a single ‘new’ statement. I plan to keep it that low
  • 100% TDD. No code unless I have first written a test for it. This excludes DI container setup. But this includes DOM manipulation
  • Maximum of 4 args per constructor. No logic beyond assigning instance variables in the constructor
  • No jQuery. I shouldn’t need it, and I want to use js without it for once
  • A blog post per night of coding. Two for tonight, because it’s my first go :)

I’m setting pretty stringent rules for DI and testing for a few reasons. There really isn’t that much of either in browser-based Javascript going on in the world. Heck, I doubt there’s even that much of it going on in Node.js land. I’m hoping to show how it can be done successfully for a non-trivial project, and perhaps give reference to those who want it (contingent on me opening up the code, of course). I’ve had a lot of success with DI and TDD in my professional career thus far (DI primarily in C#, TDD in both personal and work projects), but I often get lazy and thing “not a big deal this time…” and regret it later. Especially with constructor parameter counts. I want to push myself further, and this will provider a great opportunity to.

Stay tuned!

Asynchronous Tests and Javascript

A lot of Javascript unit testing frameworks out there provide an “asynchronous testing” feature, seemingly to get around the issue of testing things that use setTimeout, or uses xhr. The idea being if you want to test code like this, you can:

function setFoo() {
  setTimeout(function() { 
    window.foo = 'bar';
  }, 2000);
}

Replace setTimeout with $.ajax if you must, it amounts to the same thing.

Obviously the following test won’t work, since it needs a 2 second break:

setFoo();
window.foo.should.equal('bar');

Qunit gets around this by having a stop() and start() call

setFoo();
stop();
setTimeout(function() {
  start();
  window.foo.should.equal('bar');
}, 2000);

Jasmine has a similar thing, but with a waitsFor function

runs(function() { 
  setFoo(); 
});
waitsFor(function() { 
  return window.foo == 'bar'; 
}, 'window.foo should be set', 2000);
runs(function() { 
  window.foo.should.equal('bar'); 
});

I don’t know about you, but I don’t particularly want to have to wait around for 2 seconds to see if this test succeeds. The whole point of unit testing is to get rapid feedback when things break – 2 seconds per test is not what I’d call rapid!

There’s a much better way; take advantage of Javascript’s ability to replace practically anything – include setTimeout and XmlHttpRequest. Or, be lazy and let SinonJS do the walking for you:

var clock = sinon.useFakeTimers();
setFoo();
clock.tick(2000);
window.foo.should.equal('bar');
clock.restore();

Simple! Best of all, it’s synchronous! Debugging this sort of test, should you need to, is simple.

Basil comes with a Sinon adapter, which handles the setup and restoration of the timers for every test, so it boils down to:

setFoo();
this.clock.tick(2000);
window.foo.should.equal('bar');

For completeness, if you have web service calls as well:

function someRequest() {
  $.get('http://example.com/getSomeVariable', function(result) {
    window.foo = result;
  });
}

Using async support (in this case, of Jasmine):

runs(function() { 
  someRequest(); 
});
waitsFor(function() { 
  window.foo != undefined; 
}, 'foo should be set', 1000);
runs(function() {
  window.foo.should.equal('server result');
});

This bit actually has a few big problems, I’m not sure how people get around this:
1) What timeout should I use for waitsFor? What is a reasonable amount of time?
2) How do I know what the server returns? Why do I even care?
3) I cannot run this test locally (from a file:// URL) – it has a hard dependency on my web app running, which may not be desirable

So, let’s let SinonJS do the heavy lifting

var fakeServer = sinon.fakeServer.create();
fakeServer.respondWith('http://example.com/getSomeVariable', 'fake server content');
someRequest();
  
window.foo.should.be.undefined;

fakeServer.respond();

window.foo.should.equal('fake server content');

fakeServer.restore();

Again, Basil can take away the create() and restore() of the fake server, making it a whole lot leaner.

This test no longer has any connectivity constraints or timeout dilemmas and enabled control over expected return values.