Code Review: Finance

2011-05-16 00:00:00 +0100 by Alex R. Young

Code Review is a new series on DailyJS where I take a look at an open source project to see how it's built. Along the way we'll learn patterns
and techniques by JavaScript masters. If you're looking for tips to
write better apps, or just want to see how they're structured in
established projects, then this is the tutorial series for you.

The purpose of these code reviews is not to nitpick; it is simply to
learn and hopefully educate. I intend to cover all aspects of JavaScript
-- the various server-side interpreters, browser-based code, jQuery plugins -- anything I find with something to teach us.

This week's code review is on
Finance by TJ Holowaychuk.


Finance is a little accounting web app. It seems like something useful
for logging things like business expenses (I always forget to do that!),
but it could be used for any kind of payment.


You'll need Node and npm to use Finance.

Check the code out with Git, then set up the packages with npm:

git clone https://github.com/visionmedia/finance.git
cd finance
npm install


Running node app.js should bring up an instance of Finance.
No database setup or authentication is necessary. Try filling in a few
payments to get a feel for the app.

App Structure

I was looking for a database library, but I found something interesting!
TJ has opted to use a built-in database library,
db.js, which writes JSON to a file. The default data is saved to
/tmp/finance.db which is worth changing if you actually
want to use the app.

Saving data just writes out JSON.stringify(this), and
loading it involves reading the file and iterating over each value:

 * Load data.
 * @param {Function} fn
 * @api public

Database.prototype.load = function(fn){
  var self = this
    , fn = fn || noop;

  fs.readFile(this.path, 'utf8', function(err, json){
    if (err) return fn(err);

    var data = JSON.parse(json)
      , keys = Object.keys(data)
      , len = keys.length;

    for (var i = 0; i < len; ++i) {
      self[keys[i]] = data[keys[i]];


  return this;

I like how he writes to this rather than an object inside

Of course, this app is built with Express. TJ
has structured his main app.js file in an interesting way
-- it loads the libraries, does the configuration, then loads controllers from separate files:

var month = app.resource('month', require('./controllers/month'));
var items = app.resource('items', require('./controllers/item'));

This works by using the
express-resource module. This patches Express, which is why the var Resource =
line looks slightly suspicious given
that Resource doesn't appear anywhere else.

I have a feeling we might see this practise become popular in Express
app development. Even though it's tempting to keep adding routes to
app.js, keeping a slim main file makes managing code easier
as a project grows over time (as I found with Nodepad).

Controller Methods

TJ uses res.end() in methods that don't need to return

exports.update = function(req, res, next){
  var month = req.params.month
    , id = req.params.item
    , data = req.body.item[id]
    , item = db.months[month].items[id];

  try {
    validate(data, 'entity');
    validate(data, 'date', 'date');
    validate(data, 'category');
    validate(data, 'amount', 'number');
    for (var key in data) item[key] = data[key];
    item.tags = parseTags(item.tags);
  } catch (err) {
    res.send({ error: err.message });

I know that res.send() sends a HTTP 204 No Content
response in Express, so presumably this ends the HTTP connection without
returning any headers.

The controllers are written using RESTful methods: index,
create, update, destroy. There's
also a validation method which throws exceptions when a validation
fails. The controller method catches this and sends an error back using
JSON: res.send({ error: err.message }).


The views are written with Jade, naturally, and
they're very straightforward. Most of the interface is generated by
client-side JavaScript, so the views are mostly placeholders. The items
for the index action are rendered by the server rather than
putting everything in the client. TJ uses the collection
option for partial to do this:

!= partial('item', { collection: items })
!= partial('item', { object: {}})

Client-Side JavaScript

The client-side code is a fairly typical jQuery brain dump. I noticed
that TJ aliased jQuery's function with var j = \$; because
he hates typing \$ (I think he bemoaned this on Twitter).


This is a small project that showcases some of TJ's new Express modules,
and isn't intended to be used as a multi-user web app. The cunning use
of JSON as the database is notable, purely because it makes installation
and backup a breeze. Rather than forcing users to install modules for a
database (and perhaps even the database itself), they can stick Finance
on their laptops and potentially even leave the JSON file in something
like Dropbox.

In fact, the entire project has a strangely self-contained yet efficient
feel about it, which appeals to me as a way to build nifty little open
source web apps.