Category: Javascript

A builder pattern implementation in Javascript

We’re using the builder pattern on our javascript project, as it useful for starting off with a set of defaults, but is clear when we want to override particular values. Although there are a few places on the net that describe who uses the builder pattern in javascript, they don’t really provide an implementation.

Here’s one that works for us:

var Builder = function() {
  var a = "defaultA";
  var b = "defaultB";
  
  return {
      withA : function(anotherA) {
        a = anotherA;
        return this;
      },
      withB : function(anotherB) {
        b = anotherB; 
        return this;
      },
      build : function() {
        return "A is: " + a +", B is: " + b;
      }
  };
};

var builder = new Builder();

console.log(builder.build());

var first = builder.withA("a different value for A").withB("a different value for B").build();

var second = builder.withB("second different value for B").build();

var third = builder.withA("now A is different again").build();

console.log(first);
console.log(second);
console.log(third);

Cheat Sheet for Javascript Testing with Jasmine

Jasmine is the default unit testing framework that I use when writing javascript, however my poor brain can’t always remember all the different ways of getting things to work. There are quite a number of cheat sheets out on the internet including:

They don’t quite cover all the examples as well. Here’s my contributions to demonstrate some of the common uses.

describe("jasmine", function () {

    describe("basic invocations", function () {

        var SampleDependency = function () {
            return {
                usefulMethod:function (firstParameter, secondParameter) {
                },
                anotherUsefulMethod:function () {
                }
            };
        };

        var Consumer = function (dependency) {
            return {
                run:function () {
                    dependency.usefulMethod("first", "second");
                },
                runSecondMethod:function () {
                    dependency.anotherUsefulMethod();
                },
                runWithRequiredCallback:function(callback) {
                    callback("an argument");
                }
            };
        };

        it("should spy on an existing function", function () {
            // given
            var dependency = new SampleDependency();
            spyOn(dependency, "usefulMethod");
            var consumer = new Consumer(dependency);

            // when
            consumer.run();

            // then
            expect(dependency.usefulMethod).toHaveBeenCalled();
            expect(dependency.usefulMethod).toHaveBeenCalledWith("first", "second");
            expect(dependency.usefulMethod).toHaveBeenCalledWith(jasmine.any(String), jasmine.any(String));
            expect(dependency.usefulMethod.callCount).toEqual(1);
            expect(dependency.usefulMethod.mostRecentCall.args).toEqual(["first", "second"]);
        });

        it("should demonstrate resetting of the spy", function () {
            // given
            var dependency = new SampleDependency();
            spyOn(dependency, "usefulMethod");
            dependency.usefulMethod();
            dependency.usefulMethod.reset();

            // when
            dependency.usefulMethod();

            // then
            expect(dependency.usefulMethod).toHaveBeenCalled();
            expect(dependency.usefulMethod.callCount).toEqual(1);
        });

        it("should demonstrate creating a spy object with prepopulated methods", function () {
            // given
            var dependency = jasmine.createSpyObj("dependency", ["usefulMethod", "anotherUsefulMethod"]);
            var consumer = new Consumer(dependency);

            // when
            consumer.run();
            consumer.runSecondMethod();

            // then
            expect(dependency.usefulMethod).toHaveBeenCalled();
            expect(dependency.anotherUsefulMethod).toHaveBeenCalled();
        });

        it("should demonstrate creating a stub object", function () {
            // given
            var dependency = jasmine.createSpyObj("dependency", ["usefulMethod", "anotherUsefulMethod"]);
            var consumer = new Consumer(dependency);
            var stubbedCallback = jasmine.createSpy("stub callback");


            // when
            consumer.runWithRequiredCallback(stubbedCallback);

            // then
            expect(stubbedCallback).toHaveBeenCalled();
            expect(stubbedCallback).toHaveBeenCalledWith("an argument");
        });
    });


    describe("returning a value", function () {
        var Dependency = function () {
            return {
                getMultiplier:function () {
                    return 10;
                }
            };
        };

        var Consumer = function (dependency) {
            return {
                calculateSomethingWithMultiplier:function (number) {
                    return number * dependency.getMultiplier();
                }
            };
        };

        it('should be correct', function () {
            // given
            var dependency = new Dependency();
            spyOn(dependency, "getMultiplier").andReturn(40);
            var consumer = new Consumer(dependency);

            // when
            var result = consumer.calculateSomethingWithMultiplier(3);

            // then
            expect(result).toEqual(120);
        });
    });


    it("should demonstrate creating a stub that returns a value", function () {
    });

    describe("creating a stub that calls a fake", function () {
        var Dependency = function () {
            return {
                request:function (callback) {
                }
            };
        };
        var Consumer = function (dependency) {
            var capturedValue = "";
            return {
                hardAtWork:function () {
                    dependency.request(function (value) {
                        capturedValue = value;
                    });
                },
                getCapturedValue:function () {
                    return capturedValue;
                }
            };
        };

        it('should demonstrate creating a stub function that does something interesting', function () {
            // given
            var dependency = new Dependency();
            spyOn(dependency, "request").andCallFake(function (callback) {
                callback("Controlled return value from callback");
            });
            var consumer = new Consumer(dependency);

            // when
            consumer.hardAtWork();

            // then
            expect(consumer.getCapturedValue()).toEqual("Controlled return value from callback");
        });

    });
});

RequireJS is the Spring Framework of Javascript

I’ve been working on setting up the infrastructure for a mostly javascript based project, and we’ve been putting RequireJS into the codebase to help us manage the file dependencies instead of having to declare them within the page that is using them. As a concept, RequireJS is helping us keep different javascript modules apart in different files and let’s us assemble them.

RequireJS works by declaring dependencies and having the framework pull them in when you need them.

define(["aDependency"], function(theDependency) {
  // now I can do something with theDependency
  theDependency.aMethodOnIt();
})

This is pretty much how spring works, but the issue I have is that RequireJS manages the lifecycle of the javascript objects, so when you want to pass in a substitute for a test, you end up in a dilemma.

define(["aDependency"], function(theDependency) { // how do I get inject a different instance?
  // now I can do something with theDependency
  theDependency.aMethodOnIt();
})

Unsurprisingly a number of people wrote libraries such as testr which allow you to override the requirejs to inject different versions. Although very reasonable approaches, I find this approach a little bit smelly as you’re effectively patching a library you don’t own. The ruby community know the dangers of monkey patching too much, particularly those parts of a code base you cannot control and the potential issues you face when you try to upgrade.

Our current approach involves using RequireJS to manage the file/name dependencies, but for us to write javascript that allows us to control the instances of the objects that we want. Here’s an example:

dependency.js

define([], function () {
    return function () {
        return {
            doSomeWork:function () {
            }
        };
    };
});

consumer.js

define([], function () {
    return function (aDependency) {
        var dependency = aDependency;
        return {
            start:function () {
                dependency.doSomeWork();
            }
        };
    };
});

And then we control the lifecycle of the components and instances in the application using the following code.

main.js

define(["consumer", "dependency"], function (Consumer, Dependency) {
    var dependency = Dependency();
    var consumer = Consumer(dependency);
    consumer.start();
});

And our jasmine tests get to look like this:

requirejs = require('requirejs');

describe("consumer", function() {
    it("should ensure the dependency does some work", function() {
        // given
        var dependency = jasmine.createSpyObj("dependency", ["doSomeWork"]);
        var consumer = requirejs("consumer")(dependency);

        // when
        consumer.start();

        // then
        expect(dependency.doSomeWork).toHaveBeenCalled();
    });
});

This approach has been working out well, forcing us to manage the dependency and global hell that javascript global functions can quickly become. Thoughts? Please leave a comment.

“fs is not defined” in jasmine-node version 1.0.28

I was using jasmine-node this weekend (package.json says it’s version 1.0.28) and hit this error:

../node_modules/jasmine-node/lib/jasmine-node/cli.js:89
        var existsSync = fs.existsSync || path.existsSync;
                         ^
ReferenceError: fs is not defined

It looks like this has already been reported here as Issue #186. The quick fix is to add the require declaration in yourself at the top of the file.

var js = require('fs');

Goto Aarhus 2012

This year was my first time to both attend and present at Goto Aarhus. Over the years, many of my colleagues have said that it’s one of the best conferences with topics in lots of different areas. This year focused on topics such as NoSQL, Big Data, Humans at Work, Javascript, Continuous Delivery, Cloud and many more areas.

Two of the best presentations I attended, both for content and delivery were Sam Newman and Jez Humble, author of Continuous Delivery (Disclaimer: They are my colleagues after all). What I enjoyed about their talks were both their talk about real world examples, as well as important advice as well as the delivery. Getting the balance right is really difficult to do.

I also really liked the keynote from Dirk Duellmann from CERN who talked about the big data challenges they have storing information. Although it took a while to get to the meaty part of the data, storage details I think it’s a very interesting outlook they have with architectural choices such as the view that they cannot design for hardware or devices today as these will be obsolete as time goes forward. Being able to retrieve historical information is important as it the ability to store all of the data in a format others can read. They have realised the importance of the scale of the work they are doing, so they are focusing on doing something good (storing and making available data) and working with other groups to do the analysis.

There were loads of highlights such as meeting many new people and connecting with old ones as well as some interesting side conversations.

I gave my talk (above) and was very happy with the results. The Trifork team behind the conference are awesome at getting feedback to presenters for quickly and I was very happy with the results. The conference uses a simple voting system for feedback (red, yellow, green) and they keep track of the number of walk outs. I ended up with 90 green, 26 yellow, 1 red and only 2 walkouts. I have no idea how that compares with other speakers but I’m pretty happy with the results. What I also appreciated were the people who came up afterwards to talk to me about how the topic is really important and what some people got out of it (affirmation they are doing the right thing, new ideas to take back, new books to read, more things to focus on, or a good idea of how to prepare as they step into the role).

Testing Pattern: Exploratory API via the Web

Last year I was working with Tiest, a former colleague of mine at a bank working on a system with an internal API. It was quite an experience, though I will save that for another (set of?) blog posts for another time. The application was centrally hosted with a client API that allowed people to interact with the server side. The testers needed something to help them do more exploratory testing and my former colleague came up with a great solution to this problem that I thought would be worth recording here for posterity.

Our solution had these characteristics:

  • Provided through a web browser – Installing items onto the testers machines became a bit laborious, namely because they didn’t have rights to install, change or run anything with administrator privileges. It was easier to deploy the tool centrally, and then let the testers prod from afar. This was as simple as writing a page that submitted some code to a web server, that than executed it and returned the results back to the client.
  • Supported dynamic execution – We could have written a web layer on top of the client API but we didn’t really want to add another layer for maintenance. We simply used the javax.script package to turn our standard POJOs into a scriptable/dynamically invokable system.
  • Built in reflection functions – Using the scripting interface meant that the server would not store any state. So the server had a number of built in functions such as a listAll(object) that would show all available property/methods to the user
  • Example queries stored on a wiki – When a tester would ask for something to be checked against the test environment, I would convert it into an appropriate query they could paste into the query browser window. They could then execute it, tweaking parameters, etc and learn to compose things. They didn’t have to really understand how java (as script) worked, just build on what was there.

Although I won’t be reaching into my testing patterns toolkit for this pattern too often, I feel it worked well to enable our non-technical testers to get at something given a number of environmental constraints.

Scandev 2011 Summary

A couple of weeks ago 700 geeky Swedes (and a handful of other Scandinavian people) descended on Gotheburg to attend Scandanvian Deveopers Conference. It was the first year that I went along and enjoyed the experience of this conference.

The two days had plenty of options – with eleven (yes eleven!) parallel tracks including language specific ones (java, .net), mobile, upcoming things, agile methods, web, SOA, etc. Something for everyone for the most part. This invariably brought a whole collection of interesting speakers from plenty of different walks of life. I met plenty of new people and reconnected with many others.

My key takeaways
Just like many of my colleagues, I’m interested in the “what could” be for functional programming. I have my own thoughts on its applicability, relevance and maintainability to my day to day work, however I made myself attend several sessions to see what it was. Neal Ford (great presenter as usual) did a great introductory session to the mindset behind functional programming. I’m glad to see that my studies in this at university meant a lot of it I already understood (first class functions, recursion, etc). I understood, though can’t extrapolate the strength of closures (at least the way that Neal was describing them), and the real world application of currying.

I enjoyed listening to Douglas Crockford talk about the new changes in the upcoming update to the Javascript language. I found him honestly refreshing – talking about which features to avoid (and why) and which things have been added to make users’ lives much easier and still maintain backward compatability. I can’t say that I learned a lot that I could immediately apply but had to laugh at pictures like this:

I also really enjoyed Matthew McCullough’s talk on git that was both insightful and entertaining on the internals, practicals and plenty of live demonstrations using the tool. As a fairly new user to the tool, I learned quite a bit and know more about what I don’t know and can work to fill that gap.

I have to admit the keynotes didn’t really get me thinking any differently, but I think that’s more of a function of having followed Alistair Cockburn’s thoughts for some time and having worked with and understanding change (the topic that Henrik Kniberg talked about).