blog

Developing with Node.js and MongoDB: Part I

May 25, 2012

For the past 3-4 months I’ve been part of a developer team here at e-conomic that’s working full-time on a Node.js and MongoDB solution. We’re primarily developing a REST API that’s used by a web client and a mobile app. Later on, we will make the API publicly available to our partners.

In the following, I’ll provide some insights into what we have done plus provide a lot of tips based on our experiences.

Great fun

Generally speaking, I simply love developing on this platform. The dynamic nature of JavaScript, MongoDB’s documents, the fact that there’s no schema for data in MongoDB, and MongoDB’s API – these things all make the platform great to work with. You have to be prepared to fiddle with things a little since some of the modules for Node.js are a bit rough around the edges. The upside is that I have a detailed insight into how our application works. And you actually have a lot of open source Node.js modules to choose from.

One of the things that make Node.js development so wonderful is that there is no gigantic framework you need to spend time getting to know. I’m sure that the minimalist approach and the fact that we developers are so close to the actual machinery are the main reasons why we now have a solution with maintenance-easy and highly transparent code. It’s a great feeling to be genuinely proud of the code we’ve produced.

Works on Windows, Mac and Linux

Most of us developers at e-conomic use Webstorm for Windows which contains embedded Node.js debugging, but one guy also uses Mint from time to time, another uses Ubuntu with Sublime text 2, and we used to have a Mac user as well. Node.js and MongoDB run smoothly on all platforms, and it literally only takes 10 minutes to download and install. And so far, we haven’t had to change a single configuration setting for either Node.js or MongoDB. It just works!

Our staging and production environments are running Linux. We have only experienced a couple of issues between the platforms, so for the time being we’ll continue our strategy of making our application compatible with Windows, Mac and Linux. This way, developers can use their preferred OS as they please.

Our multi-OS strategy means that there are a few Node.js modules that we can’t use because they only work with Linux. But so far, we’ve been able to find replacements for these modules, or we’ve simply done without them. Our biggest problem has actually been that file and folder names are case insensitive in Windows – contrary to Linux.

These are the services, tools and Node.js modules that we use

Git and GitHub.com for version control. Part of the code review is handled by writing comments inline in commits at GitHub.com.

Webstorm and Sublime Text 2 as IDE.

Test: Mocha as the test framework, with chai for assertions, JSCoverage for code coverage reports, Restler for calling our API during integration testing and Injectr for dependency injection.

Heroku.com and MongoHQ.com for renting test servers in the cloud. Node.js and MongoDB are preinstalled as services.

JMeter for load tests.

TeamCity as CI server (soon to come), with busy pull from GitHub. If your CI server is reachable from the Internet, GitHub can also push to it on commits.

Dropbox for my code, which works fine with Git. I can simply stop working at home and then continue in the office from where I left off. The Dropbox file versioning system has bailed me out on several occasions when I’ve made mistakes while getting familiar with Git.

Node.js as a webserver for REST API

You can find many different opinions on code style, frameworks etc. for Node.js. We have been fortunate to have many experienced JavaScript developers on our team. If you’re new to JavaScript, you have to be prepared to learn a lot of new things. Having said that, server-side JavaScript is very different from client-side JavaScript, meaning that you can’t reuse all your best practices from client-side JavaScript.

It almost never makes sense to have the same code on the client and the server. But occasionally, JavaScript can reside in one place and then be moved.

Node.js comes with a whole new event-based concurrency model. Things are made easier because pieces of code never run at the same time. On the other hand, your code is split up into a lot of small pieces (callbacks), and all kinds of things may happen between running the pieces. Sometimes you really have to watch your step – but try not to resort to a library such as async as soon as you run into problems. Often, you can get by with just restructuring your code a bit. And keep in mind that code that uses async can be very hard for others to read. I think we only use async in a single place in our production code, and I actually have an idea for rewriting and simplifying this code without async.

Avoid throwing errors and using try-catch – instead use the Node.js convention in which you call your callback with the error as the first parameter. The callback is always called with null as the first parameter if there is no error.

Use function hoisting instead of nested callbacks. Give your callback function a name that describes the step it performs in your callback chain. This is an effective way of avoiding callback hell.

Try never to do anything CPU heavy in Node.js. If you want to run a CPU heavy job, you should start the job asynchronously on an application server. For PDF generation, for instance, we use a couple of application servers.

Our logs at loggly.com have been invaluable in case of bugs and contain a useful search functionality.

When we run load tests, a single JMeter client can’t overload Node.js and MongoDB. You need several clients to really make them buckle.