Work

I am a principal at Develogical, a software development consultancy based in London, UK. We specialise in agile software development practices, training, education and research.

I also teach at Imperial College and Oxford University, and am involved with the UK agile community.

Contact

robert at chatley dot com

Play

I play the violin and I like cycling.

Recent Articles


On Learning JavaScript

In the last week, I have been learning JavaScript. Like many people, I had previously written little bits and pieces of JavaScript on web projects to try and make various bits of HTML pages dynamic, but I’d never looked at it in depth as a proper programming language. I’ve now come to quite like it.

I think that one of the things that affects people’s judgement of JavaScript is the environment of the browser and the interaction with the DOM. With all of the browser inconsistencies, and the clunkiness of the DOM API, the experience of writing JavaScript can be a bad one. I know I certainly never enjoyed it before. It never really felt like a proper language, but now I think I just wasn’t doing it right. Somewhere this week I read that JavaScript is the only language that people feel that they don’t need to learn before they use it. Development often follows a post-modern approach of Googling for snippets and pasting them into HTML pages.

I wanted to give JavaScript a chance as a proper language, so I wanted to try it away from the browser. Thankfully, the current popularity of node.js means that there is an easy way to try out programs using a command-line interpreter. Not everything you write in node needs to be a web server. It is a full JavaScript interpreter built on V8, so it can run any valid script. The other tool that I wanted was something to do unit testing. I find that test-driven development is a very helpful approach in learning a new language, as for every example I try it can give me fast feedback on whether or not my code works as I expect. I looked around for a unit testing tool for node, getting some good advice from David Harvey and Raoul Millais. In the end I settled on jessie, which is an enhanced runner for jasmine, and allows you to write rspec-like specs, and to run them easily from the command line.

The other thing I needed was a source of knowledge. I read two books which I found helpful. The first was Douglas Crockford’s JavaScript: The Good Parts. This is a good introduction, laying out the fundamentals of the language. It is reasonably short and easy to understand. It does not cover the who language - as the title says, only the subset that Crockford considers the good parts. It is a little concerning that the book has appendices called Bad Parts and Awful Parts. The style of this book is terse, at some places to the point of bluntness, but it is quite easy to read. To accompany this, I found it useful to watch the Google I/O presentation by Alex Russell. This covers few basics, but gives an idea of how to think about the language. The second book I read was Stoyan Stefanov’s JavaScript Patterns. This book is much more advanced. It does have an introduction to the language but it moves pretty fast. Don’t read this book as your first JavaScript book. It is good though, and has lots of useful information about object-creation, inheritance mechanisms and design patterns.

The main characteristics of the language as far as I can see, some of which were slightly surprising to me, are: JavaScript is a functional language and functions are first class citizens; Functions are the only way to define scope; There are no classes; Almost everything is an object; Almost everything is mutable. These characteristics make it very different from its (almost) namesake Java, which is another source of confusion. There seem to be many ways to try to make JavaScript work more like Java, by implementing things that are a bit like classes and classical inheritance, but I now see that doing this is not really in the idiom of the language.

I thought I would just run through one of the examples that I’ve put together this week, which helped me to understand things better. It’s writing a program to generate the Fibonacci sequence, something that I’m sure most programmers have done at least a few times in their lives in programming exercises. To start with I wrote a test:

require('./fibonacci')

describe("Fibonacci Sequence", function() {
	
  var fib = new FibonacciSequence();

  it("defines the first two terms to be 1", function() {
    expect(fib.term(0)).toEqual(1);
    expect(fib.term(1)).toEqual(1);
  });
		
  it("has each term equal to the sum of the previous two", function() {
    expect(fib.term(2)).toEqual(2);
    expect(fib.term(3)).toEqual(3);
    expect(fib.term(5)).toEqual(8);
  });

});

This uses a test syntax pretty similar to the rspec syntax that may well be familiar to Ruby programmers. Although it looks like we’re using new to create an object of the class FibonacciSequence, there are no classes in JavaScript. We’re calling a constructor function, that returns a new object, but there are no classes. Here’s the implementation.

FibonacciSequence = function FibonacciSequence() {
  this.term = function (i) {
    if (i === 0) { return 1; }
    if (i === 1) { return 1; }
    return this.term(i - 1) + this.term(i - 2);
  };
};

We should also specify what happens in the case of a negative argument. Let’s say we expect an exception to be thrown. We can add a test for that:

  ...
  it("is not defined for negative terms", function() {
    expect(function() { fib.term(-1); } ).toThrow("Argument may not be negative: -1");
  });
  ...

Note how the expectation has to be set up slightly differently, as we don’t want to call the piece of code that we’re expecting to throw an exception while we’re in the middle of setting up the expectation. We wrap the code we want to test in an anonymous function, and pass that to jessie for it to call later, when the time is right. In the implementation, we throw an error in a fairly standard way. The only thing to note is that as JavaScript isn’t strongly typed, we don’t have to throw something that is a sub-type of a particular exception class. There are no classes. So we can throw whatever we want. Here I just threw a string, although you could easily construct your own exception object if you preferred. Updating the implementation gives us:

FibonacciSequence = function FibonacciSequence() {
  this.term = function (i) {
    if (i < 0) { throw "Argument may not be negative: " + i.toString(); }
    if (i === 0) { return 1; }
    if (i === 1) { return 1; }
    return this.term(i - 1) + this.term(i - 2);
  };
};

Update:

After posting this, Raoul commented that it would have been more idiomatic to return undefined rather than throwing the error in the above example. It would also seem to fit rather better with the problem domain, given the way I named my test. Changing this gives the below:

...
 it("is not defined for negative terms", function() {
   expect(fib.term(-1)).toBeUndefined();
 });
...
FibonacciSequence = function FibonacciSequence() {
  this.term = function (i) {
    if (i < 0) { return undefined; }
...

The other feature that I wanted to implement was the ability to iterate through the sequence, rather than just calculating specific terms. As the sequence is mathematically infinite, an internal iterator wasn’t going to be much use here, as although it would be very easy, and idiomatic, to pass in a closure to apply to each element of the sequence, this might never terminate. At least for this example, we want an external iterator.

  it("can be iterated through", function() {
    var seq = fib.iterator();
    expect(seq.next()).toEqual(1);
    expect(seq.next()).toEqual(1);
    expect(seq.next()).toEqual(2);
    expect(seq.next()).toEqual(3);
    expect(seq.next()).toEqual(5);
  });

  it("can have multiple independent iterators", function() {
    var seq = fib.iterator();
    expect(seq.next()).toEqual(1);
    expect(seq.next()).toEqual(1);
    expect(seq.next()).toEqual(2);
  
    var seq2 = fib.iterator();
    expect(seq2.next()).toEqual(1);

    expect(seq.next()).toEqual(3);
    expect(seq.next()).toEqual(5);
  });

Implementing this turns out to be quite straightforward. One of the key messages from Alex Russell’s talk mentioned above was that when we program in JavaScript we need to reverse our thinking, from objects where we store data and then attach behaviour, to functions which - through the mechanism of closure - have data storage attached. Here my iterator function is defined as a property of the sequence object, so I can access it from the sequence, and when I call it, it returns a new object which is the iterator, with a next() method. The iterator’s index is just a local variable inside the iterator() function, whose state is maintained as part of the closure. We don’t need to store it in a field. The only thing that looks slightly strange, and took me a while to get my head around, was the need to make the assignment that = this. We need this in order to store a reference to the sequence object inside the closure, otherwise we won’t later have access to the term() method. This is due to the “special” way in which the keyword this works. JsLint wasn’t very happy about me using the ++ operator to increment i, but I thought it could keep its opinion to itself on that one.

FibonacciSequence = function FibonacciSequence() {
  this.term = function (i) {
    if (i < 0) { throw "Argument may not be negative: " + i.toString(); }
    if (i === 0) { return 1; }
    if (i === 1) { return 1; }
    return this.term(i - 1) + this.term(i - 2);
  };
  this.iterator = function () {
    var i = 0, that = this;
    return {
      next: function () {
        return that.term(i++);
      }
    };
  };
};

So that is the end result, and I think it looks quite neat. It is pretty functional in style. It doesn’t define any types or classes, only functions, and the test looks pretty much like an rspec test. Overall I’m quite pleased with the way I was able to write programs in JavaScript once I understood how it worked, and what was idiomatic. I feel I should pursue this some more, especially with the growing interest in Node in the industry.