Prototype and adapt with the MEAN stack

Rapid web development with MongoDB, Express, AngularJS, and Node.js

Web development may seem like a bustling space where everything changes every 5 minutes, but, in reality, the fundamental high-level concepts of building a web application haven’t changed much since the introduction of Ajax. The libraries and concepts, like the MEAN stack, that people have built up around HTTP and browser-side JavaScript simply provide abstractions to help people build sophisticated browser-based tools more easily. However, the fundamental challenges of web development remain mostly unchanged, and the ultimate arbiter of the value of a web development framework is how easily it enables you to overcome these challenges. In this article, I’ll highlight what I believe to be the fundamental categories of web development problems, and how the MEAN stack, consisting of MongoDB, Express.js, AngularJS, and Node.js, helps you solve them.

Problem 1: Prototyping, or, how do I build the damn thing?

With the growing popularity of the lean startup model, the pressure to shorten product development cycles and churn out a prototype application quickly and cheaply has never been greater. And, as developers, we’re doing this better at an exponential rate. Projects that once required hundreds of millions of dollars of capital in the late ‘90s became projects that you could build in a month or two with a couple tens of thousands of capital at a startup accelerator around 2008. Now, these sorts of projects are being churned out at hackathons around the country in a matter of days. As great as this seems, we can do better.

fluent

Much of the time-consuming grunt work associated with building out a prototype comes from managing rules for displaying and saving data. Small details like “display the user’s name here” were solved pretty well by MVC frameworks and templating, at least until AJAX-y functionality became the norm and the declarative syntax of templating languages gave way to jQuery spaghetti code. On the other hand, details like “the user should be able to modify their profile data but not their login count” were doable but not in a particularly elegant way. With the MEAN stack, both of these tasks can be done with ease and elegance.

AngularJS’ two-way data binding brings declarative template syntax into the realm of client-side JavaScript, while retaining the dynamic interactivity that makes client-side JavaScript so necessary. For instance, if you were to start building out a single page app (or SPA for short), your JavaScript could look something like this:

$(document).ready(function() {
 $.get(‘/me', function(data) {
   $(‘#username').html(JSON.parse(data).username);
 });
});

This approach is simple enough, but it opens up a huge can of worms when you want to make improvements. What if you wanted to display the username in more than one place? What happens when you want to refresh the user data from the server? What about editing the username in place? You can do all this with some careful code design and disciplined refactoring, but remember that we’re out to make this as dead simple as possible. With AngularJS, this becomes a lot simpler. Data binding ties your UI to your JavaScript state, so your JavaScript effectively becomes a simple API exposed to your HTML, which becomes the one true definition of all your UI/UX decisions.

Going the other way, what about managing access to what data the user can modify? In the pre-MVC web development world, before object-relational mapping (ORM) software, this was a major pain in the ass. Adding a single data item to your schema became a significant adventure unless you really knew what you were doing. ORMs made this better, but with MongoDB, doing this is elegantly simple even without an ORM. For example, lets say we have a user schema that looks like this:

{
 _id : 24,
 internal : {
   referralCode : "1234”
 },
 profile : {
   username : "vkarpov”
 }
}

Obviously, modifying the referral code should be disallowed, but users should be able to modify their username. With the MEAN stack, making this work as expected is pretty simple. You use AngularJS to do a simple PUT request to your server with the client-side user object:

$http.put(‘/me', $scope.user).success(function(data) {
 /* notify user of success */
});

On the server side, you can tell MongoDB to only overwrite the profile sub-document without touching the internal sub-document.

db.collection(‘users').update({ _id : user._id }, { profile : user.profile });

This way, you at least know that the user can only modify their profile through the /me route. And, when you find yourself needing to do validation on the internals of the profile sub-document, there’s an excellent ORM-equivalent for MongoDB and Node.js called MongooseJS which can take care of that for you.

Problem 2: Adapting, or, how do I handle requests for “one more thing”?

Probably the most difficult lesson for me to learn on my path to becoming a software developer was that a project is never done. A stagnant codebase is a rotting codebase (and it stinks just as bad as rotting food does in real life). However, improving your codebase isn’t just about refactoring and simplifying, there are always new features to add. Users and product managers can start to sound like Uncle from the children’s television show Jackie Chan Adventures, with their constant requests for “one more thing.”

More often than not, these requests require some sort of concurrency and/or scheduling. For example, lets say you’ve hired someone to do some analytics on usage and they want an Excel-friendly dump of the user data daily. Or your business people have decided to set up a Mailchimp list and want people to be signed up for the mailing list when they register for the site unless they opt out. Or you want to start showing prices in foreign currencies. All of these requests have one thing in common: they’re a pain to handle in most web development frameworks, but Node.js makes them pathetically simple.

The fundamental difference between Node.js and languages like Ruby and Python is that Node.js code runs in an event loop, whereas Ruby and Python code usually runs sequentially. Conceptually, this makes performing tasks like “execute this code at 6pm every day” or “execute this code after you’ve finished sending the HTTP response to the user” intuitive and elegant in Node.js versus somewhat unnatural in Ruby or Python. The tasks listed above become a straightforward part of your server instead of packaged into separate processes to be run as part of a Linux cron job. Creating a CSV dump every day at 12pm without blocking up the server, sending a Mailchimp API request after you’ve handled the user’s registration, and sending an HTTP request for updated exchange rates every day at 6pm are all simple functions in Node.js, as opposed to separate processes.

Next time, I’ll be providing a high level overview of testing and scalability with the MEAN stack.

Image via O’Reilly Media

tags: , , , , ,