Beginner Node.js – Part 4: Architecture Tips

We’ve reached the second half of this beginner Node.js series. YayHopefully at this point, you’re becoming more comfortable with Node, NPM, and pulling in packages. This post starts to get into the meat and potatoes of writing apps using nothing but JavaScript. I’m not going to tell you how you should write apps, but give you some tips and common troubles of architecting an app.

I want to start discussing creating a project and some tips on architecture to make development easier and headaches to a minimum. As I mentioned in the previous post,  npm init is what starts a  package.json for you. That’s the backbone of your project in the sense. It manages dependencies, any extra development dependencies, and metadata about your project that could be used by various other services.

Initial Thoughts

If you ran the  npm init command in a directory, you’ll end with nothing but the  package.json file.

Now what?

Poking around Google brings up numerous opinions on how a Node app should be structured. When it comes down to it, it’s up to you how you want the app to be organized. There’s no rule set determined by the Node engineers for you to follow.

That’s the inherent beauty and the curse of Node. Modularity allows you to define sections of your app how you want them. Some developers love that freedom, others are scared of it.

What I can recommend at the top is always keep in mind what Node is good at, asynchronous I/O, event driven execution, and being non-blocking. Don’t try to insert other language paradigms into Node as it might go against how Node operates and then you get a structure that doesn’t scale.

#1: Don’t Write Big Apps

Since Node is stuck running in a single process (asynchronous != multi-threaded), try to break pieces of your app into separate, smaller modules that can run on their own. Not only will that allow those pieces to run independently on their own threads, but testing, iterating, and defense against fault tolerance is done without disrupting other sections of the application.

Communication between those mini apps can be done either over the network, which Node is great at implementing, or can be done using a message bus via Redis, MongoDB, or some other intermediate data store.

When scaling starts to become an issue, this also allows you to load balance specific pieces that are causing the bottle neck. This becomes much more efficient from a resource point of view when you only need to scale what needs to be scaled.

I’ll show examples of this in my next post, but if you want to learn more, this talk given at November this year discusses the benefits and shows an example of how to implement this.

#2: Leverage Dependency Injection

This can be applied to any language but it’s worth mentioning.

When building custom components, make sure they can are isolated and can be tested on a stand-alone basis. Make sure each file does one thing and any dependencies that it needs are passed in from the calling module.

Just a quick example:

The database is passed into the User model so that it can be mocked when doing tests.

Again, not revolutionary, but it will help in the end.

#3: Leverage Module Default File

When requiring a module in Node, if the last part of the path is a directory, Node will automatically look for a file named  index.js and will use that as the required file. For example, let’s say you have the following app:

It’s a small trick but something that’s not obvious when you are starting to develop with Node.

#4: Avoid Nesting Directories Too Deep

Since requiring modules goes by the path to the file, if the directories become several layers deep, you can run into problems with require paths becoming confusing like this:

That not only is bad for maintenance, but it’s also ugly, and we don’t like ugly things in our code.

There are numerous ways to get around this which is a bit much for me to go into here, but there’s a good gist on GitHub that explains those workarounds well.

Let’s Make a Web App!

Hopefully at this point, you are starting to become comfortable with writing code in Node. Being that it is just JavaScript, development is easy, but the nuances of Node development are still being fleshed out.

In the last post of the series, I will show you how to take all that we’ve learned so far and build a web app. I’ll be using Express.js and start by creating a simple, straightforward website. From there, I’ll go into a bit more advanced concepts of creating isolated services to give the application a decoupled architecture.