The Work and Flow of JavaScript Development: Adding a Feature

This post is the third in a series on The Work and Flow of JavaScript Development. The first two posts covered Getting Started and Continuous Delivery.

In my earlier posts about The Work and Flow of JavaScript Development, I started by defining work and flow; Work is anything that I aim to accomplish during the course of day-to-day coding, deploying, and architecture designs. Flow covers the way in which the work is done and with which tools and rhythm I use to get those things done. The second entry on the topic dove into the tooling to set up continuous integration and a project repository. I followed that up with a deployment test to Windows Azure from the Github Repository.

Flowing

As a structure for the series, I introduced the user story “The end user wants to be able to list the geek badges they’ve attained through hackathons, contributions on github and other places.” To manage the user stories I will turn to a tool like Github’s Issues and for a Kanban board I’ll use Huboard. (Kanban is a method for managing knowledge work that displays tasks and lets team members pull work from a queue and track the progress of items from backlog, read, working, and on to done. Huboard creates a virtual Kanban board.)

I’ll add the user story as an issue in Github as shown.

wf1

After adding the user story as an issue, I’ll open up Hoboard and navigate to that project. In Huboard the user story is listed under the Backlog.

wf2

Next, I’ll skip using the backlog and move the item immediately to the working column.

wf3

In WebStorm I’ll click on the preferences command button to bring up the mocha testing options.

wf4

After that I’ll add the paths to the tests directory and the working directory.

wf5

I’ll click OK and then execute the tests with mocha by adding a simple “test the testing framework is installed right test.


var assert = require("assert")
describe('The Project Tests', function () {
   it('should work, true?', function () {
       assert.equal(true, true);
   })
})

That execution returns a green light, showing I’ve got a functioning test, the framework integration in WebStorm is working, and the mocha framework itself is installed and working.

wf6

Working

Once the housekeeping around the user story is finished, it’s time to sling some code. I’m generally intent on avoiding the haphazard cowboy code route. Cowboy coding leads to many things, but rarely does it lead to a finely tuned app. For that we need a solid deploy process and some testing. So I’ll throw out the cowboy approach in favor of a resilient and disciplined Test Driven Development (TDD) or Behavior Driven Development (BDD) approach.

For this feature I’ll go with a simple mixed TDD and BDD approach. To describe that a bit more, I’ll use some wording that would be familiar to BDD such as “X thing should do Y functionality for A, B, C reasons.” The nice thing about BDD is that I can take the user story and break it down into more refined tests that detail exactly what I’m doing in plain written language. Some examples would be:

  • The application page should display the results in an itemized list for the viewing user.
  • The application page should display the results inclusive of X, Y, and Z columns for the viewing user.

In this case, I’ll start with just these two behavioral assertions about the data itself. Those will give me enough to start putting together some tests. These first tests serve two purposes: First, they get the project started in a test-first practice providing confirmation that I have the sample testing data built correctly. Second, they begin the process of refactoring as additional tests are put together. Tests need to be refactored regularly during additional code being added for implementation of the desired functionality. My first test will be a simple one to verify the list of a known set of items has the appropriate number of items.


var assert = require("assert");
var Badges = require("../Models/Badges");
var badges = new Badges();

describe('The application page', function () {
   it('should have data with the results in an itemized list of badges.', function () {
       var number_of_badges = badges.get_badges().length;
       assert.equal(number_of_badges, 4);
   })
})

This test will fail, since there are no Badges to create a badges object that has a length. So let’s put together an object to provide a list of the data. I’ve put together a sample data set that looks like this in a file called Badges.js.


var badges = [
   {
       badge : "Knode",
       shape : "polygon-6",
       height: 200,
       width : 200,
       size  : 42,
       url   : "images/knode.png"
   },
   {
       badge : "Nordic JS",
       shape : "square",
       height: 160,
       width : 160,
       size  : 11,
       url   : "images/nordic.png"
   },
   {
       badge : "JavaScript",
       shape : "square",
       height: 300,
       width : 300,
       size  : 8,
       url   : "images/JavaScript.png"
   },
   {
       badge : "Node PDX",
       shape : "rectangle",
       height: 319,
       width : 623,
       size  : 146,
       url   : "images/NodePDX.png"
   }
];

function Badges () {
}

Badges.prototype.get_badges = function () {
   return badges;
}

module.exports = Badges;

For now this badges object is just set up to instantiate based on a constructor function that is empty. The function get_badges actually returns the data once the object is created. Finally, at the end I’ll export the Badges object via modules.exports.

Now when I run the test, I have a green light representative of successfully implemented functionality. Next up is writing a test to ensure I have particular pieces of data coming back, specifically the name of the badge, simply labeled badge, and the height, width, and URL of the image for the badge.

My first effort at testing this looked something like this:


it('should have data with the results including badge name column.', function () {
   var badge_exists = true;
   var working_badges = badges.get_badges();
   for (var i = 0; i < working_badges.length; i++){
       if (working_badges[i].badge === "" ||
           working_badges[i].badge === null ||
           working_badges[i].badge === undefined){
           badge_exists = false;
       }
   }
   assert.equal(badge_exists, true);
})

This test passes, but if I add an empty record to the JSON data from the Badges object then the test fails. Since I’m assuming good data in this first implementation I’ll leave the sample data alone, which this test verifies just fine.

I could add this same test for the other three fields I want to verify are included in every set of data that is returned. However, there’s a bit too much copy and paste to this test, so I’m going to refactor it a bit. I’ll extract the if statement testing for the particular field out into a function, using WebStorm’s extract method feature. This code now stands by itself in a global function.


function verify_field (working_badges, i, badge_exists) {
   if (working_badges[i].badge === "" ||
       working_badges[i].badge === null ||
       working_badges[i].badge === undefined) {
       badge_exists = false;
   }
   return badge_exists;
}

A few more minor modifications to change the passed in parameters to the_field shown in the code snippet below. The the_field parameter would be the passed in field to provide verification against whether it exists or not. After this refactor I’d whittled the code down to this:


function verify_field (the_field) {
   if (the_field === "" ||
       the_field === null ||
       the_field === undefined) {
       return false
   }
   return true;
}

The test calling the verify_field function now looks like this:


it('should display the results including badge name column.', function () {
   var badge_exists = true;
   var working_badges = badges.get_badges();
   for (var i = 0; i < working_badges.length; i++){
       badge_exists = verify_field(working_badges[i].badge);
   }
   assert.equal(badge_exists, true);
})

That’s a bit cleaner. So I’ll move on to refactoring the for loop. I’ll clean that code up to a slightly different logic, as shown. Basically it looks for any non-existent field and immediately throws a false flag by returning it to the calling function. This speeds up the test and reduces recursively executing code that doesn’t need to run if a false if for the_field is found.


function check_fields (working_badges, field) {
   for (var i = 0; i < working_badges.length; i++) {
       if (verify_field (working_badges[i][field]) === false){
           return false;
       }
   }
   return true;
}

After that the actual test was down to a much more reasonable two lines:


it('should display the results including badge name column.', function () {
   var working_badges = badges.get_badges();
   assert.equal(check_fields (working_badges, badge_exists), true);
})

There was one more refactor, by simply moving the working_badges variable to the global level of the test file I could then write a single-line test for all of the other columns. The remaining tests take the following form:


it('should have data with the results including badge name column.', function () {
   assert.equal(check_fields (working_badges, 'badge'), true);
})
it('should have data with the results including height column.', function () {
   assert.equal(check_fields (working_badges, 'height'), true);
})
it('should have data with the results including width column.', function () {
   assert.equal(check_fields (working_badges, 'width'), true);
})
it('should have data with the results including url column.', function () {
   assert.equal(check_fields (working_badges, 'url'), true);
})

Now I’ll take a look at the actual page in which we want to display this data. For now I’m going to directly display this data in the index.jade page. In the index.js file I’ll instantiate the badges object and call the data to work with. Then step through and build the text into a simple string.


var Badges = require ("../Models/Badges");
var badges = new Badges ();

exports.index = function (req, res) {
   var working_badges = badges.get_badges();
   var display_text = '';

   for (var i = 0; i < working_badges.length; i++){
       display_text += working_badges[i].badge;
   }

   res.render ('index', { title: 'The Badges Ribbons and Stars App', the_badges: display_text});
};

In the index.jade file I’ll make a minor addition of the div #{ the_badges } to display the text in a div tag in the page.


extends layout

block content
   h1= title
   p Welcome to #{title}

   div #{ the_badges }

This provides us a display of the badge names, like this:

wf8

Summary

Following this work and flow I now have a page, with data displayed. The unit tests confirm the “happy path” from the beginning of the idea (user-story creation) to the implementation, testing, and execution of the code in a working page.

The next step is to build on that, create more user stories, and build out the display of the data. Stay tuned for the conclusion of the series where I’ll work on that and add some final notes on the work and flow of JavaScript development.

adronhall@gmail.com'

Adron Hall is a jovial, proactive, test & code, code & test, get things done well, software architect, engineer, code monkey, coder, and distributed systems advocate. As a coder, Hall plies a polygot language path including C#, Java, JavaScript, and Erlang lately -- as well as Pascal, Basic, Visual Basic, C++, C, COBOL, RPG, CL, and others in the past. He founded Deconstructed.io with Aaron Gray, Node PDX with Troy Howard, and more startups are in the works. You can read his blog at Composite Code (http://compositecode.com). View posts by .

Interested in writing for New Relic Blog? Send us a pitch!