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.
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.
- Central Node.js modules: MongoDB native driver, Express, Gzippo, JSV for JSON schema validation and Grunt for builds.
- Loggly.com for logging in the cloud.
- 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
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.
Read part II of this post to learn more about web frameworks, MongoDB, hosting and more.