Search icon CANCEL
Subscription
0
Cart icon
Your Cart (0 item)
Close icon
You have no products in your basket yet
Arrow left icon
Explore Products
Best Sellers
New Releases
Books
Videos
Audiobooks
Learning Hub
Conferences
Free Learning
Arrow right icon

Why Meteor Rocks!

Save for later
  • 23 min read
  • 08 Jul 2015

article-image

In this article by Isaac Strack, the author of the book, Getting Started with Meteor.js JavaScript Framework - Second Edition, has discussed some really amazing features of Meteor that has contributed a lot to the success of Meteor.

Meteor is a disruptive (in a good way!) technology. It enables a new type of web application that is faster, easier to build, and takes advantage of modern techniques, such as Full Stack Reactivity, Latency Compensation, and Data On The Wire.

(For more resources related to this topic, see here.)

This article explains how web applications have changed over time, why that matters, and how Meteor specifically enables modern web apps through the above-mentioned techniques.

By the end of this article, you will have learned:

  • What a modern web application is
  • What Data On The Wire means and how it's different
  • How Latency Compensation can improve your app experience
  • Templates and Reactivity—programming the reactive way!

Modern web applications

Our world is changing. With continual advancements in displays, computing, and storage capacities, things that weren't even possible a few years ago are now not only possible but are critical to the success of a good application. The Web in particular has undergone significant change.

The origin of the web app (client/server)

From the beginning, web servers and clients have mimicked the dumb terminal approach to computing where a server with significantly more processing power than a client will perform operations on data (writing records to a database, math calculations, text searches, and so on), transform the data and render it (turn a database record into HTML and so on), and then serve the result to the client, where it is displayed for the user.

In other words, the server does all the work, and the client acts as more of a display, or a dumb terminal. This design pattern for this is called…wait for it…the client/server design pattern. The diagrammatic representation of the client-server architecture is shown in the following diagram:

why-meteor-rocks-img-0

This design pattern, borrowed from the dumb terminals and mainframes of the 60s and 70s, was the beginning of the Web as we know it and has continued to be the design pattern that we think of when we think of the Internet.

The rise of the machines (MVC)

Before the Web (and ever since), desktops were able to run a program such as a spreadsheet or a word processor without needing to talk to a server. This type of application could do everything it needed to, right there on the big and beefy desktop machine.

During the early 90s, desktop computers got even more beefy. At the same time, the Web was coming alive, and people started having the idea that a hybrid between the beefy desktop application (a fat app) and the connected client/server application (a thin app) would produce the best of both worlds. This kind of hybrid app—quite the opposite of a dumb terminal—was called a smart app.

Many business-oriented smart apps were created, but the easiest examples can be found in computer games. Massively Multiplayer Online games (MMOs), first-person shooters, and real-time strategies are smart apps where information (the data model) is passed between machines through a server. The client in this case does a lot more than just display the information. It performs most of the processing (or acts as a controller) and transforms the data into something to be displayed (the view).

This design pattern is simple but very effective. It's called the Model View Controller (MVC) pattern.

why-meteor-rocks-img-1

The model is essentially the data for an application. In the context of a smart app, the model is provided by a server. The client makes requests to the server for data and stores that data as the model. Once the client has a model, it performs actions/logic on that data and then prepares it to be displayed on the screen. This part of the application (talking to the server, modifying the data model, and preparing data for display) is called the controller.

The controller sends commands to the view, which displays the information. The view also reports back to the controller when something happens on the screen (a button click, for example). The controller receives the feedback, performs the logic, and updates the model. Lather, rinse, repeat!

Since web browsers were built to be "dumb clients", the idea of using a browser as a smart app back then was out of question. Instead, smart apps were built on frameworks such as Microsoft .NET, Java, or Macromedia (now Adobe) Flash. As long as you had the framework installed, you could visit a web page to download/run a smart app.

Sometimes, you could run the app inside the browser, and sometimes, you would download it first, but either way, you were running a new type of web app where the client application could talk to the server and share the processing workload.

The browser grows up

Beginning in the early 2000s, a new twist on the MVC pattern started to emerge. Developers started to realize that, for connected/enterprise "smart apps", there was actually a nested MVC pattern.

The server code (controller) was performing business logic against the database (model) through the use of business objects and then sending processed/rendered data to the client application (a "view").

The client was receiving this data from the server and treating it as its own personal "model". The client would then act as a proper controller, perform logic, and send the information to the view to be displayed on the screen.

So, the "view" for the server MVC was the "model" for the client MVC.

why-meteor-rocks-img-2

As browser technologies (HTML and JavaScript) matured, it became possible to create smart apps that used the Nested MVC design pattern directly inside an HTML web page. This pattern makes it possible to run a full-sized application using only JavaScript. There is no longer any need to download multiple frameworks or separate apps. You can now get the same functionality from visiting a URL as you could previously by buying a packaged product.

A giant Meteor appears!

Meteor takes modern web apps to the next level. It enhances and builds upon the nested MVC design pattern by implementing three key features:

  • Data On The Wire through the Distributed Data Protocol (DDP)
  • Latency Compensation with Mini Databases
  • Full Stack Reactivity with Blaze and Tracker

Let's walk through these concepts to see why they're valuable, and then, we'll apply them to our Lending Library application.

Data On The Wire

The concept of Data On The Wire is very simple and in tune with the nested MVC pattern; instead of having a server process everything, render content, and then send HTML across the wire, why not just send the data across the wire and let the client decide what to do with it?

This concept is implemented in Meteor using the Distributed Data Protocol, or DDP. DDP has a JSON-based syntax and sends messages similar to the REST protocol. Additions, deletions, and changes are all sent across the wire and handled by the receiving service/client/device. Since DDP uses WebSockets rather than HTTP, the data can be pushed whenever changes occur.

But the true beauty of DDP lies in the generic nature of the communication. It doesn't matter what kind of system sends or receives data over DDP—it can be a server, a web service, or a client app—they all use the same protocol to communicate. This means that none of the systems know (or care) whether the other systems are clients or servers. With the exception of the browser, any system can be a server, and without exception, any server can act as a client. All the traffic looks the same and can be treated in a similar manner.

In other words, the traditional concept of having a single server for a single client goes away. You can hook multiple servers together, each serving a discreet purpose, or you can have a client connect to multiple servers, interacting with each one differently. Think about what you can do with a system like that:

why-meteor-rocks-img-3

Imagine multiple systems all coming together to create, for example, a health monitoring system. Some systems are built with C++, some with Arduino, some with…well, we don't really care. They all speak DDP. They send and receive data on the wire and decide individually what to do with that data. Suddenly, very difficult and complex problems become much easier to solve. DDP has been implemented in pretty much every major programming language, allowing you true freedom to architect an enterprise application.

Latency Compensation

Meteor employs a very clever technique called Mini Databases. A mini database is a "lite" version of a normal database that lives in the memory on the client side. Instead of the client sending requests to a server, it can make changes directly to the mini database on the client. This mini database then automatically syncs with the server (using DDP of course), which has the actual database.

Out of the box, Meteor uses MongoDB and Minimongo:

why-meteor-rocks-img-4

When the client notices a change, it first executes that change against the client-side Minimongo instance. The client then goes on its merry way and lets the Minimongo handlers communicate with the server over DDP. If the server accepts the change, it then sends out a "changed" message to all connected clients, including the one that made the change. If the server rejects the change, or if a newer change has come in from a different client, the Minimongo instance on the client is corrected, and any affected UI elements are updated as a result.

All of this doesn't seem very groundbreaking, but here's the thing—it's all asynchronous, and it's done using DDP. This means that the client doesn't have to wait until it gets a response back from the server. It can immediately update the UI based on what is in the Minimongo instance. What if the change was illegal or other changes have come in from the server? This is not a problem as the client is updated as soon as it gets word from the server.

Now, what if you have a slow internet connection or your connection goes down temporarily? In a normal client/server environment, you couldn't make any changes, or the screen would take a while to refresh while the client waits for permission from the server. However, Meteor compensates for this. Since the changes are immediately sent to Minimongo, the UI gets updated immediately. So, if your connection is down, it won't cause a problem:

why-meteor-rocks-img-5

All the changes you make are reflected in your UI, based on the data in Minimongo. When your connection comes back, all the queued changes are sent to the server, and the server will send authorized changes to the client.

Basically, Meteor lets the client take things on faith. If there's a problem, the data coming in from the server will fix it, but for the most part, the changes you make will be ratified and broadcast by the server immediately.

Coding this type of behavior in Meteor is crazy easy (although you can make it more complex and therefore more controlled if you like):

lists = new Mongo.Collection("lists");

This one line declares that there is a lists data model. Both the client and server will have a version of it, but they treat their versions differently. The client will subscribe to changes announced by the server and update its model accordingly. The server will publish changes, listen to change requests from the client, and update its model (its master copy) based on these change requests.

Wow, one line of code that does all that! Of course, there is more to it, but that's beyond the scope of this article, so we'll move on.

To better understand Meteor data synchronization, see the Publish and subscribe section of the meteor documentation at http://docs.meteor.com/#/full/meteor_publish.

Full Stack Reactivity

Reactivity is integral to every part of Meteor. On the client side, Meteor has the Blaze library, which uses HTML templates and JavaScript helpers to detect changes and render the data in your UI. Whenever there is a change, the helpers re-run themselves and add, delete, and change UI elements, as appropriate, based on the structure found in the templates. These functions that re-run themselves are called reactive computations.

On both the client and the server, Meteor also offers reactive computations without having to use a UI. Called the Tracker library, these helpers also detect any data changes and rerun themselves accordingly. Because both the client and the server are JavaScript-based, you can use the Tracker library anywhere. This is defined as isomorphic or full stack reactivity because you're using the same language (and in some cases the same code!) on both the client and the server.

Re-running functions on data changes has a really amazing benefit for you, the programmer: you get to write code declaratively, and Meteor takes care of the reactive part automatically. Just tell Meteor how you want the data displayed, and Meteor will manage any and all data changes. This declarative style is usually accomplished through the use of templates.

Templates work their magic through the use of view data bindings. Without getting too deep, a view data binding is a shared piece of data that will be displayed differently if the data changes.

Let's look at a very simple data binding—one for which you don't technically need Meteor—to illustrate the point. Let's perform the following set of steps to understand the concept in detail:

  1. In LendLib.html, you will see an HTML-based template expression:
    <div id="categories-container">
         {{> categories}}  
    </div>

  2. This expression is a placeholder for an HTML template that is found just below it:
    <template name="categories">
       <h2 class="title">my stuff</h2>..

  3. So, {{> categories}} is basically saying, "put whatever is in the template categories right here." And the HTML template with the matching name is providing that.

    If you want to see how data changes will affect the display, change the h2 tag to an h4 tag and save the change:

    <template name="categories">
       <h4 class="title">my stuff</h4>

    Unlock access to the largest independent learning library in Tech for FREE!
    Get unlimited access to 7500+ expert-authored eBooks and video courses covering every tech area you can think of.
    Renews at $19.99/month. Cancel anytime

  4. You'll see the effect in your browser. (my stuff will become itsy bitsy.) That's view data binding at work. Change the h4 tag back to an h2 tag and save the change, unless you like the change. No judgment here...okay, maybe a little bit of judgment. It's ugly, and tiny, and hard to read. Seriously, you should change it back before someone sees it and makes fun of you!

Alright, now that we know what a view data binding is, let's see how Meteor uses it.

Inside the categories template in LendLib.html, you'll find even more templates:

<template name="categories">
<h4 class="title">my stuff</h4>
<div id="categories" class="btn-group">
   {{#each lists}}
     <div class="category btn btn-primary">
       {{Category}}
     </div>
   {{/each}}
</div>
</template>

Meteor uses a template language called Spacebars to provide instructions inside templates. These instructions are called expressions, and they let us do things like add HTML for every record in a collection, insert the values of properties, and control layouts with conditional statements.

The first Spacebars expression is part of a pair and is a for-each statement. {{#each lists}} tells the interpreter to perform the action below it (in this case, it tells it to make a new div element) for each item in the lists collection. lists is the piece of data, and {{#each lists}} is the placeholder.

Now, inside the {{#each lists}} expression, there is one more Spacebars expression:

{{Category}}

Since the expression is found inside the #each expression, it is considered a property. That is to say that {{Category}} is the same as saying this.Category, where this is the current item in the for-each loop. So, the placeholder is saying, "add the value of the Category property for the current record."

Now, if we look in LendLib.js, we will see the reactive values (called reactive contexts) behind the templates:

lists : function () {
return lists.find(...

Here, Meteor is declaring a template helper named lists. The helper, lists, is found inside the template helpers belonging to categories. The lists helper happens to be a function that returns all the data in the lists collection, which we defined previously. Remember this line?

lists = new Mongo.Collection("lists");

This lists collection is returned by the above-mentioned helper. When there is a change to the lists collection, the helper gets updated and the template's placeholder is changed as well.

Let's see this in action. On your web page pointing to http://localhost:3000, open the browser console and enter the following line:

> lists.insert({Category:"Games"});

This will update the lists data collection. The template will see this change and update the HTML code/placeholder. Each of the placeholders will run one additional time for the new entry in lists, and you'll see the following screen:

why-meteor-rocks-img-6

When the lists collection was updated, the Template.categories.lists helper detected the change and reran itself (recomputed). This changed the contents of the code meant to be displayed in the {{> categories}} placeholder. Since the contents were changed, the affected part of the template was re-run.

Now, take a minute here and think about how little we had to do to get this reactive computation to run: we simply created a template, instructing Blaze how we want the lists data collection to be displayed, and we put in a placeholder. This is simple, declarative programming at its finest!

Let's create some templates

We'll now see a real-life example of reactive computations and work on our Lending Library at the same time. Adding categories through the console has been a fun exercise, but it's not a long-term solution. Let's make it so that we can do that on the page instead as follows:

  1. Open LendLib.html and add a new button just before the {{#each lists}} expression:
    <div id="categories" class="btn-group">
    <div class="category btn btn-primary" id="btnNewCat">
       <span class="glyphicon glyphicon-plus"></span>
    </div>
    {{#each lists}}

  2. This will add a plus button on the page, as follows:

    why-meteor-rocks-img-7

  3. Now, we want to change the button into a text field when we click on it. So let's build that functionality by using the reactive pattern. We will make it based on the value of a variable in the template.
  4. Add the following {{#if…else}} conditionals around our new button:
    <div id="categories" class="btn-group">
    {{#if new_cat}}
    {{else}}
       <div class="category btn btn-primary" id="btnNewCat">
         <span class="glyphicon glyphicon-plus"></span>
       </div>
    {{/if}}
    {{#each lists}}

  5. The first line, {{#if new_cat}}, checks to see whether new_cat is true or false. If it's false, the {{else}} section is triggered, and it means that we haven't yet indicated that we want to add a new category, so we should be displaying the button with the plus sign. In this case, since we haven't defined it yet, new_cat will always be false, and so the display won't change. Now, let's add the HTML code to display when we want to add a new category:
    {{#if new_cat}}
    <div class="category form-group" id="newCat">
         <input type="text" id="add-category"
    class="form-control" value="" />
       </div>
    {{else}}
    ...
    {{/if}}

    There's the smallest bit of CSS we need to take care of as well. Open ~/Documents/Meteor/LendLib/LendLib.css and add the following declaration:

    #newCat {
    max-width: 250px;
    }

  6. Okay, so now we've added an input field, which will show up when new_cat is true. The input field won't show up unless it is set to true; so, for now, it's hidden. So, how do we make new_cat equal to true?
  7. Save your changes if you haven't already done so, and open LendLib.js. First, we'll declare a Session variable, just below our Meteor.isClient check function, at the top of the file:
    if (Meteor.isClient) {
    // We are declaring the 'adding_category' flag
    Session.set('adding_category', false);

  8. Now, we'll declare the new template helper new_cat, which will be a function returning the value of adding_category. We need to place the new helper in the Template.categories.helpers() method, just below the declaration for lists:
    Template.categories.helpers({
    lists: function () {
       ...
    },
    new_cat: function(){
       //returns true if adding_category has been assigned
       //a value of true
       return Session.equals('adding_category',true);
    }
    });

Note the comma (,) on the line above new_cat. It's important that you add that comma, or your code will not execute.

Save these changes, and you'll see that nothing has changed. Ta-da! In reality, this is exactly as it should be because we haven't done anything to change the value of adding_category yet. Let's do this now:

  1. First, we'll declare our click event handler, which will change the value in our Session variable. To do this, add the following highlighted code just below the Template.categories.helpers() block:
    Template.categories.helpers({
    ...
    });
    Template.categories.events({
    'click #btnNewCat': function (e, t) {
       Session.set('adding_category', true);
       Tracker.flush();
       focusText(t.find("#add-category"));
    }
    });

  2. Now, let's take a look at the following line of code:
    Template.categories.events({

    This line declares that events will be found in the category template.

  3. Now, let's take a look at the next line:
    'click #btnNewCat': function (e, t) {

    This tells us that we're looking for a click event on the HTML element with an id="btnNewCat" statement (which we already created in LendLib.html).

    Session.set('adding_category', true);
    Tracker.flush();
    focusText(t.find("#add-category"));

  4. Next, we set the Session variable, adding_category = true, flush the DOM (to clear up anything wonky), and then set the focus onto the input box with the id="add-category" expression.
  5. There is one last thing to do, and that is to quickly add the focusText(). helper function. To do this, just before the closing tag for the if (Meteor.isClient) function, add the following code:
    /////Generic Helper Functions/////
    //this function puts our cursor where it needs to be.
    function focusText(i) {
    i.focus();
    i.select();
    };
    } //<------closing bracket for if(Meteor.isClient){}

Now, when you save the changes and click on the plus button, you will see the input box:

why-meteor-rocks-img-8

Fancy! However, it's still not useful, and we want to pause for a second and reflect on what just happened; we created a conditional template in the HTML page that will either show an input box or a plus button, depending on the value of a variable.

This variable is a reactive variable, called a reactive context. This means that if we change the value of the variable (like we do with the click event handler), then the view automatically updates because the new_cat helpers function (a reactive computation) will rerun. Congratulations, you've just used Meteor's reactive programming model!

To really bring this home, let's add a change to the lists collection (which is also a reactive context, remember?) and figure out a way to hide the input field when we're done.

First, we need to add a listener for the keyup event. Or, to put it another way, we want to listen when the user types something in the box and hits Enter. When this happens, we want to add a category based on what the user typed. To do this, let's first declare the event handler. Just after the click handler for #btnNewCat, let's add another event handler:

'click #btnNewCat': function (e, t) {
   ...
},
'keyup #add-category': function (e,t){
   if (e.which === 13)
   {
     var catVal = String(e.target.value || "");
     if (catVal)
     {
       lists.insert({Category:catVal});
       Session.set('adding_category', false);
     }
   }
}

We add a "," character at the end of the first click handler, and then add the keyup event handler. Now, let's check each of the lines in the preceding code:

This line checks to see whether we hit the Enter/Return key.

if (e.which === 13)

This line of code checks to see whether the input field has any value in it:

var catVal = String(e.target.value || "");
if (catVal)

If it does, we want to add an entry to the lists collection:

lists.insert({Category:catVal});

Then, we want to hide the input box, which we can do by simply modifying the value of adding_category:

Session.set('adding_category', false);

There is one more thing to add and then we'll be done. When we click away from the input box, we want to hide it and bring back the plus button. We already know how to do this reactively, so let's add a quick function that changes the value of adding_category. To do this, add one more comma after the keyup event handler and insert the following event handler:

'keyup #add-category': function (e,t){
...
},
'focusout #add-category': function(e,t){
   Session.set('adding_category',false);
}

Save your changes, and let's see this in action! In your web browser on http://localhost:3000, click on the plus sign, add the word Clothes, and hit Enter.

Your screen should now resemble the following screenshot:

why-meteor-rocks-img-9

Feel free to add more categories if you like. Also, experiment by clicking on the plus button, typing something in, and then clicking away from the input field.

Summary

In this article, you learned about the history of web applications and saw how we've moved from a traditional client/server model to a nested MVC design pattern. You learned what smart apps are, and you also saw how Meteor has taken smart apps to the next level with Data On The Wire, Latency Compensation, and Full Stack Reactivity. You saw how Meteor uses templates and helpers to automatically update content, using reactive variables and reactive computations. Lastly, you added more functionality to the Lending Library. You made a button and an input field to add categories, and you did it all using reactive programming rather than directly editing the HTML code.

Resources for Article:


Further resources on this subject: