Polymorphic rants http://www.lucagrulla.it Most recent posts at Polymorphic rants posterous.com Mon, 26 Sep 2011 01:41:00 -0700 Control flow in Javascript http://www.lucagrulla.it/flow-control-in-javascript http://www.lucagrulla.it/flow-control-in-javascript

Mark Needham recently wrote a blog post on how his team worked around a Javascript asynchronous unwanted behaviour.

They want to iterate over a collection, executes some code for each element of the collection and only when all the collection has been traversed execute a final step.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
//for the original blog post check
//http://www.markhneedham.com/blog/2011/09/25/jquery-collecting-the-results-from-a-collection-of-asynchronous-requests/

var people = ["Marc", "Liz", "Ken", "Duncan", "Uday", "Mark", "Charles"];
 
var grid = [];
$.each(people, function(index, person) {
  $.getJSON('/git/pairs/' + person, function(data) {
    // parse data and create somethingCool
    grid.push(somethingCool);
  });
});
 
// do something with grid

Obviously this didn't work. Due to the asynchronous nature of Javascript the do something with grid block is invoked before the grid itself is filled and nothing interesting happens.

 

Their final approach is solving the unwanted behaviour by mostly removing any possible event driven behaviour and handling control in a full imperative way, explicitly calling functions in the expected sequence.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// for the origina blog post check
// http://www.markhneedham.com/blog/2011/09/25/jquery-collecting-the-results-from-a-collection-of-asynchronous-requests/

var people = ["Marc", "Liz", "Ken", "Duncan", "Uday", "Mark", "Charles"];
asyncLoop(people, [], function(name, grid, callBackFn) {
  // parse data and create something cool
  grid.push(somethingCool);
  callBackFn();
}, function(grid) {
  // do something with grid
});

function asyncLoop(collection, seedResult, loopFn, completionFn) {
  var copy = collection.slice(0);
  (function loop() {
    var item = copy.shift();
 
    if(copy.length == 0) {
      completionFn(seedResult);
    } else {
      loopFn(item, seedResult, loop);
    }
  })();
}

This works but it's not leveraging Javascript nature, and the code itself results harder then what it should be.

How the same problem can be solved embracing asynchronous thinking ?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
function fecthData() {
  var people = ["Marc", "Liz", "Ken", "Duncan", "Uday", "Mark", "Charles"];
 
  var grid = [];
  $.each(people, function(index, person) {
    $.getJSON('/git/pairs/' + person, function(data) {
      // parse data and create somethingCool
      grid.push(data["name"])
      if (grid.length === people.length) {
        $(document).trigger("gridFilled", [grid]);
      }
    });
  });
}
 
 
$(document).bind("gridFilled", function(e, grid) {
   //ready to do something with grid !
})

The way to achieve control flow in Javascript is with events.

When a block is completed it emits an event. All the interested parties will be listening to the specific event and execute their specific job, contributing to our overarching business flow.

This alternative solution is probably also more idiomatic and as a consequence more coincise and easier to read.

Permalink | Leave a comment  »

]]>
http://posterous.com/images/profile/missing-user-75.png http://posterous.com/users/hd2akPlb4Tfom lucagrulla lucagrulla lucagrulla
Thu, 15 Sep 2011 12:13:00 -0700 Introducing node-tail: a NodeJS tail library http://www.lucagrulla.it/node-tail-a-nodejs-tail-library http://www.lucagrulla.it/node-tail-a-nodejs-tail-library

In the previous blog post I described the architecture of the firehose we built in Forward with NodeJS.

At the lowest level each node has to tail a log file.

Tom Hall and I couldn't find any useful cross-platform (i.e. not relying on the unix tail command) node module for that task, so I ended up writing node-tail:

Using node-tail is very simple:

1
2
3
4
5
6
7
Tail = require('tail').Tail;

tail = new Tail("fileToTail");

tail.on("line", function(data) {
  console.log(data);
});

node-tail is also available via npm, just install it with:

> npm install tail

 

Permalink | Leave a comment  »

]]>
http://posterous.com/images/profile/missing-user-75.png http://posterous.com/users/hd2akPlb4Tfom lucagrulla lucagrulla lucagrulla
Tue, 15 Jun 2010 22:41:48 -0700 Javascript testing http://www.lucagrulla.it/javascript-testing http://www.lucagrulla.it/javascript-testing Javascript has become in the last years the language for rich web applications,  but still it rarely receives the level of attention it deserves. Libraries such jQuery boost our productivity but the code we often end up writing tend  to be a big ball of mud, with an entangled mix of presentation logic, busines logic and server side interaction,  all incredibly hard to test and to maintain. It's time to move away from this approach and start writing better quality Javascript. The very first step required to avoid Javascript spaghetti code is start thinking to Javascript as a first class language, and start dealing with it with the same mindset and approach we would use for any server side language. With this new approach in the same way we identify roles and integration points  in server side code we want to start building abstractions in our Javascript codebase. With the right abstractions in place we are defining clear boundaries between different parts of the system, and as a consequence our code is simpler, we promote reuse  and the DRY principle, and  we are finally enabling better testing. Let's look at any standard Web 2.0 Javascript code from this new perspective: now the DOM and HTTP are two clear integration points. Our javascript code manipulates the DOM adding  nodes or changing existing nodes content in the same way any other language would interact with a database. Each call to a server over HTTP via Ajax is exactly the same of calling a web server from our server side code. With these very two first abstractions in mind, we can start rewriting our code, isolating these interactions behind clearly defined objects. Now the javascript code is not a ball of mud anymore, but a network of objects that collaborate. With these smaller objects  in place we can now favour interaction based tests, moving away from any dependency on the DOM and on the HTTP protocol. The identified abstractions let me actually mock  and stub things out and test if the different tiers in my javascript code are exchanging the right messages. This separation of concerns keep the business logic nicely isolated from the user interface transformations, enabling also a cleaner state based testing for that specific part of the code (there are no more dependencies on the DOM).

Permalink | Leave a comment  »

]]>