Saturday, February 26, 2011

Understanding Inheritance In JavaScript

In this article I will present the JavaScript inerhitence model in a concise, and I hope, easy to understand manner. The intended audience consists of developers with some previous experience with dynamically typed languages. It is my opinion that any difficulty associated with understanding the JavaScript inheritance model can be attributed to the difficulty teaching recursive definitions in general. It's sometimes hard to know where to start, when your definition is circular.

That said, let's boil JavaScript inheritance down into 5 key points in the following order:

1) In JavaScript, everything is an 'object' and all variables simply hold references to them. The other 'primitive' or basic types (of objects) are functions, booleans, strings, numbers and arrays.

2) Objects are collections of properties keyed by a reference. Most often, references to string objects are used as keys as they are immutable. This means that if foo and bar reference string types which contain the same data they are in fact the same object. This essentially makes Objects equivalent to hashes or dictionaries in other languages.

3) In JavaScript functions are special objects. Not only can they be called or applied, they have a special 'prototype' property which holds an object that can be accessed and modified. When a function is used as a constructor with the 'new' key word, the resulting object that is created will *dynamically* inherit from the object referenced by the constructor function's 'prototype' property.

Example:
  Constructor = function() { };
Constructor.prototype.name = 'alpha';
Constructor.prototype.say_name = function() { console.log("my name is: " + this.name) };
object = new Constructor();
object.say_name();


4) Upon initial definition, the prototype property of every new function can be thought of like this:
  func = function() {}
func.prototype = { 'constructor': func };

That is, the value referenced by func.prototype is an object contains a reference to func itself. This recursive definition is a bit eye-crossing but actually very beautiful in that way that only recursion can be.

5) Here's where the recursive definitions start to get difficult to visualize. In JavaScript, every object (including functions) dynamically inherit from the special 'Object.prototype' object. In other words, 'Object' is THE constructor function of ALL objects in the JavaScript universe. The corollary being that Object.prototype.constructor == Object.

Try it:
  > Object.prototype.constructor == Object
true

Implications


These 4 points form the foundation of inheritance in JavaScript. Let's make use what we've learned:

Corollary 1:


Object types, or 'classes' can be (and generally are) referred to by their contructor function. Examples: Object, Function, String, Boolean, Array etc.

Corollary 2:


If you want to add a method to every object in the javascript universe (even after it is constructed!), mess with Object.prototype.
Example:
> Object.prototype.foo = 'bar'
> func = function() {}
> func.foo
"bar"
> Object.prototype.foo = 'baz'
> func.foo
"baz"

Corollary 3:


There's no such thing as multiple inheritance in JavaScript. That is class 'Foo' can not inherit from both 'String' and 'Array' directly. Though, you can use some clever tricks to hack multiple inheritance into the language. For examples, see http://www.amirharel.com/2010/06/11/implementing-multiple-inheritance-in-javascript and http://code.google.com/p/joose-js/.

Ubunt+Node+cluster on Amazon EC2 Quickstart

Just Show Me The Scripts


If you're just looking for a script to setup nodejs under ubuntu quickly, check out this set of scripts.

Walk Through


First you'll need to Signup for AWS/EC2 and generate a key pair. Google it, there should be plenty of tutorials.

Next, create an instance using the AWS Management Console and log into it using your key pair. You can find the AMI's here. I picked a 32bit 10.04 LTS AMI in US-East.

Install node's perquisites (or those that aren't the default ubuntu LTS ami):
  sudo apt-get update
sudo apt-get -y install build-essential libssl-dev

Now let's create a nodejs system user:
  sudo adduser --home /home/nodejs --shell /bin/bash --disabled-password --disabled-login --system nodejs

Now login as that user:
  sudo su nodejs

For the heavy lifting we use the excllent 'nvm' from creationix
  git clone git://github.com/creationix/nvm.git ~/.nvm
. ~/.nvm/nvm.sh

Install nodejs:
  nvm sync
time nvm install latest
nvm use latest

Setup the nodejs user's enviroment to have that latest nodejs in it's path
  echo -e -n "\n. ~/.nvm/nvm.sh\n" >> ~/.bashrc
echo -e -n "\nnvm use latest\n" >> ~/.bashrc

Setup npm, this makes life much easier:
  mkdir ~/git
cd ~/git
git clone https://github.com/isaacs/npm.git
cd npm/
make install

Taking Full Advantage Multiple Cores/CPUs


Assuming you want to take full advantage ec2's multiple cores then install 'cluster' - https://github.com/LearnBoost/cluster
  npm install cluster

Setup hello world example:
   mkdir ~/git/sandbox
cd ~/git/sandbox

Edit cluster.js to contain cluster example:
      var cluster = require('cluster')
, http = require('http');

var server = http.createServer(function(req, res){
console.log('%s %s', req.method, req.url);
var body = 'Hello World';
res.writeHead(200, { 'Content-Length': body.length });
res.end(body);
});

cluster(server)
.use(cluster.logger('logs'))
.use(cluster.stats())
.use(cluster.pidfiles('pids'))
.use(cluster.cli())
.use(cluster.repl(8888))
.listen(3000);

Test it!
  node cluster.js

Using the domain you ssh'd into earlier, browse to http://:3000, you should see hello world.

From the EC2 instance, login into the cluster admin interface:
  telnet 0 8888
Type help()

Saturday, February 12, 2011

Realtime Performance Visualizations using Node.js

Preamble


This article outlines how to create a realtime heatmap of your syscall latency using HTML5, some great node modules, and DTrace. It was inspired by talk that Bryan Cantrill and Brendan Greg gave on Joyent's cool cloud analytics tools. While specific, the code provided could easily be adapted to provide a heatmap of any type of aggregation Dtrace is capable of providing.

System Requirements



First thing's first, you're going to need a system with DTrace. This likely means Solaris (or one of its decedents), OS X, or a BSD variant. There doesn't appear to be Dtrace available for Linux.

Security


Secondly, please be aware that at the time of writing the demo code contains a fairly substantial secruity vulnerabilty. Namely the d script is sent from the client with no authentication what so ever. If you bind to localhost this shouldn't be a big deal for a demo. Time permitting I intend to clean up the code.

Dependencies


For this tutorial you'll also need:

node - http://nodejs.org/#download (duh)
npm - https://github.com/isaacs/npm (makes installing modules a breeze)
node-libdtrace - https://github.com/bcantrill/node-libdtrace (provides dtrace functionality)
Socket.IO - 'npm install socket.io' (websockets made easy)

Server


Now we're ready to start writing our web server:

heat_tracer.js

Client


In order to display our heatmap, we're going to need some basic HTML with a canvas element:

heat_tracer.html

Finally the JavaScript client which translates the raw streaming data into pretty picture:

heat_tracer_client.js

Run It!


Run Heat Tacer with the following. Note, sudo is required by dtrace as it does kernal magic.

sudo node heat_tracer.js

If all goes well you should see a moving version of something like the image below.



Contribute


You can find the latest version of Heat Tracer here. It is my hope that this article will provide the ground work for a much more abitious performance analytics project. If you're interested in contributing please let me know.

Further Research


More information about Bryan and Brendan's demo can be found here
Socket.IO can be found here.

Labels: , , ,