Thursday, May 19, 2011

Memorable moments in code reading

Reading through other people's code can be tedious. But sometimes you come across a comment that makes it all worthwhile. Thanks to the httplib2 contributor who added this gem.

Monday, April 25, 2011

Creating HTML5 Cache manifests for GWT Apps

I've been working recently on making Springpad work offline using some of HTML5's new features and want to share a solution to a problem I ran into generating the cache manifest file. The cache manifest is a text file containing the version number of your manifest file and the paths of the files on your site that you wish to cache. For more specifics on how to set up an offline application with this file check out Mark Pilgrim's excellent Dive Into HTML5.

That's pretty simple. Generally, when you make a web application you know all of the resource names and locations and can add those to the manifest. Unfortunately, when you are using GWT, the situation is slightly more complicated. GWT compiles javascript files from your Java source code, one per browser platform you are targeting. It names these files by generating a checksum based on the contents of the file. Then it creates a simple javascript file that loads the correct javascript file based on the browser's useragent. So this means that everytime you make a change to your application and recompile, you will need to specify a different javascript file in your cache manifest.

You could do this by hand, but that's tedious and likely to be forgotten at some point. Alternatively, you could do some regex'ing of the bootstrapping file and figure out from that what javascript file to put into the manifest. This is better than doing it by hand, but seems hacky and painful since that javascript will be obfuscated in production.

The solution that we settled on was to implement a custom GWT linker to generate the manifest file. GWT allows you to create your own linkers to either override their linker or to supplement it. Here's the code for the linker which will find the compiled name for the javascript file that we want in our cache manifest and then output a cache manifest will that file in it. For right now, all we care about is the Safari user agent, so that's all that I'm handling. Other browsers also handle offline, so in that case you would want to modify this create a different manifest file for each user agent and then have your server serve the appropriate one based on the user agent in the GET request. I've added comments inline to explain how our version works. Hope this helps.




Tuesday, March 29, 2011

Test Driven Development

At this point, I guess Test Driven Development (TDD) is old news but while I've always liked the idea and have even made preachy statements about unit tests in the past, I've found it difficult in practice to actually write in a test driven way. I don't mean that I don't always test first, but that frequently when I'm in a rush, I test-never. This has come back to bite me enough that I've gradually started writing more tests when it was easy to do.

I recently came across this screencast of Gary Bernhardt using TDD to create a simple string calculator. Gary's velocity is super impressive, but more importantly the video shows how fast TDD can be, especially with a good key mappings to run tests and a split screen.

I watched this at a good time because at Springpad we've recently started a new project all in python. After reading some more about TDD, I've been trying to make a habit of this style of development. So far it's been great. I think the big advantages for me so far have been:

  • Better than a compiler: especially in a dynamic language these are key to make sure you don't have any spelling mistakes or stupid problems. But they're so much better too obviously. Why check that the method exists, when you could check that it behaves as expected before runtime.
  • Staying out of the debugger is fast: Since starting this, I've tried to write enough tests at the right level such that I don't need to debug the program ever. And I've been mostly successful which for me has really sped things up.
  • Deeper understanding of the codebase: Since you spend more time thinking about behavior not only of your code but also of libraries that you use so that you can test it right, you end up knowing the code a lot better. Seems obvious in retrospect, but I didn't start TDD for that reason.

  • I think there's still a lot to figure out with this. Should you use mocks versus stubs? Does a test belong in a separate integration suite versus the unit tests? Etc. So far I haven't created any strong opinions on this, but I'd love to hear anyone's thoughts on how it should be done.