A mini-diary
Before I get completely seduced by Angular.JS and others equally as sweet for use on an upcoming and very important web app project, I really need to give Backbone.js another chance, a fair chance. Nothing could provide this with better timing than the publication now of the completed Developing Backbone Applications, by Addy Osmani. The book signifies a big change, in that it is simpler to dive into Backbone.js, and you can do it with more confidence since you are being shown a path following best practices.
Here’s the rub: Backbone.js is “not opinionated, meaning you have the freedom and flexibility to build the best experience for your web application however you see fit. You can either use the prescribed architecture it offers out of the box or extend it to meet your requirements.”
The question is, do I have the wherewithall to cope with that much freedom? Is it even a good idea? Shouldn’t I go with one of the more opinionated framework libraries, like AngularJS? Like black box. Like “do it my way, just do it (this way)”.
This article will contribute to my answer to that question, and might even help someone asking herself similar questions.
MV* Fundamentals
The Fundamentals chapter is important, not just for the habitual discussion on design patterns, but for some non-trivial distinctions that are seldom addressed:
-
The difference between a desktop MVC app (i.e., Smalltalk-80 MVC) and a web app, due to the fact that the context of the latter involves the “HTTP protocol, which is stateless. This means that there is not a constantly open connection between the browser and server…. This fact creates a completely different context when compared to the one of the operating systems on which many of the original MVC ideas were developed. The MVC implementation has to conform to the web context.”. The Ruby on Rails HTTP request lifecycle is then shown as an example of server side MVC (actually Model2), as is the Front Controller variant pattern exemplified by the Zend Php framework.
-
The implications of the rise of client-side and single-page apps in the battle against latency caused by heavy client server data query HTTP request traffic, as a further distinction: “The need for fast, complex, and responsive Ajax-powered web applications demands replication of a lot of this logic on the client side, dramatically increasing the size and complexity of the code residing there. Eventually this has brought us to the point where we need MVC (or a similar architecture) implemented on the client side to better structure the code and make it easier to maintain and further extend during the application lifecycle.”
Then and only then is the Backbone.js style presented, and the need for departure from MVC nailed:
“It’s with controllers that most JavaScript MVC frameworks depart from the traditional interpretation of the MVC pattern. The reasons for this vary, but in my opinion, Java‐ Script framework authors likely initially looked at server-side interpretations of MVC (such as Ruby on Rails), realized that the approach didn’t translate 1:1 on the client side, and so reinterpreted the C in MVC to solve their state management problem. This was a clever approach, but it can make it hard for developers coming to MVC for the first time to understand both the classical MVC pattern and the proper role of controllers in other JavaScript frameworks.
“So does Backbone.js have controllers? Not really. Backbone’s views typically contain controller logic, and routers are used to help manage application state, but neither are true controllers according to classical MVC.
“In this respect, contrary to what might be mentioned in the official documentation or in blog posts, Backbone isn’t truly an MVC framework. It’s in fact better to view it a member of the MV* family that approaches architecture in its own way.”
And that architecture is important for what it gives us in common with MVC, the separation of concerns.
Diving right into the Backbone Basics chapter
The book itself is released as a creative commons book right on GitHub: http://addyosmani.github.io/backbone-fundamentals/ and the repo includes instructions for building it out of source, as well as separate code samples in the practicals folder: https://github.com/addyosmani/backbone-fundamentals So for example, you can find Exercise 2 (the Book Library from chapter 5) in https://github.com/addyosmani/backbone-fundamentals/tree/gh-pages/practicals/exercise-2
For the basics chapter, readers are encouraged to get set up with a simple html boilerplate (p. 27) that can be re-used to run the examples in a browser, or on jsFiddle, etc.; “For Chrome, you can open up the DevTools via the Chrome menu in the top-right corner: select Tools→Developer Tools or alternatively use the Ctrl+Shift+I shortcut on Windows/Linux or ⌘-Alt-I on Mac.” Which is what I did to just copy over the Chapter 3 examples and run them.
To explore the basic code, I downloaded and set up TodoMVC on my laptop from http://todomvc.com/. I have nginx on my Mac, so I just copied the contents of the downloaded zip file to /usr/local/var/www/todomvc and pointed my browser to http://localhost:8080/todomvc/architecture-examples/backbone/ (from http://localhost:8080/todomvc/ I just clicked on the backbone.js link).
To create a link in finder to /usr/local I did a open -a Finder /usr/local in a terminal, then did a Command-T to put a permanent link in finder. That way I was able to open the /usr/local/var/www/todomvc directory inside WebStorm.
It was actually very interesting just to copy and paste and execute in the console, as suggested. To do this, I created a file called index.html and populated it with the code on pp. 27-28. I then opened it as a local file in Chrome, then did “Hamburger” (Menu) → Tools → Developer Tools (also works: press option and command keys and “i” key simultaneously). I then click on Console and can copy and paste multiple lines of code and execute by typing enter. Since the html file opened in the browser satisfies basic backbone dependencies (loading backbone, jquery and underscore) I can copy and paste, and also type multiple lines (control enter to continue typing on next line without executing). Executing the code by pressing enter executes it and you can see the logs to console. In this way it is possible to check out the Backbone Basics chapter without too much hassle, interactively.
Or else directly stick the code between the script tags, like this (pp. 31-32):
<!DOCTYPE HTML> <html> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"> </script> <script src="http://documentcloud.github.com/underscore/underscore-min.js"> </script> <script src="http://documentcloud.github.com/backbone/backbone-min.js"> </script> <script> // Your code goes here var Todo = Backbone.Model.extend({ // Default todo attribute values defaults: { title: '', completed: false } }); // Setting the value of attributes via instantiation var myTodo = new Todo({ title: "Set through instantiation." }); console.log('Todo title: ' + myTodo.get('title')); // Todo title: Set through instantiation. console.log('Completed: ' + myTodo.get('completed')); // Completed: false // Set single attribute value at a time through Model.set(): myTodo.set("title", "Title attribute set through Model.set()."); console.log('Todo title: ' + myTodo.get('title')); // Todo title: Title attribute set through Model.set(). console.log('Completed: ' + myTodo.get('completed')); // Completed: false // Set map of attributes through Model.set(): myTodo.set({ title: "Both attributes set through Model.set().", completed: true }); console.log('Todo title: ' + myTodo.get('title')); // Todo title: Both attributes set through Model.set(). console.log('Completed: ' + myTodo.get('completed')); // Completed: true </script> <h2>Hola, mundo</h2> </body> </html>
When you edit the html file and reload, the console.log statements will be executed along with everything else. Cool.
jsfiddle.com is a nice alternative, too; an example is cited in the book for the Validation section: http://jsfiddle.net/2NdDY/7/
In this way, you get to play around with the basic backbone.js concepts: models, views (and what’s “el”?), collections, events, routers, RESTful persistence, the Sync API and Backbone dependencies.
Exercise 1 – the TODO example
This is a pedagogical reconstruction of the TodoMVC Backbone example. So in order to end up with essentially the same thing, I downloaded TodoMVC, copied architecture-examples/backbone to a separate directory, copied in assets to to the same level as js, and edited index.html to reflect the following file tree:
exercise-1/ ├── assets │ ├── base.css │ ├── base.js │ ├── bg.png │ ├── director.min.js │ ├── handlebars.min.js │ ├── ie.js │ ├── jasmine │ │ ├── jasmine-html.js │ │ ├── jasmine.css │ │ └── jasmine.js │ ├── jquery.min.js │ ├── lodash.min.js │ └── require.min.js ├── index.html └── js ├── app.js ├── collections │ └── todos.js ├── lib │ ├── backbone.js │ └── backbone.localStorage.js ├── models │ └── todo.js ├── routers │ └── router.js └── views ├── app.js └── todos.js
I loaded up index.html into a local Chrome browser and it worked fine. And then followed along in the chapter.
Exercise 2 – Book Library—Your First RESTful Backbone.js App
This chapter is a lot of fun, and very rewarding, since you can work along with the book file by file and step by step and really understand what’s going on. And you get a complete backbone.js app talking to your own node.js, express.js and mongodb backend, and see how the directories and bootstrapping of the app occurs. The end result is similar to what you get from the practicals/exercise-2 directory of the backbone-fundamentals repo on Github.
I particularly like the way Express templates are avoided completely, and the whole backbone app is launched via an Express.js static invocation:
//Where to serve static content app.use( express.static( path.join( application_root, 'site') ) );
which invokes site/index.html directly (notice the use of the Node.js path module, which greatly simplifies things).
On my Mac I had mongodb installed via homebrew, and node via nvm, so executing was simple, I started up mongodb:
$ mongod all output going to: /usr/local/var/log/mongodb/mongo.log
and then executed the app:
$ node server.js Express server listening on port 4711 in development mode
and was able to work with the app at url http://localhost:4711/
Conclusion
Frankly I’m excited. Thanks to this book, I was attracted towards diving into Backbone.js once again despite my lack of free time to do so, since I am motivated by both clarity and a clear path following best practices. I’ll have a lot more to say about this book in particular and my future use of backbone.js on important projects of my own in the near future.