Pretty image
JavaScript MVC frameworks are here to stay. Here Stephen introduces Knockout, one of the best.

You can’t make soup with just water. Then why do you only use jQuery to build a web application? The answer is you don’t. This article addresses why you need much more than just jQuery in your toolbox to be successful on the web today—what you need is a JavaScript MVC framework.

The War Is Over

A JavaScript MVC framework is a framework that provides data models, views, collections, events, bindings, and dependency tracking. Additionally, some frameworks provide explicit or implicit hooks back into server-side data models via convention-based REST interfaces. The interesting thing is, the war is already over. I know, I know, maybe you didn’t realize there was a war, or maybe it was more of a takeover, but however you cut it—JavaScript MVC frameworks are here to stay. That is a good thing.

How did this war wage on and how did MVC win? Against what or whom?

Well, I may be committing a logical fallacy, but JavaScript MVC frameworks won out over nothing. That’s right—the alternative was nothing. That is, roll your own JavaScript framework or don’t make highly interactive data-driven applications. Take your pick, but either way; it wasn’t going to be a pretty ending. Because unless you had the scale of a corporation building something like Gmail or just a awesome group of co-located skilled engineers who will make sure each JavaScript team agreement is followed to the letter of the law, then you were out of luck.

Which is all fine and good, but, why not just jQuery? jQuery is for DOM manipulation, simplifying Ajax and generally make cross-browser support work. You can use it with a JavaScript MVC framework—don’t worry. jQuery is still the standard DOM abstraction layer.

The last part of how JavaScript MVC frameworks won, besides that they were fighting against the alternative of “do nothing” is the same way that TDD (test driven development, but you know that…) won. It works. It’s dependable. It makes sense. You ship faster. You ship better products. The jury came back on this one—it’s over. Onward we go.

No Lack of Options

There are many options available in this space—too many for your humble author to enumerate. Frameworks like Backbone.js have really caught wind with the community, Ember.js has a very full-featured stack and Knockout is straightforward and based more on MVVM than MVC. Google, of course, has an entry with Angular and that will surely take over the world at some point in time—but not quite yet.

I’m just going to discuss Knockout and use it exclusively in my code samples. Why? Besides my personal experiences with the framework, KO is expressive and straightforward as far as binding syntax, UI refreshes, dependency tracking, and templating.

One last word on jQuery versus JavaScript MVC frameworks, from Knockout’s documentation: “KO doesn’t compete with jQuery or similar low-level DOM APIs. KO provides a complementary, high-level way to link a data model to a UI. KO itself doesn’t depend on jQuery, but you can certainly use jQuery at the same time, and indeed that’s often useful if you want things like animated transitions.”

The key points to a JavaScript MVC framework, as enveloped by Knockout, are: object models, horizontal scaling, shared skill sets, clean code, focus on services, and thinner layers. We’ll discuss each of these.

Object Models

Haven’t we spent enough time in this industry to at least know having an object model is better than a loose association of variables spread across a number of files that somehow, in someone’s mind, resembles a ball of mud? I mean—that’s a lesson that we’ve learned as well, right?

Luckily for us, using Knockout (again, or any first-tier JavaScript MVC framework) we can take advantage of our core domain object model in the browser. Later we’ll see how they can sync up back to the server. For instance, here you can see that we’ve defined a view model for a portfolio (as in investments):

 var portfolioViewModel = {
  name : "401k",
  id : 99,
  owner : “454-abc-565”
 };

This model is similar, if not identical, to what we have on the server-side—that’s important because the data is only persisted after it passes through the domain logic and validation back at the server. However, the server can be the page or a service end point. More on that later as well, but as a spoiler alert, it’s no different than any other contemporary Ajax design.

We named our model object portfoioViewModel. It has three properties, and in this instance each one is initialized. This is all vanilla JavaScript—no magic.

By the way, Knockout is not pure MVC. Don’t worry. It’s MVVM: Model, View, View-Model, where the View-Model is like a special controller that also has all the logic needed to work with the view, convert data back and forth, and protect the other two tiers from each other. It’s an idiom that takes just a little getting used to, but it’s quite powerful for UI development.

Object Models—Dynamically

Knockout allows you to dynamically generate your client models. Why would you want to do this? Simple—maintain the model code once, and use everywhere.

Pretend you have this class server-side.

 public class Portfolio{
 public string name;
 public double marketValue;
 public string ownerId;
 }

It’s inefficient to recreate the class entirely, by hand in JavaScript, on the client, because we wish to work with the same data structures. Why not just serialize the whole structure down? Lots of developers wonder this once they start with a framework, and luckily, most frameworks have considered this and provided solutions.

In Knockout, it’s the ko.mapping plugin.

With this, you can write some code like:

 var myData = getPortfolioWithAjax(); //get an instance of that
  //server-side Portfolio class

Now you will have myData as a Portfolio object, client side in a JavaScript object. This actually turns into another reason to keep your domain model simple, to enable this type of serialization.

Next, you can load that data up into a view model object using ko.mapping.

 var viewModel = ko.mapping.fromJS(myData);

At this point, all the public fields in Portfolio (since the private normally wouldn’t be serialized down) are accessible via viewModel, e.g. viewModel.name(). The mapping plugin also handled making the object a KO object, meaning that all of these fields of the object are observables. More on observables later.

Horizontal Scaling

Frameworks like Knockout certainly do not enable horizontal scaling themselves. It just makes it easier and more cost effective. When you have the ability to push more work into the client, driving richer user experiences, faster pages or any of the other benefits of a solid UI, you will do that. When the risk versus reward of doing so is too high, you will avoid richer interfaces. The JavaScript MVC framework is an enabler for you, the developer, to make the trade-off.

Rylander2.jpg

Horizontal Scaling via Browsers

In this figure you see that when we are capable of doing more in the browser, we do so. That means more processing, that is the right processing, can be done in the browser. For instance, reordering and filtering a set of data doesn’t require a server session, a post-back, and a retrieval of JSON, XML or (goodness) HTML. If the data set is present, do the work in the browser. And just as jQuery enables us to write quick and simple DOM manipulations, a framework like Knockout has our data in the model and it’s just a matter of resorting. In fact, the UI can respond to the resorted dataset via observables, which we will cover later.

Once more work is done in the browser, the server-side architecture can begin to change as well. Maybe the solution doesn’t require beefy web boxes anymore to deal with constant dynamic data queries, page renders or POSTs. Instead, a thinner Ajax services layer can be rolled out as in the following figure. Here, we can scale our Services tier as our user base increases. The Services tier can deal with the caching of data from other sources, hiding it from the browsers and the web app. It delivers some specialization, which means that different parts of the system can grow organically and respond without a server whose main purpose is serving HTML getting involved.

Rylander3.jpg

Horizontal Scaling via Services Layer for Ajax

Shared Skill Sets

One of the not so obvious reasons to get on board a JavaScript MVC framework is the promotion of full stack development—what used to be termed “shared skills.” In the classic web site/application model there are “server-side,” also sometimes called “backend developers,” who do server-ish work; connect to databases, transform data, etc.

Then there are front-end developers (FED’s) who are concerned about the UI and UX via CSS, HTML and JavaScript. The FED makes the application come to life and has traditionally had to pick up whatever loose pieces the server-side developers left them. Sometimes, this could be as ambiguous as server-generated ID tags in HTML elements, or fragments of JSON. Lots of these practices came from Microsoft, though they also brought forward the MVVM model, so they continue to breakeven with lots of developers.

Rylander4.jpg

Classic Web Development Model

In this figure you can see how both these sets of skills are required in creating an application, but are disconnected. The disconnection promotes inefficiency all around, as the two often work against each other, and leads to hand-offs during development.

The alternative is illustrated in the next figure. In this world we are leveraging the domain models from the server-side in the front end. This means that the FED’s on the team are working with the domain, and not some mimic of the domain objects. It also means that both server-side and FED’s can work together on what the view-model’s responsibilities should be. Finally, since the JavaScript is now separated from the UI, the code is in a better place to be unit tested and run through automation.

At the end, developers will become full stack developers—able to work from the back to the customer at the browser at the front.

Rylander5.jpg

Bridging Skills

Clean Code, REST and Layers

These three topics are tied together in a lot of discussion and literature, so I won’t be the one to break them apart. REST is, for whatever reasons, seen as clean. Maybe because it promotes layers, or because everyone has an affinity for the HTTP spec and its simplicity. Here is how they break down.

Clean Code—because frameworks like Knockout inherently promote modularization, separation from UI, and models, you can generate code that is worlds more readable than can a developer slinging JavaScript alone.

REST—many of frameworks, including Backbone, promote idioms following RESTfull practices to get and put data objects. Knockout doesn’t promote any particular way, but it also doesn’t stop you from following a basic RESTfull approach to talk to the server and manipulate domain-model objects.

Layers—by providing the capability to write Clean Code, following REST patterns, layers will emerge—and when done right, this is considered a good thing. Better the layer you know than the layer you don’t know.

A Word on Templates

The concept of a server-side template can’t help but be contentious. Why? Because it’s rendering a view on the wrong tier of the application. The browser is responsible for the view. But in the traditional web site sense all it receives is an HTML document. That would be fine if the web were still just about traversing resource links to new documents all day, but it’s not.

For example, if your server-side template is rendering a view, let’s say it’s working on the table that is in the middle of a page, and it needs to use another value that was rendered somewhere else in the page to do a row calculation. Ignoring that there are other solutions to avoid such a mess, what is the answer? Trick question: no matter the answer, it’s all server-side so devoid of browser context and requiring a page refresh. Plus, is a server-side page template rendering being done in the View or the Controller? It’s not the view, as the view is certainly not on the server. But, it can’t be the controller, as the controller doesn’t work directly on the view. This model just doesn’t work for every use case the way it used to.

In the last part of this article we’ll dive into some of the core concepts of the framework and explain what makes these important to building powerful apps and growing a team of full-stack developers.

Bindings

Pretend you want to take an object, like a transaction from a Portfolio (e.g. buy 55 shares AAPL at 454.341) that is loaded up into your client side view-model and display each row in a table. It’s all client side at this point, and there is no need to write any more JavaScript. Just use declarative bindings such as:

 <td><span data-bind='text: ticker'></span></td>
 <td><span data-bind='text: name'></span></td>
 <td><input type="text" data-bind='value: shares' /><td>
 <td><input type="text" data-bind='value: price' /><td>

The data-bind syntax is the glue here—and it does exactly what it says, replaces the value for a given HTML element with the value associated with that field on the JavaScript view-model object. This is triggered after calling ko.applyBindings(myModel). It can also iterate over a collection of objects like:

 <tbody data-bind="foreach: trxns">

where trxns are all the transactions in a portfolio, an array in the Portfolio object. The value binding is the most basic. There are bindings for all sorts of situations, like text, html, css, if, checked, hasfocus—and what is not there can be developed without too much effort. This too can be found in the Knockout documentation.

Dependency Tracking

This is arguably the most sought-after feature of JavaScript MVC frameworks, and Knockout has an easy-to-use implementation. Dependency tracking enables automatic UI refreshes based on model data value changes. For instance, when the underlying model for the field “name” changes, the UI will update. The bindings are two-way—so updates to a textbox that is bound to an observable will update the model.

The key to this is observables. Your JavaScript object properties need to be initialized as Knockout observables. This puts an abstraction between the actual property and how it’s changed or read. At the same time, Knockout can track the property, know when it’s changed, and fire the events to update anything that is bound to this property. This code illustrates the Portfolio JavaScript object as an observable:

 var portfolioViewModel = {
  name : ko.observable(‘401k’),
  id : ko.observable (99),
  owner : ko.observable (“454-abc-565”)
 };

Now, when the name field is updated, Knockout knows and can respond by triggering the bound items to update. You can also manually subscribe to change events to be notified of a change.

Templates

With a client-side template you’ll find a new canvas of possibilities. Since you are in your view to do view rendering, you can keep iterative looping structures and their associated template close by. As well, the basics of client-side templating mean that the server side can be more concerned about getting the correct data, in the correct format, and not the semantic nature of the data returned. In this way, the FED’s on the team can handle binding large amounts of data into the appropriate UI structures. It can be changed, swapped, iterated on—all independent of any server-side compiles or deployments.

 <div data-bind="template: { name: 'transaction-template',
  data: trxns }"></div>
  
 <script type="text/html" id="transaction-template">
     <p> data-bind="text: name"></p>
     <p>Purchase Price: <span class="price"
  data-bind="text: price"></span></p>
 </script>

Here we have the trxns collection, from our view-model. The first line says: “bind this data set to the named template and put the content here in my div.” There are many different ways to work with templates and a myriad of applications for them—this is the most basic. Templates work in conjunction with observables and declarative bindings—it is the transportation and implementation engine for those concepts in most cases. The client-side templates also put the CSS and the actual markup closer together, as these are components that should ride side by side and exhibit some cohesion.

Debugging

The most applicable tool to debugging Knockout applications, or any JavaScript MVC framework applications, is Firebug for Firefox or any other browser development tool in your favorite browser.

For example, if you want to validate that your bindings are working when an observable is updated, you could type something like this right into the console in firebug and watch the UI for the update. The below would turn any field, bound to MarketValue to 555 in the UI.

 viewModel.HoldingTransactions()[0].MarketValue(555) //updates the
  //model directly for the first transaction in the
  //transactions collection on the view model

Conclusion

JavaScript MVC frameworks are enabling technologies. They enable you to bring domain concepts cleanly into the front end, work with familiar concepts, and promote full-stack development. They also may help your application improve its layering and use of REST-based lightweight service tiers, and you’ll generally end up with more modular clean code.

They do this through declarative bindings, dependency tracking, and templating. A JavaScript MVC framework can be a great benefit to the technology your team uses as well as the possibilities that are opened up when a solid abstraction and framework are in place. Happy coding.

Stephen Rylander is a technical lead with Morningstar focusing on web platforms on a global scale. He focuses on technical design, high quality code, teams and automation. Stephen has worked on four different public web platforms handling millions of daily page views, from finance to ecommerce to music and entertainment. He is adept at working with globaly distributed teams and has accepted that enjoying software development more than most people is just somethign he'll have to live with. He is also married, loves to cook and has two beautiful children.

Send the author your feedback or discuss the article in the magazine forum.