Preston L. Bannister { random memes }

2009.12.30

Almost but not quite … server-side JavaScript

Filed under: Javascript, Software — Preston L. Bannister @ 8:05 pm

Bit over three years back I looked at server-side Javascript, and was not enthused with the available choices.

Three distinct usages I’d like to cover: optimal performance,Windows web server (IIS) interoperable, and webhosting.

In addition, there are three interesting aspects of optimal performance: throughput, scalability, and stability.

For serving static content, I really like the model of a single-threaded non-blocking web server, of which thttpd was an early example, and for which the C10K question clarified the need. A small/simple web server has a much better chance to being very reliable. With the single-threaded non-blocking model, massive scalability is possible.

For serving dynamic content, I really like the isolation and load distribution possible with the FastCGI model (or the like). Dynamic code tends to be complex. Javascript interpreters are complex. Complex code tends to fail more often. Complex code can use more compute throughput than possible on a single box. For intranet applications, a single front-end web server is often preferable, and load distribution via FastCGI offers more headroom. All of which tends to argue for the FastCGI model, with isolation from the front-end web service, and potential distribution of load across more than one machine.

For the widest possible usage, in additional to optimal deployments (when there is no restriction on the front-end web server), the engine on which the application runs should be deployable behind IIS (for Windows-only organizations), and at common web-hosting services (like Dreamhost). Microsoft’s recent support of FastCGI with IIS is a big help.

At that time (three years back), none of the solutions were really optimal – and in fact were pretty far from optimal. The Java-based RhinoJavascript interpreter was easiest to embed, but failed the webhosting case. The C++ based JavaScript interpreters were a pain to embed, and offered good (but not great) performance.

Fast forward to the present, and Google offers the V8 JavaScript Engine that offers great performance, and is easy to embed. (Google as the good guys, riding to the rescue once again … you’d think they have white hats superglued to their brains.) Suddenly we have lots of projects embedding the V8 engine. In addition, seems most all the single-threaded non-blocking web servers have picked up support for FastCGI.

Oh … and I am pretty much fed up with the Java Servlet model. After considerable time with the problem, I am of the opinion that the servlet model chose the wrong abstractions, and this makes for awkward solutions. (Of course, the servlet model appeared very early in the history of web applications, so the mistake is easy to understand.)

Which means the model offered by node.js makes a lot of sense. I like the notion of a naked node (running JavaScript on the V8 engine) performing request dispatch without any extra layers or abstractions. The main lack with node.js is the ability to work via FastCGI (and thus no means to be deployed behind IIS on Windows).

But there are as yet items unresolved and/or unclear.

  • Projects like v8cgi offer the V8 JavaScript Engine connected via FastCGI.
  • The node.js project offers a single-threaded non-blocking web server … but can it work behind FastCGI?
  • Is the environment for server-side JavaScript the same (or sufficiently similar) between node.js and v8cgi?
  • Comet is still a question. Can FastCGI work well with long-outstanding requests from applications?

The good news is that we seem a lot closer to attractive and well-supported server-side JavaScript for web applications … but it seems we are not quite fully there, as yet.

2009.02.03

Elegant distributed applications

Filed under: Javascript, Software, Web — Preston @ 8:24 pm

“Elegance is the attribute of being unusually effective and simple”

Heard this first applied to theories in Physics. Any not-over-complicated theory that effectively explained the facts was – as I understood – considered an “elegant” theory. (My original interest – and college degree – was in Physics. I wanted to build starships.)

Came up, long ago, with rules for “elegant” distributed applications. The first significant distributed application I spent time with was the early FileNet system. This was well over twenty years ago. Strong interest in scaling to large (by the standards of the time) deployments, forced careful thought about performance. Pretty much everything I have worked on before and since has had a network in the middle, so I’ve had time and reason to think about the subject. Changing technology does not change the inherent nature of distributed systems, so the relevant set of notions will pretty much always apply.

(What continues to surprise me is that individuals and outfits still get these same bits wrong!)

In the interest of hitting the usual points once….

When building distributed applications, there are some basic principles you should always keep in mind.

Minimize the amount of data crossing the network.
The capacity of the network is always limited. Capacity is large in the usual development setup, when both server and client are on the same segment. In real use the available capacity is almost always less, and sometimes much less.
Minimize the number of round-trips across the network.
Networks always have latency. This has nothing to do with the speed of a network (in terms of bits/second). I have written about this before. For an interactive application the ideal is one round-trip per user action.
Shift computation from the server to the clients, where practical
There are almost always more clients than servers. If you can shift computation to the clients, you will get better overall throughput.

From the above principles, for building web applications you can derive further guidelines.

Code complexity belongs on the server. Code in the client should be simple.
Code to be executed on the client must be shipped across the network. The less you have to ship across the network, the better. If you have an application that calls for code-complexity on the client, you want to ship the code once, and should be looking at solutions like Java WebStart. Otherwise you want to ship as little code as possible across the network. This fits perfectly with the use of compact scripts in the client using Javascript.

The fact that Javascript is interpreted on each and every load (and not compiled) serves only to reinforce this guideline.

Large iterations belong mainly on the server, not the client.
Compiled code is usually much more efficient than interpreted code. The server can (or should) use compiled code. In the case of web applications, the client code is interpreted code.
Large data belongs on the server, not the client.
The (sometimes) narrow network channel, and the relative efficiency of compiled code – both argue for keeping large data on the server.
Use the strengths of the web browser.
Native code is faster than interpreted code. The web browser is smart, and incorporates a large set of behaviors in native code. Use of built-in behaviors can mean smaller Javascript and faster execution.

In the present, Javascript offers an elegant solution to the need for a scripting language in both client and server. Made the mistake(?) of responding to a recent post. Seems that each time something like this comes up, we have an almost fixed set of notions coming back. After a few iterations – just not very interesting.

Some quotes, with names omitted to protect the guilty.

Arrays have no semantics. They are not first-class collections. Do not use them in any public API, regardless of the language you use. Wrap arrays with a public type that exposes semantics.

The semantics of arrays as collections and iterations are simple and perfectly suited for small scripts. For the most part, you do not need anything more. The domain for scripting is small, concise, and hideously flexible code. More elaborate solutions might make sense in large server-side code. Client-side script or structures shipped between client and server should only be as elaborate as is needed – and no more.

You’re right in the sense that JS is “good enough” for most of basic usages, but almost useless for writing bigger software. It’s the reason why there’s been recently a lot of higher level languages that generates JS code. Either Java (GWT) or haXe (http://haxe.org)

You should not be writing large code in Javascript. You must use Javascript in the client (the web browser), but in-browser script should not be large. You should consider Javascript as “glue” code on the server-side – small code, few iterations, with huge flexibility – to allow special-case customization without re-coding. Javascript (as with ELisp in Emacs and AutoLisp in AutoCAD) is a scripting language. You do not want to write the bulk of a large application in Javascript. Large code is a non-goal for a scripting language.

I still dislike JavaScript, and likely always will. It has some pretty fundamental flaws.

Javascript evolved almost as a hack (if not quite). Early versions were less capable. Early examples were uninspired (or worse). The present iteration preserves past mistakes. Ignore the mistakes, and use the good parts. The good parts are … very good, as suits a scripting language.

JavaScript has no place on the server.

Quite the opposite – as the scripting language known to the largest group, and fated to be well-known over a long period – Javascript can serve exceptionally in the role that scripting languages have long met in large, successful applications. Not for large use, but with a valued place. Often when faced with the need to adapt a large application to a specific customer/site needs, there are always cases when a simple list of options is not enough (and rarely-used options serve only to make the application obscure to all customers). There is always a part of the problem space best met by a scripting language deeply integrated with your application.

Historically we have always had a zoo of suitable scripting languages, with insufficient reason to choose between them. In an odd way, the rise of Javascript in the web browser does us a favor, as Javascript is sufficient, and now most widely known of all scripting languages. There are times when a single logical solution is best for all involved.

Javascript is good enough.

2008.09.15

Google’s Chrome: Bet your enterprise on it

Filed under: Javascript, Software, Web — Preston @ 1:10 am

Have to credit an article for a bit of insight – though at all not what the author intended.

There is an aspect I had previously missed. The Google Chrome web browser is an excellent platform for company intranet applications.

Lots of companies have internally-used applications. Lots of developer-hours went into those applications, and some of those applications end up being mission critical. The average level of programming talent that went into creating those applications is often less than first rate, and so they tend to be somewhat inefficient, and somewhat unreliable.

Google Chrome is probably the best platform for those not-entirely-performant and not-entirely-reliable internally developed applications. The fast Javascript engine means less efficient applications will run better on Chrome, and isolation of Javascript engines within means less-reliable applications will cause less trouble when run within Chrome.

Is this what the Google-folk expected? My guess is not.

Organizations with a long enough history will almost certainly have had to deal with vendor-forced upgrades that interacted badly with important in-house applications. The fact that Chrome is open source means that companies now have more of a choice – they could choose to opt-out of any changes that disrupt important internal applications.

Google may have accidentally created the ideal platform for large organizations that are looking at deploying internally developed web applications.

2008.06.11

property.import task for Ant

Filed under: General, Javascript — Preston @ 8:05 am

I have Ant build scripts that can be run on either Windows or Linux. There are a few properties that need to be set differently, depending on the platform is use. Been using this little snippet for a while now.

import.js

Array.prototype.map = function(f) {
    var a = [];
    for (var i=0; i<this.length; ++i) {
        a.push(f(this[i],i));
    }
    return a;
};
Array.as = function(v) {
    var a = [];
    for (var i=0; i<v.length; ++i) {
        a.push(v[i]);
    }
    return a;
}

var PROPERTY = (function(){
    var t = {};
    var _get = function(k) {
        return project.getProperty(k);
    };
    t.get = _get;
    t.verbose = function(n) {
        n = 1 * n;
        if (0 < n) {
            t.get = function(k) {
                var v = project.getProperty(k);
                self.log("get " + k + " = " + v);
                return v;
            };
        } else {
            t.get = _get;
        }
    };
    t.low = function(s) { var v = t.get(s); return v && v.toLowerCase(); };
    var os_name = t.low("os.name");
    var user_name = t.low("user.name");
    if (os_name.match(/^windows/)) {
        os_name = "win32";
    }
    t.byUser = function(s) {
        return t.get(s + "." + user_name);
    };
    t.byOS = function(s) {
        return t.get(s + "." + os_name);
    };
    t.byPlatform = function(s) {
        return t.get(s + "." + os_name + "." + user_name);
    };
    t.pick = function() {
        return Array.as(arguments).map(function(k){
            var v = t.get(k) || t.byPlatform(k) || t.byUser(k) || t.byOS(k);
            project.setProperty(k,v);
            self.log("set " + k + " = " + v);
            return v;
        });
    };
    return t;
})();

PROPERTY.verbose(attributes.get("verbose"));
PROPERTY.pick(attributes.get("name"));

Task definition from Ant build file:

    <scriptdef
        name        = "property.import"
        language    = "javascript"
        src         = "import.js"
        >
        <attribute name="name" />
        <attribute name="verbose" />
    </scriptdef>

Example contents of build.properties:

nsis.home.win32=c:/Program Files/NSIS
launch4j.home.win32=c:/tools/launch4j
launch4j.home.linux=${user.home}/tools/launch4j

Usage is simple:

    <property.import
        name        = "launch4j.home"
        verbose     = "0"
    />

The property.import task looks for variants of the named property suffixed with user.name, os.name or both. For the above import of launch4j.home the property.import task when run by user “preston” on Windows gets the value from the first of:

launch4j.home.win32.preston
launch4j.home.win32
launch4j.home.preston

This allows checkin of build.properties while picking up appropriate per-user and per-platform property values when run.

2007.06.14

Mapping components – Javascript

Filed under: Javascript, Software — Preston @ 1:48 pm

Accessing components in the DOM from Javascript using getElementById() is tedious, somewhat verbose, and does nothing to enhance the readability of the code. Generally there are two cases: finding global elements within the page, and finding members within (possibly repeated) components.

There are (of course) many ways to do this, but what I have settled on is using the ID attribute to identify global elements (what ID was meant for), and using the NAME attribute to identify members within a component. This use of the NAME attribute is exactly analogous to standard usage inside forms, just extended for use with non-form objects.

The code to build a map of global objects:

DOM.byId = function() {
    var map = {};
    DOM.asArray(arguments).apply(function(name){
        var v = name.split('.');
        var o = map;
        while (1 < v.length) {
            var s = v.shift();
            o = o[s] = o[s] || {};
        }
        o[v[0]] = document.getElementById(name);
    });
    return map;
};

The code to build a map of a component:

DOM.byName = function(root) {
    var map = {};
    var walk = function(o) {
        var name = o.getAttribute && o.getAttribute('name');
        if (name) {
            var v = name.split('.');
            var m = map;
            while (1 < v.length) {
                var s = v.shift();
                m = m[s] || (m[s] = {});
            }
            m[v[0]] = o;
        }
        for (o = o.firstChild; o; o = o.nextSibling) {
            walk(o);
        }
    };
    walk(root);
    return map;
};

Usage is quite simple:

var named = DOM.byId(
    'grid1',
    'textWidth',
    'textHeight'
);
var grid1 = DOM.byName(named.grid1);

Now named (by ID) global objects in the DOM can be later referred to in the Javascript code simply as named.grid1, named.textWidth, named.textHeight. Named objects within a component (by NAME) can be referred to as grid1.container, grid1.top.container, grid1.top.strip, (etc.).

Note that both DOM.byId() and DOM.byName() map IDs and NAMEs like “foo.bar” into a corresponding structure:

{ foo: { bar: reference to DOM element } }

Code in base.js.

Auto-adjusting sizer – Javascript

Filed under: Javascript, Software — Preston @ 1:22 pm

Took a couple years to get reasonably fluent at HTML/CSS/Javascript, and pick out what seems a decent programming model. Reached the point where most of the public examples of Javascript usage (in particular) look to me as very poorly written. Still it seems like every time I turn out another example, I find another useful idiom.

Take sizing of DOM elements. Say you want to put a sizable component within a page. The DOM model for this is a mess. You can set the width and height of an element o with o.style.width and o.style.height (assuming the element is sizable). You can read the width and height of an element with o.offsetWidth and o.offsetHeight. Not exactly symmetric, and in fact – due to the DOM layout model – these are in fact often not quite the same numbers. Yuck.

Looking at a bunch of repetitive code (button handlers to alter a component’s width/height), realized there was an common idiom that could be extracted into a “sizer” object.

grid.sizer = function() {
    var o = { dx: grid1.container.offsetWidth, dy: grid1.container.offsetHeight };
    o.apply = function() {
        grid1.container.style.width  = o.dx + "px";
        grid1.container.style.height = o.dy + "px";
        o.dx = grid1.container.offsetWidth;
        o.dy = grid1.container.offsetHeight;
    }
    return o;
};

(The component has been mapped by functions DOM.byId() and DOM.byName() described here.)

Now either width, height, or both can be set or adjusted using the “sizer”.

sizer.dx = 500;
sizer.apply();
sizer.dx += 100;
sizer.dy = 400;
sizer.apply();

Kind’a like a remote control for a component. But still not quite right, as (depending on the CSS) the actual component size may be a little different than what was set via the style. The difference is not readily deducible from the DOM, and I did not want to kludge in anything browser or style specific. The difference between the actual size and the size wanted can be computed … then it occurred to me that the “sizer” could be made auto-adjusting.

grid.sizer = function() {
    var ddx = 0, ddy = 0;
    var o = { dx: grid1.container.offsetWidth, dy: grid1.container.offsetHeight };
    o.apply = function() {
        grid1.container.style.width  = (ddx + (0 | o.dx)) + "px";
        grid1.container.style.height = (ddy + (0 | o.dy)) + "px";
        var now = { dx: grid1.container.offsetWidth, dy: grid1.container.offsetHeight };
        ddx += o.dx - now.dx;
        ddy += o.dy - now.dy;
        o.dx = now.dx;
        o.dy = now.dy;
    }
    o.adjust = function() {
        var want = grid.sizer();
        o.apply();
        o.dx = want.dx;
        o.dy = want.dy;
        o.apply();
    }
    return o;
};
var sizer = grid.sizer();
sizer.adjust();
grid.layout();

The essential bit here is that the “sizer” remembers the difference between the size as set, and the actual size in ddx and ddy. A single upfront call to sizer.adjust() initializes ddx and ddy. Note that on later changes to the component size, if the actual size differs from what was wanted (due to CSS changes, browsers bugs, whatever), then ddx and ddy are adjusted to match.

Simple, clean, and browser-independent.

2007.06.10

Storing data within a web page – Javascript

Filed under: Javascript, Software — Preston @ 11:22 pm

An approach or two to storing data within a web page. Something like “microformats”, only not. First approach, embed JSON data within an updatable SCRIPT tag, with a test page. Works in Firefox, but in IE when updating the tag containing the data, the script is executed (which is arguably right – if inconvenient in this case). Something like:

<script id="properties" type="text/javascript">
PAGE.add({"age":123,"revision":345,"editor":"John Doe"});
</script>

Second approach, embed JSON data within a hidden, updatable tag, with a test page. Works in both Firefox and IE (no surprise).  Something like:

<div id="properties" style="display: none;">[{"age":123,"revision":345,"editor":"John Doe"}]</div>

Requires an extra bit of encoding, but nothing difficult. The result is arguably cleaner.

var readProperties = function() {
    PAGE.data = JSON.parseJSON(DOM.decode(named.properties.innerHTML)) || [];
};
var injectProperties = function() {
    named.properties.innerHTML = DOM.encode(JSON.toJSON(PAGE.data));
};

This is leading up to something else altogether.

Bouncing JSON requests – Javascript

Filed under: Javascript, Software — Preston @ 1:46 am

Simple measure of round-trip times for bouncing a JSON request off a server.  The server-side script (bounce.php) is:

<?php
$a = array(
    'date'  => date('Y.m.d H:i:s'),
    'uname' => php_uname()
);
echo json_encode($a);
?>

The code to generate a JSON request (in bounce.html) is in effect:

var o = JSON.makeGET("bounce.php");
o.onResponse = function(v) {
    // use v
};
o.sendGET();

Where v is the JSON response (click bounce.php to see a response).

Next Page