Monday, August 11, 2008

Hitting the limits on iPhone Safari

Hit a hard iPhone resource limit:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
<html xmlns="">
<meta http-equiv="content-type" content="text/html; charset=utf-8"/>
<meta name="viewport" 
    content="width=device-width; initial-scale=1.0; maximum-scale=1.0; user-scalable=no;" />
<meta name="apple-touch-fullscreen" content="YES" />
<title>iPhone image loading test</title>
<script type="text/javascript">
var n = parseInt('02123003022000310', 4),
    nTiles = 0;

function drawTile() {
    document.getElementById('img').src = 
        '' +
        n.toString(4) + '.jpeg?g=131';
    document.getElementById('count').innerHTML = nTiles+'';


window.onload = function () {
    window.setInterval(drawTile, 500);
    <img src="#" id="img" />
    <p>Total tiles: <span id="count">0</span></p>

After downloading about 210 images, the iPhone simply stops downloading new ones. This is probably due to hitting the hard 30MB same-page resource limit as as documented on A List Apart. Apple itself documents the limit at 2 megapixels. Who knew that they also didn't free such resources when no longer in use?

I don't see any easy way around this one, and the implications are huge: even if your app is scrupulous in conserving JavaScript and DOM memory resources, sooner or later the browser itself will fail you. This precludes especially any browser-based Ajax mapping application, and many long-running Ajax apps in general.

So much for Web 2.0 on the iPhone.

Tuesday, July 8, 2008

Where are the JavaScript unittesting frameworks?

Now that JavaScript has been patched together into a number of promising server-side frameworks (Synergy, Jaxer, and, coming soon(ish), Rhino on Rails), JavaScript is really taking off as a potentially full-stack enterprise solution.

One serious failing, however, seems to be the continued lack of decent developer support tools, the worst of which has got to be testing. Sure, there are a number of decent browser test automation frameworks out there:

Sure, these are all great platforms - for AUTOMATION. Let's be clear, however: Automation is in no way the same thing as unit testing. Automation requires a full environment, and seeks to replicate the end-user experience on the full product stack by means of emulated behaviors - mouse clicks, key presses, and so on. Usually, such tests launch a browser app, set up the environment, execute the test case steps (which can mean multiple page loads), and then close the browser app, for EVERY TEST CASE. Such tests are absolutely necessary for any non-trivial user-facing product.

At the same time, developers need more granularity than that. We need to test hundreds of individual methods and edge cases in our code that target specific functions. We need a framework that can be run at build-time, and can plow through hundreds of focused test cases in a matter of seconds. We need a browser, sans GUI.

For the purpose of headless, command-line browser code testing, it seems only the GPL Crosscheck framework offers the robustness of browser emulation required for any serious work. Built on Rhino with a Java layer of cleverly reverse-engineer browser behaviors, Crosscheck itself has numerous bugs and drawbacks in common browser features (no cookie emulation, poor DOM Level 0 support, nonexistent IFrames, incomplete CSS emulation), the greatest of which seems to be that development has stalled on the project.

It should be immediately apparent to any front-end developer maintaining a moderate-to-large codebase why command-line unit-testing is important. Also, I realize that, as a developer, I should be getting things done and building solutions. One could investigate building a command-line app for Windows (and perhaps a fork for Linux using Wine?) that would instantiate the actual browser binaries from the command line and run code without launching the browser chrome; it seems this should work at least for Internet Explorer (COM objects) and Firefox (XULRunner) and maybe Safari too. I would like to submit patches to Crosscheck, but I'm not sure if the core developers even have time to review patches, and I don't personally have the time to sink into development of a competing framework right now. My hope is that someone out there in the development community will take notice of this need and have the time and/or resources to tackle this problem, and maybe one day I'll be that person. In the meantime, we'll have to settle for running our test suites in a matter of hours and not minutes.

Tuesday, April 15, 2008


$ history | awk '{print $2}' | sort | uniq -c | sort -rn | head

 149 cd
 138 ls
  42 svn
  27 python
  23 vim
  18 exit
  16 locate
  11 ssh
  10 rm
   8 less

Saturday, March 29, 2008

New blog

For all 2.3 of you out there reading this, I'd like to announce a new blog on "metaphysics?" so I can keep a clean sterile separation between work and life. My postings on this blog will continue to be exactly as infrequent as they have been since I started. Thank you.

Saturday, February 9, 2008

Strategies for Success (and other myths)

The writings and thoughts of Karl Marx and Friedrich Engels and orthodox Communism in general date themselves squarely between the Industrial Revolution and Darwin's historic Origins. The revolutionary implementation of Communism was doomed to failure, of course, because by the time it gained critical mass it was already obsolete; groups of humans can't be organized as machines are organized. Top-down mandates of economic equality don't work, because the system will always be more complex than even the most tyrannical police state can enforce. People under duress may provide acceptable manual labor but don't contribute new ideas or new efficiencies to the process when their main concern is not personal investment in work but in following orders; thus micromanaged economies will always underperform freemarket systems.

The lesson of Communism that especially American right-wing capitalists don't want to learn is that micromanagement and monopoly are anathema to the principles of the free market. Applying the principles of Darwinian natural selection to the economic domain, we see that a healthy economic ecosystem is one in which no single player is too dominant (see: super predators), but rather neck-and-neck competition keeps everyone on their toes while allowing smaller players to emerge as competitive with more established ones. Conversely, an economy of monoculture tends toward stagnation. Companies that grow too large become entrenched in a single business model and risk the ire of large partners when proposing innovations in production methods (see: Microsoft and IE).

Government clearly has a role to play in keeping the market competitive by regulating and sometimes smashing large corporations into smaller pieces. But more importantly, ownership of past success is not a guarantor for future success. Top-down institutionalization of past success models is a sure sign that the business is failing to see the next step in its evolution. In this regard, corporate (read: Stalinist) ownership of information and ideas will always fail in the face of bottom-up Darwinian trial-and-error. This is especially true in industries touched by technology, and we're already seeing established media companies, record companies, and television networks collapse under their own weight.

Enter the Internet. To the extent that it remains free, equal, and open, it provides the most fertile soil yet for innovation and progress (of ideas, of creativity, of economic advancement, of democracy). The chaotic hordes of the MySpace/YouTube generation will surely hasten the extinction of the giant record companies and the television networks, as the wisdom of crowds will do a better job determining what the crowds like than any closed, proprietary group of mavens in a boardroom or a laboratory ever will.

The lesson for internet companies trying to attract millions? Release early and often. Keep your coupling loose. Submit to what your users are telling you - investing 10 months in a project you're sure will be a hit is a huge risk; you'd better be basing your decisions on reams of user feedback and research, because your perfect vision for the product will always fail you unless you're playing with rules that have been subjected to the Darwinian rigor of millions of little trial-and-error tests.

Saturday, February 2, 2008

Easy Date Formatter

This should do the trick for most uses:
 * takes a string in form 'd/m/Y'
 * d => day (2 digits, leading 0)
 * D => day (2 digits, no leading)
 * l => day (of week, text, 3 chars)
 * L => day (of week, text, full length)
 * m => month (2 digits, leading 0)
 * M => month (2 digits, no leading 0)
 * f => month (text, 3 chars)
 * F => month (text, full length)
 * y => year (2 digits)
 * Y => year (4 digits)
 * g => hour (12hr, leading 0)
 * G => hour (12hr, no leading)
 * i => minute
 * s => second
 * t => hour (12hr, formatted with am/pm)
 * @param {String} format String for the formatting of this Date object
 * @return {String}
Date.prototype.format = (function () {
    var days = ['Sun', 'Mon', 'Tue',
        'Wed', 'Thu', 'Fri', 'Sat'];
    var fulldays = ['Sunday', 'Monday', 'Tuesday',
        'Wednesday', 'Thursday', 'Friday', 'Saturday'];
    var months = ['Jan', 'Feb', 'Mar',
        'Apr', 'May', 'Jun',
        'Jul', 'Aug', 'Sep',
        'Oct', 'Nov', 'Dec'];
    var fullmonths = ['January', 'February', 'March',
        'April', 'May', 'June',
        'July', 'August', 'September',
        'October', 'November', 'December'];

    function twoDigits(n) {
        return (n<10? '0':'')+n;

    return function formatDate(format) {
        var d = this;

        var matches = this.matches || {
            'd': function () { return twoDigits(d.getDate()); },
                'D': function () { return d.getDate()+''; },
                'l': function () { return days[d.getDay()]; },
                'L': function () { return fulldays[d.getDay()]; },
                'm': function () { return twoDigits(d.getMonth()+1); },
                'M': function () { return d.getMonth()+1; },
                'f': function () { return months[d.getMonth()]; },
                'F': function () { return fullmonths[d.getMonth()]; },
                'y': function () { return (d.getFullYear()+'').slice(2, 4); },
                'Y': function () { return (d.getFullYear()+''); },
                'g': function () { return twoDigits(d.getHours()%12); },
                'G': function () { return d.getHours()%12+''; },
                'i': function () { return twoDigits(d.getMinutes()); },
                's': function () { return twoDigits(d.getSeconds()); },
                't': function () { return (d.getHours() > 11? 'am' : 'pm'); }
        this.matches = matches;

        return format.replace(/[dDlLmMfFyYgGist]/g, function (match) {
            return matches[match]();

Friday, January 25, 2008

Introducing CSSx

Sick of the lack of syntactic sugar for CSS? While many designers are fine with the simplicity of CSS, some developers managing large codebases (such as Zillow's still-terse 2500-line master.css) have been flailing for sanity. Enter CSSx, a syntax-enhancing compiler for CSS. It accepts all currently-valid CSS syntax, so you can use your current CSS chops unaltered, but adds variables and block nesting to the language.

/* sample.cssx */

$red = #f00 /* a comment here*/;
$block = {
    div {
        padding: 10px;
    color: $red;
    border-width: 1px;
    margin: 20px 10px 15px 0;

.warning {
    color: $red;

.content {
    .warning {
        width: 200px;

    cite { @rule($block); }

    p {
        span.tooltip {
            color: blue;
        font-size: 1.1em;

    .header {
        font-size: 0.8em;

    font-family: Verdana, Arial, sans-serif;

It's still very beta (I'd peg it at 0.1), but please download, give it a spin, and give me feedback on what works/doesn't work for you, or what you'd like to see added. Download CSSx from Google Code.