Backbone.js in the Wild

Require ['Backbone', 'and', 'More']
One way to organize a pro Backbone App


Houston.JS Meetup - 7/25/2012

Kaleb Fulgham

What is Backbone.js?

Backbone.js gives structure to web applications by providing models with key-value binding and custom events, collections with a rich API of enumerable functions, views with declarative event handling, and connects it all to your existing API over a RESTful JSON interface.

Hold up, what is web programming?

Backbone.js, In review

MVC, MVP, MV*...

  1. Models with key-value binding
  2. Collections to enumerate
  3. Views with declarative event handling
  4. Routers provide browser history support
  5. Events galore!

It is not

An imposing goliath JavaScript
"Skeleton"

A UI widget library
"Body"

It is simple

  1. Solid minimal base framework
  2. Easy to extend functionality
  3. Does not impose UI design constraints

It is a Backbone!

That's all folks.

## Beyond a todo list
How can we develop *professional* JavaScript applications with Backbone?
## TL;DR
### Do not write applications in *vanilla* Backbone
### If you plan anything non-trivial, do not start with Backbone *alone*
### Utilize an application structure and ### set conventions

Pro Backbone Apps

  1. Organization
  2. Maintainability
  3. Extensibility
  4. Testing
## But there are so many different ways to do...
### Don't be afraid to make *decisions*.
### Choose, develop, and ship it!

ReBrew

Discover and rebrew coffee, tea, wine, and beer venues


Demo application

# 1. Organization Backbone does not outline how to organize code No directory structure or strict naming conventions
### Again, many options
## Modules are not new
function Module () {
              return {
                someStuff: { ... },
                foo: function() { ... }
              };
            }
            

Addy Osmani has helpful notes on the [Module pattern](http://addyosmani.com/resources/essentialjsdesignpatterns/book/#modulepatternjavascript).
![img/brain.jpg](img/brain.jpg)
Your need for modules is directly related to how much of your app you can hold in your head at once.
— Alex Sexton
# App Structure
## All too common
|+ App
           |- app.js
           |- controllers.js
           |- models.js
           |- views.js
           |- index.html
          

### *Dependency management nightmare*
## How about a ## *module per file*?
## Option 1 ### Type Directory + Object File
var UserModel = require('Models/User');
            var UserView  = require('Views/User');
            
Which results in this file structure
|+ App
             |+ Models
              |- User.js
             |+ Views
              |- User.js
            
## Option 2 ### Combo
var UserModel = require('UserModel');
            var UserView  = require('UserView');
            
Which results in this file structure
|+ App
             |- UserModel.js
             |- UserView.js
            
## Option 3 ### Module Directory + Type File
var UserModel = require('User/Model');
            var UserView  = require('User/View');
            
Which results in this file structure
|+ App
             |+ User
              |- Model.js
              |- View.js
            
## I propose a 4th option...
## Option 4 ### Module Directory + Type Directory/File + Module File
var UsersModel = require('modules/Users/Model');
            var UsersView  = require('modules/Users/views/MyView');
            var Users = require('modules/Users');
            
## Option 4 ### Module Directory + Type Directory/File + Module File Which results in this file structure
|+ App
             |- modules
               |- Users
                 |- views
                   |- MyViews.js
                 |- Model.js
                 |- Collection.js
                 |- Router.js
               |- Users.js
            
## AMD + RequireJS ### Asynchronous Module Definition
# Libs to require
define ['backbone'], (Backbone) ->
    # Create a simple module
    Venue = Views: {}
    class Venue.Model extends Backbone.Model
        defaults:
            categories: []
            name: 'Tasty Coffee Cafe'
    Venue # Return the module for AMD compliance
## AMD + RequireJS == 'LOVE'
When you no longer *require* a file. It is no longer requested or included.
#### performance++
[Alex Sexton](https://github.com/SlexAxton) has a lengthy blog post on [his thoughts on AMD](http://alexsexton.com/blog/2012/03/my-thoughts-on-amd/).
Now I have *modular* & *AMD* classes. What's next?!
# 2. Maintainability
## Grunt.js
### Node.js powered *task-based* command line build tool for JavaScript projects.
## Tasks, tasks, and more tasks * coffee - Compile CoffeeScript files * concat - Concatenate files. * init - Generate project scaffolding from a predefined template. * lint - Validate files with JSHint. * min - Minify files with UglifyJS. * qunit or jasmine - Run *tests* in a headless PhantomJS instance. * requirejs - Runs the r.js command to process *RequireJS* * server - Start a static web server. * watch - Run predefined tasks whenever watched files change. * etc. (many more Grunt tasks can be found in the npm repo)
### Grunt takes all code, templates, and CSS and compiles them into deliverables
## Backbone Boilerplate framework tool [grunt-bbb](https://github.com/backbone-boilerplate/grunt-bbb)
### *bbb* creates a *solid* scaffold for Backbone apps
## Scaffold Structure ![img/bbb_myapp.png](img/bbb_myapp.png)
## bbb debug
C:\dev\myapp>bbb debug <--- "Executes debug build target"
                Running "clean:0" (clean) task
                Removing: dist/
Running "lint:files" (lint) task Lint free.
Running "jst:dist/debug/templates.js" (jst) task File "dist/debug/templates.js" created.
Running "requirejs" task C:/dev/myapp/dist/debug/require.js ---------------- C:/dev/myapp/assets/js/libs/jquery.js C:/dev/myapp/assets/js/libs/lodash.js <--- "Swap with underscore.js" C:/dev/myapp/assets/js/libs/backbone.js C:/dev/myapp/assets/js/plugins/backbone.layoutmanager.js C:/dev/myapp/app/app.js C:/dev/myapp/app/router.js C:/dev/myapp/app/main.js C:/dev/myapp/app/config.js
Running "concat:dist" (concat) task File "dist/debug/require.js" created.
Done, without errors.
# 3. Extensibility
Again, do *not* use vanilla Backbone
## Backbone Application Framworks
### Backbone.Marionette Flexible, mature, & comprehensive library for Backbone apps [Github Backbone.Marionette](http://derickbailey.github.com/backbone.marionette/)

Before Marionette

# Define the Item View for each Model
class ItemView extends Backbone.View
    tagName: 'li'
    template: _.template $('#item-template').html()

    initialize: ->
        @model.on 'change', @render, @
        @model.on 'destroy', @remove, @

    render: ->
        @$el.html @template( @model.toJSON() )
        @

    clear: ->
        @model.clear()

Before Marionette

# Define the List View which creates Item View(s)
class ListView extends Backbone.View
    tagName: 'ul'
    template: _.template $('#list-template').html()

    initialize: ->
        @collection.on 'add', @addItem, @
        @collection.on 'remove', @removeItem, @
        @collection.on 'reset', @render, @

    addItem: -> # Add item to local model-to-view children map
    removeItem: -> # Remove item from above map

    render: ->
        @$el.html ''
        @collection.each (model) ->
            view = new ItemView model: model
            @$el.append view.render().el

With Marionette

class MItemView extends Backbone.Marionette.ItemView
    tagName: 'li'
    template: '#item-template'

class MListView extends Backbone.Marionette.CollectionView
    itemView: MItemView

It's that Simple

### Automatic re-render on change, add, or remove
### Built-in memory management. No zombie views
### Listen for events triggered at all render stages
### Chaplin Structure, conventions, and a field-tested implementation [![img/chaplin.png](img/chaplin.png)](https://github.com/chaplinjs/chaplin)
### Thorax (Walmart) Structure, modular, form serialization, & opinionated (especially in mobile) [Github Thorax](http://walmartlabs.github.com/thorax/)
## Framework Key Features
## Modularization
## Routing
## Layouts
## Complex Views
## Templates
## Event-driven Architecture
## Memory Management
Mathias from MoviePilot presented
[Application framework plugins on top of Backbone](https://speakerdeck.com/u/molily/p/application-frameworks-on-top-of-backbonejs-talk-at-appsberlinjs)
# 4. Testing
There is no excuse. *Test* your code!
## Jasmine, Mocha, or QUnit
With *modular* code, you are already doing yourself a favor when it comes to test separation.
# DEMO [ReBrew](https://github.com/kalebdf/rebrew)
# Thank you!

Questions?



We are hiring UI Developers!

Kaleb Fulgham (@kalebdf)

kfulgham@prospricing.com

## Links & References * [ReBrew App source code on github](https://github.com/kalebdf/rebrew) * [Backbone.Marionette plugin](https://github.com/derickbailey/backbone.marionette) * [Read more about Backbone & Backbone.Marionette](http://lostechies.com/derickbailey/) * [Application framework plugins on top of Backbone](https://speakerdeck.com/u/molily/p/application-frameworks-on-top-of-backbonejs-talk-at-appsberlinjs) * [MVC Module Magic Talk](https://github.com/SlexAxton/MVCModuleMagicTalk) * [Backbone + Require.js](http://backbonetutorials.com/organizing-backbone-using-modules/) * [Addy O. and JS Design Patterns](http://addyosmani.com/resources/essentialjsdesignpatterns/book/) * [Houston.js Meetup Group](http://houstonjs.com)