Learning Closure: managing dependencies and compiling

Google’s closure library offers semantics and tools to manage dependencies between modules. This is specially useful when building single-page javascript applications.

To find out how smoothly this works, I’ll build a simple javascript application that given a string, displays its MD5 hash. We’ll

If you have used jQuery you’ll find that this code is verbose and painfully similar to java.

To ease your mind, think that structured libraries like Closure and YUI tend to promote more readable and maintainable code (at the expense of coolness).

Closure and YUI are a better fit when the goal is to build a complex application.

Try this at home

See the demo of the sample application discussed below.
You can browse browse or download all source code discussed here, including all 3rd party libraries. I welcome all comments and corrections.

Project setup

Create an empty directory (i called mine goog-dependencies-example), enter it and download all the stuff

You should now have a structure like this:

goog-dependencies-example\
  |-- closure-templates\
  |-- closure-library\
  |-- jshash-2.2\

Publish this directory on a web server.

During development, I use
lighttpd with this minimal configuration file to quickly publish just a directory. Save the file in the directory you want to publish, run lighttpd -D -f lhttpd-minimal.txt and browse to http://localhost:3030/. Lighttpd is available on ubuntu, macos (via macports) and windows (via cygwin).

UI: template

We need a ui component with a textarea to input some text, a button to execute and and a textarea to see the results. Using closure template is definitely overkill here, but it’s useful to demonstrate how to load templates a dependencies.

Create the file md5.ui.template.soy

{namespace net.caprazzi.md5.ui.template}

/**
 * md5 ui template
 * To retrieve its contents, invoke the function
 * net.caprazzi.md5.template.ui.main()
 */
{template .main}
<div class="md5-ui">
	<textarea class="md5-input"></textarea><br/>
	<button class="md5-action">Hash It!</button><br/>
	<textarea class="md5-output"></textarea><br/>
</div>
{/template}

And execute this command to compile it to a javascript file:

$ java -jar closure-templates/SoyToJsSrcCompiler.jar \
	--shouldProvideRequireSoyNamespaces \
	--outputPathFormat js/md5.ui.template.js md5.ui.template.soy
// This file was automatically generated from md5.ui.template.soy.
// Please don't edit this file by hand.

goog.provide('net.caprazzi.md5.ui.template');

goog.require('soy');
goog.require('soy.StringBuilder');

net.caprazzi.md5.ui.template.main = function(opt_data, opt_sb) {
  var output = opt_sb || new soy.StringBuilder();
  output.append('<div class="md5-ui">
	<textarea class="md5-input"></textarea><br/>
	<button class="md5-action">Hash It!</button><br/>
	<textarea class="md5-output"></textarea><br/></div>');
  if (!opt_sb) return output.toString();
};

UI: javascript

Now let’s write some code that hashes the contents of the first textarea when the button is clicked.
Name the file js/md5.ui.js.

goog.provide('net.caprazzi.md5.ui');

// NOTE the inclusion of our template
goog.require('net.caprazzi.md5.ui.template');

// NOTE the inclusion of jshash
// as defined in third_party_deps.js
goog.require('jshash.md5');

goog.require('goog.events');
goog.require('goog.dom');

net.caprazzi.md5.Ui = function(parent) {
	this.parent = parent;
}

net.caprazzi.md5.Ui.prototype.render = function() {
	var html = net.caprazzi.md5.ui.template.main();
	this.parent.innerHTML = html;
	this.input = goog.dom.$$('textarea', 'md5-input', this.parent)[0];
	this.button = goog.dom.$$('button', 'md5-action', this.parent)[0];
	this.output = goog.dom.$$('textarea', 'md5-output', this.parent)[0];

	var self = this;
	goog.events.listen(this.button,
			goog.events.EventType.CLICK,
			function() { self.onButton_()});
}

net.caprazzi.md5.Ui.prototype.onButton_ = function() {
	this.output.value = hex_md5(this.input.value);
}

Application entry point

This file exposes the function main(), that will be executed at page load. It only requires the two modules that uses directly

goog.provide('net.caprazzi.md5.application');

goog.require('net.caprazzi.md5.ui');
goog.require('goog.dom');

net.caprazzi.md5.application.main = function() {
	var container = document.getElementById('md5-ui-container');
	var ui = new net.caprazzi.md5.Ui(container);
	ui.render();
}

deps.js: the dependencies file

Calcdeps.py is a script that comes with closure library. It parses the source files in search of goog.require() and goog.provide() declarations. It then uses those declarations to build a dependency tree.

The dependency tree is stored in a file as a list of goog.addDependency calls. Each calls describes a file and the modules it provieds and requires. This line declares that md5.component.js will provide ‘net.caprazzi.md5′ and require ‘net.caprazzi.md5.template’ and others:


goog.addDependency('js/md5.component.js',
    ['net.caprazzi.md5'],
    ['net.caprazzi.md5.template', 'goog.events', 'goog.dom', 'jshash']);

Run this command in the root of the project to generate the deps.js all the dependecies (including google’s). This may take a while.

$ python closure-library/closure/bin/calcdeps.py \
    -p closure-library/closure \
    -p closure-library/third_party \
    -p closure-templates \
    -p js \
    -i js /md5.* \
    -o deps \
> deps.js

The option ‘-o deps’ tells calcdeps.py to output a dependency tree. The other options specify the source directories and files. Spend a moment to review the contents of the resulting file.

Managing the third party library ‘md5.js’

As I explained above, calcdeps uses special declarations in the javascript files to make sense of the dependencies. We know that by ‘jshash.md5′ i mean ‘jshash-2.2/md5.js’ but calcdeps could only figure this out if the file included a correct goog.require statement.

At this point we may just add the line to the file and go on with our lives. But we all agree that editing 3rd party libraries is not a good practice.

I maintain a text file ‘extradeps.txt’ where each line associates a module to a file, in this case the contents are

jshash.md5 jshash-2.2/md5-min.js

Then a simple python script parses that file and generates the missing addDependency() statements:

import sys
for mod, path in [  line.strip().split(' ') for line in file(sys.argv[1]) ]:
	print "goog.addDependency('%s',['%s'],[]);" % (path, mod)

Execute the script to see what the output looks like. Then remember to concatenate its output to deps.js each time your rebuild:

$ python fix_deps_file.py extradeps.txt >> deps.js

in dev: index_dev.html

The last piece of the puzzle is the one that holds everything together: the html

<html>
	<head>
		<title>Hash me, hash me</title>
		<script>
			CLOSURE_NO_DEPS=true;
			CLOSURE_BASE_PATH="./";
		</script>
		<script src="closure-library/closure/goog/base.js"></script>
		<script src="deps.js"></script>
		<script>
			goog.require('net.caprazzi.md5.application');
		</script>
	</head>
	<body onload="net.caprazzi.md5.application.main();">
		<h3>Hash me, hash me</h3>
		<div id="md5-ui-container"></div>
	</body>
</html>

Note the two global directives before the inclusion of base.js:

  • CLOSURE_NO_DEPS stops closure from loading its own deps.js
  • CLOSURE_BASE_PATH tells closure file loader how to build the script urls.

Note that the html file only imports closure’s base.js and deps.js then invokes directly code that comes from md5.ui.js

Navigate to index.html, the application should be working.

Use firebug or another network monitor, to see how the browser is downloading many different files to satisfy all the dependencies. This is the perfect behaviour for development, because separate files are easier to debug.

going live: the single js file and index_live.html

Loading many small javascript files is an evil practice in production.
We definitely want to have all our javascript files concatenated in one big blob.

I previously used calcdeps.py with the option ‘-o deps’ to build a dependency tree. Calcdeps can also concatenate all your dependancies right away, using the option ‘-o script’. Unfortunately if you try to run it against our code, it will terminate with an exception (

Exception: Missing provider for (jshash.md5)

. Clearly, again, the dependency script doesn’t know which files provides that module

Python to the rescue again: we’ll reuse the extradeps.txt file with a new python script that takes all the external deps and puts them in a file along with the correct goog.provide() statements.

import sys
mods = [  line.strip().split(' ') for line in file(sys.argv[1]) ];
for mod, path in mods:
	print "goog.provide('%s');" % (mod)
for mod, path in mods:
	for line in file(path):
		print line

Running this script produces a calcdeps-friendly javascript file:

$ mkdir tmp/
$ python concat_extra_deps.py extradeps.txt > tmp/extra.js

We can now tell calcdeps to look into tmp/ to find what’s needed to build our big target file:

$ python closure-library/closure/bin/calcdeps.py \
	-p closure-library \
	-p tmp \
	-p js \
	-p closure-templates \
 	-i js/md5.application.js \
    -o script \
> md5_application.js

Now we can produce the final artifact and go live with index_live.html:

<html>
	<head>
		<title>Hash me, hash me</title>
		<script src="md5_application.js"></script>
	</head>
	<body onload="net.caprazzi.md5.application.main();">
		<h3>Hash me, hash me</h3>
		<div id="md5-ui-container"></div>
	</body>
</html>

Conclusions

I’ve done this exercise to understand if the closure’s dependency management would be usable in a production environment.

There was some initial misunderstanding between calcdeps and me and I had to look at base.js to understand what was going on and to find out about the global directives that influence the loader.

The syntax is neat and serves the double purpose of managing namespaces and dependencies.

My impression is that at least the goog.require/provide syntax and the calcdeps.py script can be used in production with confidence.

Closure dosen’t allow to specify css files as dependencies, while it’s possible with YUI3 (that sports a cool dependency management mechanism of his own).

As an exercise you can think about adding a compilation step using google closure compiler.

-teo
Posted in javascript | Tagged , , , , , , | 1 Comment

Book: Programming Collective Intelligence

Programming books are seldom page turners, even for geeks like us. And programming books often fail to go beyond the technology. Programming books are rarely as good as this one. Allow me to digress for a moment.

Online there is a lot of data about you. And me. Our reactions have been logged, our desires noted. You know where I am now. I know your status. Ok, I’m being dramatic, but bear with me. I have a point.

All this data tells one story and million stories in their gritty details. And since past behaviour is a good predictor of future behaviour, I can read your vekernel_triclry future in those million stories.

Not so easy, of course. All those records are generated by humans and computers. It’s cybernetic data, its scale and complexity are beyond belief. We can only make sense of that data using computers.

Back to the topic. This very thick yet enjoyable book is a programmer’s journey in the world of machine learning and statistics.

The author, Toby Segaran, is brilliant. He will hold your hand while describing many algorithms an techniques. He’ll tell you just enough theory to make sense of what’s going on. And then, plain simple python, down with the implementation.

Interested in building and thinking about a recommendation engine? What about picking a good music generessolution to a proble, amongst millions? Curious about genetic programming? Wanna have your own spam filter?

The last great thing about this book are the example. Real world, not your usual fictional pet shop. You’ll fetch data from your delicious account, correlate live stock market data from yahoo, analyze your favorite blogs and more stuff.

Tony writing is unpretentious and the book is easy to read, but beware there is a lot of meat to digest. Don’t rush.

collective_intelligence

Posted in Uncategorized | Tagged , , , | Leave a comment

Learning Closure. Ajax with goog.net.*

Google released closure library, a javascript library good to make rich internet applications.

As this is going to be an important library in software developement, I decided to try it. ‘Ajax’ networking is a good starting point, so I looked into the package goog.net and found two promising classes, HxrIo and XhrManager, which I used for my tests.

The documentation is clear but sometimes shy about who does what. Fortunately there are plenty of links to the source code, which is well written and documented.

The interesting code is below, but there’s a more extend version of my closure-library tests.

Just hit a url without waiting for a response


// load the modules
goog.require('goog.net.XhrIo');
goog.require('goog.Uri');

// the easy way: static function call with no callback
goog.net.XhrIo.send('url/');

// using the send() method of an instance.
new goog.net.XhrIo().send('urlA'); // GET, default
new goog.net.XhrIo().send('urlB', 'POST');

// also works with an Uri object
var uri = new goog.Uri('urlC');
new goog.net.XhrIo().send(uri, 'PUT');

// no http method validation, this is a valid call
new goog.net.XhrIo().send('urlF', 'XXXX');

// send some data with the POST, works as expected
new goog.net.XhrIo().send('urlG', 'POST', 'p1=v1&p2=v2);

// ATTENTION data will not be attached to a GET
// so this call won't do what you may expect.
new goog.net.XhrIo().send('urlH', 'GET', 'p1=v1&p2=v2');

Request data from the server


// an html file as text
goog.net.XhrIo.send('sample.html', function(event) {
	var text = event.target.getResponseText());
});

// an xml file as document object
goog.net.XhrIo.send('sample.xml', function(event) {
	var document = event.target.getResponseXml());
});

// a json file as javascript object
goog.net.XhrIo.send('sample.json.js', function(event) {
	var data = event.target.getResponseJson());
});

// spot the 404
goog.net.XhrIo.send('gone_fishin', function(event) {
	var success = event.target.isSuccess()); // false
	var status = event.target.getStatus()); // 404
	var statusText = event.target.getStatusText()); // not found
});

// !!! exceptions in the callback are swallowed, so check your conditions
// (there is interesting error handling stuff in goog.debug.*)
goog.net.XhrIo.send('gone_fishin.js', function(event) {
	// I expected some data, but the file is not there
	// and this will raise an exception...
	var data = event.target.getResponseJson();
	var field_data = data.field;
	// ...so this statement will not execute...
	alert('bonk');
	// ...BUT you won't see anything in your console.
});

// a 404 using an XhrIO instance and closure event management;
var io = new goog.net.XhrIo();
goog.events.listen(io, goog.net.EventType.COMPLETE, function(event) {
	var status = event.target.getStatus()); // 404
});
io.send('gone_fishin');

Using the connection manager


goog.require('goog.net.XhrManager');

// goog.net.XhrManager(opt_maxRetries, opt_headers, opt_minCount, opt_maxCount, opt_timeoutInterval)
var mgr = new goog.net.XhrManager(2, null, 0, 2);
goog.events.listen(mgr, goog.net.EventType.COMPLETE, function(event) {
	// this is fired once for each send(), even if they are retried
	var xhr = event.xhrIo;
});
mgr.send('id_one','closure.js');
mgr.send('id_two','/urlTwo');
mgr.send('id_three','/urlThree');
mgr.send('id_four','/urlFour');

// reusing an id before the request is complete, causes an exception...
try { mgr.send('id_one','/x'); }
catch (e) { /*[goog.net.XhrManager] ID in use*/ }

// ...unless the connection is aborted
mgr.abort('id_one');
mgr.send('id_one','/x');

mgr.send('other_id','/someurl', null, null, null, function(event) {
	// it's ok to reuse an id an after the request completed
	mgr.send('other_id', '/fool');
});
Posted in Uncategorized | Tagged , , , , | 7 Comments

book: forms that work

Forms that Work: Designing Web Forms for Usability

There is no html in this book, it’s not about programming forms. And that’s why I liked it.

This short book clarifies what good form design is about, in plain english. Plenty of images help, too.
I’m still not too good at designing forms but at least now I know the name of the game.

-teo

forms_that_work

Posted in book review forms design | 1 Comment

book: don’t make me think

Don’t Make Me Think!: A Common Sense Approach to Web Usability

Delightful one-night read. Some good common sense advice on web design and two brilliant chapters on usability testing on a budget.

common sense is underrated

Posted in Uncategorized | Leave a comment

netflix prize contest, a new one


With netflix announcing a new contest, it’s time to look back at how the Netflix Prize ended: BellKor’s Pragmatic Chaos team (AT&T Research engineers) won over the ensemble (a creek of lower-ranked contestants), just minutes before the deadline.

Both teams blended together different algorithms to improve by 10% the hit rate of existing netflix suggestion engine.

This is a story of monkeys and challenges, interesting beyond bytes and keyboards. Wired has good coverage, but you can google for more.

I’m reading Programming Collective Intelligence, which so far is ranking high: it uses easy-to-read-and-write python to build suggestion engines using many different algorithms. For programmers.

story coverage:

related papers:

Posted in netflix prize suggestion algorithm collective intelligence | Leave a comment

Above the Clouds: The View from Berkeley

RAD Lab released Above the Clouds: The View from Berkeley (pdf) an high-level overview of the cloud. It’s great read for anyone interested in the subject, no need to be involved in software development.

It’s the best text on the subject that I’ve read so far: the authors start and stay above the cloud, avoid stepping on technical traps, yet they never become too theoretical.

The paper will tell you what the cloud is and what is not, how it fits in today’s IT ecology. It also describes the “economics of the cloud” with no-nonsense formulas and pragmatic statements, making sensible assumptions and predictions.

If anything, I think it underestimates the impact of private clouds for small and medium organizations in the future. Designing your data center as cloud buys you a greater potential for scalability and flexibility.

Add that even a tiny company benefits from exposing its data layer as a service with domain specific logic (that is, a SaaS with an API), and that couples perfectly with a cloud architecture.

This is straightforward only for new organizations; a massive paradgim switch in an existing company could well kill it…

Posted in berkeley, cloud, paper, saas | Leave a comment

Falickaway: a flickr viewer

Available now: flickaway (demo)

I love flickr.

I also love my pictures, and sometimes flickr feels too… generic? impersonal?
Anyway. I decided to spend some time coding this flickr viewer so to have a website with my style and the same pictures I have on flickr.

I thought someone else might find it useful. If you like it, just go there, run the wizard, copy the generated html in an html file. Deploy to a web server. done.
Yes, the wizard is javascript-only as well.

I almost forgot: that html page is less than 2k.
All the javascript and the styles will be fetched from my website (or google, or yahoo), so you’ll always get the newest and best version.

A brief on technology:
I’m using jQuery (from googleapis.com), google feed apis and flickr rest api (on the wizard, to discover your feeds). All files are gzipped then deployed on Amazon S3.

Matteo

Posted in Uncategorized | Leave a comment

[C Testing] MinUnit – less is more

- Can a whole framework be 3 lines long? -

The C project I’m working on is quite small in LOC and files. It won’t grow much as it’s deployed on a chip with 4k program space and 256 bytes of ram.


No matter how small, test all your code. Always. Period.
Problem is, where to start?

Approaching unit testing may go down two different paths.

Write few functions with ifs and printfs, call them from a main(), execute and see. It’s prone to code duplication and you’ll soon start reinventing the wheel. You are paving your way to a maintainability hell. Anyway, It might work for small projects and is very easy to get started with. 

Otherwise you can embrace a framework such as CppUnit o Check, learn it and start writing tests. You get more power and less duplication. You’ll benefit from standardization, automation and much more. It’s the best approach, except for the steep learning curve. Add that writing tests is not exciting nor easy, and you might end up being so frustrated that you’ll never get your test suite done. 

Introducing the solution: MinUnit, a unit testing framework in 3 lines of code (!!!!):

/* file: minunit.h */
#define mu_assert(message, test) do { if (!(test)) return message; } while (0)
#define mu_run_test(test) do { char *message = test(); tests_run++; \
) extern int tests_run;
if (message) return message; } while (
0

(This kind of magic is why I really do miss macros in Java)

At least it is the solution for my small-scale project.

Just copy those few lines in a header file, include it and start writing tests. It is really that easy. And gone is your excuse for not testing. 
Really, this might be all you need even for a mid-sized project. Especially if you are introducing unit testing in an existing project, the jump start can really pay off.

One important feature of (some) bigger frameworks is that the test runner executes your test code in a separate address space. This way if your buggy code picks the wrong pointer, it won’t bring down the test runner, but only that unit. The runner will report it as a failure and move on. Do that with MinUnit and probably you’ll have no clue of what hit you.

Make no excuses, test-your-code.

For the records, I modified it a little bit, adding a specialized assert:
#define mu_assert_eq(expected, actual) {\
int a = (expected); \
int b = (actual); \
do { if ((a) != (b)) { \
sprintf(minunit_msg, “FAILURE %s:%d expected %d, got %u”, __FILE__, __LINE__, a, b);\
return minunit_msg; }; \
} while(0); }


There is a complete example on the project page or have a look at a real world example: test_ring_buffer.h and test.c

Matteo
Posted in avr, cyz_rgb, unit testing | Leave a comment

CYZ_RGB alpha 2 – feature complete

The second release of CYZ_RGB, an alternative firmware for BlinkM, is now ready for download.

The latest release implements all the features of the original firmware.

The program has been slightly tested at a functional level (sitting there and watching the lights go on end off), but has no unit tests.

I usually write loads of tests, possibly before the actual code; this time I was wandering in a completely new area and I knew most of the code was going to be highly disposable. Now that all hurdles have been surpassed, the refactoring stage will go hand-to-hand with writing a thorough test suite. Wish me good luck.

Go read the details.

Goals for next release:

  • Write a comprehensive test suite
  • Decouple cyz_cmd from cyz_rgb
  • Decouple usiTwiSlave from cyz_cmd
  • Reduce binary footprint (now 4072b of 4096 available)
  • Add ability to write 2 scripts

-Matteo

Posted in Uncategorized | 1 Comment