`this` in Node modules and IIFEs


June 23, 2013by @prust; javascript, nodejs, iife, root, backbone, underscore, module

For the past 8 months I've been following the convention in Backbone and Underscore and wrapping my modules in an IIFE and setting a local variable root to whatever this is outside the IIFE:

(function() {
  var root = this;
  // body of the module here

}).call(this);

This provides convenient access to the global context in both environments... at least that's what the Backbone docs said and I believed them. So I was surprised when I set properties on root but didn't find them available globally in Node. However, being new to Node, I assumed that this was because Node enforced stricter isolation between modules and that global was really a sort of pseudo-global that was just global to the module. Months later I found that different Isomorphic Javascript frameworks (airBNB/rendr and developmentseed/bones) were setting a boolean on the global object to indicate whether the module is running server-side or client-side... and that the global was actually global.

I had been fooled all this time: the docs were wrong (and were corrected shortly after I read them). this inside a module (and, hence, the root variable) does not refer to the global object in Node; it refers to module.exports. this only refers to the global object when it is inside a IIFE (provided the value of this is not overriden via call() or apply()).

It makes a lot of sense to map both of these (exports and global) to the window object in the browser. The simplest way is to map exports via an argument passed to the IIFE and to map global via a local variable set to this:

(function(exports) {
  var global = this;

  // body of the module here

})(this);

These two variables can then be used for globals, imports and exports:

(function(exports) {
  var global = this;
  var _ = global._ || require('underscore'); // imports
  var is_server = global.is_server;

  function Class1() { /* ... */ }
  function Class2() { /* ... */ }

  // exports
  exports.Class1 = Class1;
  exports.Class2 = Class2;

})(this);

There is still one case where it is necessary to fall back on a typeof check for Node-specific code: when you want to export a single class as the entire module:

(function(exports) {
  var global = this;

  function Class1() { /* ... */ }

  // export Class1 as entire module
  if (typeof module != 'undefined')
    module.exports = Class1
  else
    global.Class1 = Class1;

})(this);

SQLite's HAVING clause picks an arbitrary row


May 22, 2013by @prust; sql, sqlite, postgresql

Most SQL engines don't allow non-aggregate expressions in the HAVING clause. For instance, the Postgres docs state:

Each column referenced in condition must unambiguously reference a grouping column

SQLite, on the other hand, takes a surprising approach:

If a HAVING clause is a non-aggregate expression, it is evaluated with respect to an arbitrarily selected row from the group.

Perhaps this approach has precedence in other SQL implementations, but I would much prefer a hard fail over an arbitrary result.

Unix Philosophy and Node.js


April 23, 2013by @prust; philosophy, node.js

At Cornerstone, we've promoted using and writing "small and sharp" tools for as long as I can remember (influenced by Andrew Hunt and David Thomas, among others). But I've never seen a community take this concept as far as the Node community has. It's been fun to see substack posting some arguments for this philosophy as well as some how-to notes -- and even more fun to see Isaac Schleuter, the gatekeeper / BDFL of node, write a piece on it: Unix Philosophy and Node.js

Annoying Javascript Caching


March 21, 2013by @prust; javascript, node.js

As our team has started to move from web-powered desktop apps to true web apps, we've been bit more than once by Chrome caching the javascript files.

Once Chrome has cached your files, the simplest way I've found to force Chrome to get the latest of a particular file is to find it in the Network panel, right-click to open it in a new tab and hit Ctrl+F5.

But it would be even better to tell Chrome to stop. And really, this isn't Chrome's fault. It's the server's fault, which is sending headers telling Chrome to cache the Javascript.

If you're using node's http-server, the default is a cache header of 1 hour (don't ask me why). To drop the cache header to 10 seconds, you could send -c10, or to disable caching entirely, send -c-1:

http-server -c-1

If you're using the node-static file server, you can turn off caching like this:

var fileServer = new static.Server('./public', {'cache': false});

How to remove a cursor in Sublime Text


February 27, 2013by @prust; sublime text

Sublime Text's multiple cursor feature (hold down ctrl while clicking to create more cursors) is great -- until you click in the wrong place. Fortunately, it is possible to remove a mis-placed cursor (though not altogether intuitive): hold down alt and use the middle mouse button (or clickable scroll wheel, if you don't have a middle mouse button) to remove the errant cursor.

String.substr() is not ECMAScript


February 26, 2013by @prust; javascript

I'm not sure why I never noticed before, but String.substr() isn't actually in the ECMAScript standard. The 3rd edition of the ECMAScript spec does mention it in the non-normative annex in order to "suggest uniforn semantics for such properties without making [them] part of this standard".

There are already two methods in the standard that do essentially the same thing, String.slice() and String.substring(). My preference is String.slice() because it supports negative indexes, doesn't have confusing argument-swapping behavior ("if indexA is larger than indexB, then the effect of substring is as if the two arguments were swapped") and its API is similar to .slice() for Arrays and string slicing in other languages.

Multi-line strings are not part of ECMAScript


February 26, 2013by @prust; javascript

I've always stayed away from multi-line strings, but didn't realize until today that they aren't part of the ECMAScript standard:

var str = 'this is a long string, \
           that is two lines long.';

It also never dawned on me what exactly the backslash is doing: it is escaping the newline in the source code!

As Google's styleguide says:

The whitespace at the beginning of each line can't be safely stripped at compile time; whitespace after the slash will result in tricky errors; and while most script engines support this, it is not part of ECMAScript.

Over the years, I've gravitated toward using simple string concatenation when I don't care about preserving newlines:

var str = 'this is a long string, ' +
          'that is two lines long.';

and array joining when I do want newlines:

var str = ['this is a long string, ',
           'that is two lines long.'].join('\n');

Neither is pretty, but we don't get true multi-line strings until ECMAScript 6:

var str = `this is a long string, 
           that is two lines long.`;

Readability != closeness-to-natural-language


January 24, 2013by @prust; node.js, philosophy

I used to equate readability with closeness-to-natural-language, but have found that this does not always ring true. Sometimes a DSL is more readable than it's natural language equivalent, due to a higher signal-to-noise ratio.

In my opinion, CSS and HTML fit into this category, along with glob and, in rare cases, regular expressions (whose idea was it to make a DSL where capitalization of things like \w is not only significant, but it negates the meaning?!).

For example, glob('*.sql', ...) is more readable than _.filter(files, function(file) { return _.str.endsWith(file, '.sql'); });. You can just look at glob('*.sql', ...) and you know what it means. This ability to glance at it and know its meaning instantly, without needing to read or parse a sentence makes it even more readable than the natural language equivalent, "filter to all the files that end with .sql".

Function.length


January 17, 2013by @prust; javascript, backbone.js

Little did I know, but the Function prototype has a length property. This is how Backbone knows whether your comparator function should be treated like a _.sortBy() function (that takes a single argument) or an Array.sort() function (that takes two arguments). Perhaps this is also how mocha knows whether your tests take a done parameter. And here I had assumed they were using Function.toString() and parsing out the parameters, as Prototype's Function.argumentNames() does.

One repercussion of this is that if you are passing a single-argument function as a comparator, you have to be careful to not .bind() or _.wrap() it, or Backbone will assume it is a two-argument function.

Backbone Tips


January 17, 2013by @prust; backbone.js

A team member asked me for some Backbone tips and, while I don't profess to be a Backbone guru yet, I have been around the block with Backbone a few times and thought it would be beneficial to share some things I've learned. Please, take what follows with a grain of salt and correct me where you think differently.

Keep the view self-contained & isolated to the view’s element

One recommendation off the top would be to let Backbone’s base view class create the view’s element for you – you can parameterize the tagName and className and add attributes to it in the constructor – and to constrain all DOM event-handlers and selector queries to within that element (via the jquery-wrapped reference, this.$el, and a declarative events dictionary). The new listenTo() and stoplistening() handlers (added in 0.9.9) are preferable over the .on()/.off() because they unbind the events automatically for you on remove().

Relationships / Associations

If you need to work with relationships between models (like you would with data from a relational database) and needing to ensure that there is never more than one model object that represents a DB record, I would recommend using Supermodel.js (or possibly backbone-associations).

Subcutaneous Testing

Writing tests of the view layer that need to find things in the DOM and trigger DOM events can take a lot of developer time and is also an order of magnitude slower than unit tests that don’t involve the DOM (whether it’s the real DOM in a browser or the jsdom simulation in node). So we’ve been toying with the idea of doing what Martin Fowler calls “Subcutaneous testing” – testing everything but the thin outer “skin” via an M-V-VM pattern (Model – View – ViewModel), where the ViewModel or “Presentation Model” contains all presentation logic (but no DOM code) and has a very thin layer of generic code on top of it that keeps it in sync with a DOM template (perhaps rivets or plates).

Use Backbone.Sync or write a pluggable sync adapter for all model CRUD

I wish I had followed this advice much earlier, instead I did what most people do and just hacked in the creation and saving of models by overriding save(), etc. It’s much better to do it the right way and implement a Backbone.Sync plugin. There already are plugins readily available for Postgres, Socket.io, localStorage, Mongo, etc. This leads to more interchangeable code and coding styles, lends itself to cleaner separation and getting familiar with the established backbone APIs and allows you to swap in different persistence engines if you want.

Getters/Setters

I recommend iterating over all the attributes names for your model and using __defineGetter__ to make getters for them – that way you can use dot notation, which I find a lot cleaner and more maintainable. But for setting, you typically want to use .set() and consolidate as much as possible by passing multiple attributes to set() at a time, rather than doing separate .set() calls for each one (it’s more performant that way and you have a lot fewer change events to manage).

Collection.fetch and Collection.comparator

Collection.fetch() takes an {update: true} option which is very handy, if you pass a property name string as the comparator, rather than a function, then Backbone Collections will automatically re-sort if necessary, should that property change on a model. If you do pass in a comparator function, beware of wrapping or binding the function you pass in because Backbone’s behavior differs based on the number of arguments the function takes and wrapping/binding the function obscures the number of arguments (see the comparator docs).

Read the Source & Step Through It

The one thing that will give you the best understanding of backbone is to read & step through the source. It might seem intimidating at first, but it’s actually comparatively quite short and well-written and designed for readability (unlike the source of jquery & other hefty libraries) – the annotated source is often a good starting point – and is the best path to mastery. If something doesn’t behave as you would expect, the best thing is usually to set a breakpoint and walk through it.

jQuery setters act as getters if you pass undefined, breaking jQuery chainability


January 11, 2013by @prust; jquery

This code works fine most of the time:

var link = $('<a>').text(this.model.get('name'));

.text(), when used as a setter, returns a reference to the link and you can continue chaining to your heart's content.

That is, until this.model.get(‘name’) is undefined. When that happens, jQuery thinks you're .text() as a getter instead of a setter and link is set to an empty string instead of a jQueryified element -- which breaks subsequent code.

throw is disallowed in a ternary


January 10, 2013by @prust; javascript

I hadn’t realized this before, but throw is a statement -- just like var -- and therefore cannot be used in a ternary or anywhere that requires an expression. So you can’t do this:

callback ? callback(err) : throw err;

You have to either fall back to an if/else or wrap the throw in an anonymous function.

git URLs in NPM compare package.json versions


January 08, 2013by @prust; npm, node.js

The npm package.json docs make it sound like you can use git URLs for dependent repos and reference them via a tag, branch-name or commit SHA. While this is technically true, the docs don’t mention that “npm install” will compare the local version of the repository and the remote one (at that tag/branch/commit) and if they are identical, it will assume that nothing needs to be done -- even if the tag/branch/commit URL previously used to pull that repo is different from the current tag/branch/commit.

For instance, if your main repo depends on “my-sub-repo#master” and you change it to “my-sub-repo#new-feature” and don’t change the version in package.json on the new-feature branch, “npm install” will do nothing. You have to change the version on that branch to something like “1.1.0-new-feature.1″ and then “npm install” will realize that it different from what was previously downloaded (“master”) and will update it.

replace() can take a function


January 04, 2013by @prust; javascript

I discovered today that String.replace() can take a function as the second argument. I checked the ECMAScript 5.1 reference and it looks like it matches the MDN docs (though it is much less readable, as any good spec should be ;-).

The arguments passed to the function begin with match (the matched substring), followed by one argument for each regex capture group, followed by offset (the offset of the matched substring), and finally string (the entire string).

So you can do something like this:

" test ".replace(/t(e)s(t)/, function(match, grp1, grp2, offset, str) {
return 't' + grp2 + 's' + grp1;
});

And it will swap the two capture groups, resulting in “ttse”. Of course, this example would be better written as " test ".replace(/t(e)s(t)/, "t$2s$1"); but I’m sure I’ll find a situation someday that calls for the added flexibility.