One of the downsides of our previous application framework was that it became a huge, monolithic creature. We couldn’t change an individual thing, without carefully considering the ramifications in every place. Any manual regressions became a nightmare. It was a bad place to be.
As a result we decided to decouple our features into smaller feature apps. Each section of our site lives in its own repository and runs its own node.js process, listening on an exclusive port.
Now, we can deploy our Match Profile page, with no impact on our Dashboard page and be confident that changes will be confined to one part of the site. We do, however, have some shared bits of code used by multiple features, but that brings us to another wonder of Node.
NPM, short for “Node Packaged Modules”, is AWESOME. It acts like ‘yum’ or ‘apt-get’ in that it downloads packages from a central repository, considers each package’s dependencies, and makes the package available for your Node application to use. We include a shared library of common code in each of our feature apps by adding the git repository to our package.json.
Lastly, the one interesting thing about Node that most other web applications don’t have to deal with. As prudent developers, we try to catch expected errors, but sometimes things end up in a state we didn’t expect. In Node, when there is an uncaught exception, the process exits. We use an npm module called “Forever” to combat this. Forever is installed using “npm -g install forever” (the g is for global). We initiate the Forever script for each of our features, to keep them running. As this is the real world, we need a way to do this without too much manual typing. Our solution is to run Forever as a daemon that can be stopped and started.
With any Node.js application, you can decide exactly how sophisticated you want to make your request processing. Not every use case needs to handle cookies, for instance, so it is added when necessary, instead of making assumptions about what you’ll need.
We decided to use the Express framework, because we find it a useful way to define routes, as well as to handle lots of boilerplate code, like cookie handling or parsing GET and POST parameters. It also doesn’t make assumptions about how a developer might want to render views, so it’s extensible.
To that end, we chose Handlebars as a templating language, mostly because we were already using it on the client-side. We also decided to use Backbone.js for our models. It’s not strictly necessary, but using the same approach for accessing our Models in both the server-side code and the client-side code eliminates the need for developers to mentally switch between contexts as they work on both the server-side and client-side code.