We've built the control plane to Rackspace Cloud Monitoring in Node.js, and overall the experience has been positive.
A few things to look out for:
1. Error handling. In node you can't just wrap your code in a try/catch. And even if you register a listener for uncaught exceptions, you almost certainly have state shared between requests (for example, a database connection pool), which makes trying to handle such exceptions risky. To use node effectively, you need to be very careful to prevent exceptions from being thrown in unexpected locations.
2. Code rot. It is a lot less obvious what is idiomatic in Javascript as compared to Python, etc. Its easy to end up with a wide range of styles and patterns, which make maintenance difficult.
3. Missed or double callbacks. These are interesting mostly because they are not something you would see in synchronous code, and they can be quite difficult to troubleshoot (especially double callbacks).
Mitigating these issues is as much a cultural challenge as it is technical. Lint everything, review code aggressively, and don't merge code that doesn't have tests. Choose libraries carefully (the ecosystem has come a _long_ way in the last few years).
All of that being said, these are things you should be doing anyway. Develop a good tech culture, but get your product out and grow your user base. If you become the next Twitter you'll have the resources to undo any mistakes you make now.
We are using Node at https://starthq.com and I agree with most of the points above.
Error handling is the major issue, because you need to handle all errors manually, i.e. you can't use try catch to trap all errors further down the stack. If you don't handle all errors your Node process will terminate and you may lose some state. Even if you're confident in the stability of your code, I strongly advise that you use a watchdog process like supervisor to start a new process if the current one terminates.
We've handled this issue and kept business logic code simple by using https://github.com/olegp/common-node which uses fibers to present synchronous APIs, allowing us to use exceptions for error handling.
Be very careful when choosing third party packages, since if they don't handle all errors, again your process will terminate and there's nothing you're able to do about it, even if you're using fibers.
One last issue is changes to the core APIs. Since some of them are still in flux, it is advisable to provide an abstraction layer above them so as to be able to weather any changes. For example when streams2 came out, we only needed to upgrade Common Node, with no changes to the application itself.
It's been great at http://geekli.st and we run a full node stack. It is true error handling is an issue sometimes, but that's over shadowed by the quality of engineers looking to hack in node. Most common reason I hear for someone leaving a company... "I wanted the opportunity to hack in node at work" - not once, twice but dozens of times. In an age where finding top notch teams to build your stack is really hard, what code base you use is really important to attracting top talent.
Thanks! In fact, I knew that Rackspace uses Node and thus am incredibly happy that I got an answer from you folks.
Any particular architecture you guys followed in building your app?
I'm doing as many things right as possible, but I would rather take as much advice as I can get than being sorry later. Node, like Python, isn't really forgiving.
A few things to look out for:
1. Error handling. In node you can't just wrap your code in a try/catch. And even if you register a listener for uncaught exceptions, you almost certainly have state shared between requests (for example, a database connection pool), which makes trying to handle such exceptions risky. To use node effectively, you need to be very careful to prevent exceptions from being thrown in unexpected locations.
2. Code rot. It is a lot less obvious what is idiomatic in Javascript as compared to Python, etc. Its easy to end up with a wide range of styles and patterns, which make maintenance difficult.
3. Missed or double callbacks. These are interesting mostly because they are not something you would see in synchronous code, and they can be quite difficult to troubleshoot (especially double callbacks).
Mitigating these issues is as much a cultural challenge as it is technical. Lint everything, review code aggressively, and don't merge code that doesn't have tests. Choose libraries carefully (the ecosystem has come a _long_ way in the last few years).
All of that being said, these are things you should be doing anyway. Develop a good tech culture, but get your product out and grow your user base. If you become the next Twitter you'll have the resources to undo any mistakes you make now.