Backbonification
Migrating NewsBlur from
DOM spaghetti to Backbone.js
Samuel Clay
November 2012
Backbone.js patterns and pitfalls
— covering —
Slide 2
Slide 2 text
Background
• Started NewsBlur as a side-project in 2009
• Open-source since the beginning
• DocumentCloud alum
Slide 3
Slide 3 text
No content
Slide 4
Slide 4 text
No content
Slide 5
Slide 5 text
Folder
Feed
Unread count
Feed list header
Feed list
Unread count
Reading pane
Feed (story view)
Story title
Original/Feed view
Intelligence Level
Slide 6
Slide 6 text
No content
Slide 7
Slide 7 text
No content
Slide 8
Slide 8 text
Project
Account
Project List
Organizer
Visual Search
Facet Facet input
Workspace
Toolbar
Document List
Document
Slide 9
Slide 9 text
Task at hand
• Small handful of JavaScript files
• 8,500 lines in biggest file
• One file for templates, drawing,
delegation, element caches, state, view
modes
Slide 10
Slide 10 text
Performance
• Only necessary calculations were made
• Tree traversal time was eliminated
0
100
200
300
JavaScript Backbone.js
feed page load (milliseconds)
0
325
650
975
1,300
JavaScript Backbone.js
folder draw (milliseconds)
Slide 11
Slide 11 text
Pre-requisites
• Underscore.js
Slide 12
Slide 12 text
Pre-requisites
• Backbone.js
Router
Collection
Model Model
Model
View
View View
Model
Slide 13
Slide 13 text
Moving routers
• You have routers
• Even multiple routers
• If it touches a URL, use a router
Slide 14
Slide 14 text
Moving routers
• It’s where you can stick those out-of-
band ajax calls
• Anything having to do with the url
Slide 15
Slide 15 text
Moving models
Slide 16
Slide 16 text
Moving models
• The schema coming from the server
• May cause versioning
• Server should be sending lists of
dictionaries
Slide 17
Slide 17 text
Moving models
• Passing ?v=2 now gives arrays:
• Data used to be given in this format:
Slide 18
Slide 18 text
Moving models
• Transparently append the API version as a
parameter by overriding your collection’s
fetch method.
Moving models
• Pass a Backbone model's model.attributes to
old JavaScript methods
• When done migrating, clean up by looking
for .attributes
Slide 21
Slide 21 text
Moving models
• Populating a collection that has side-effects
• Rendering child views before the parent view
means they will be attached to the wrong
parent view
• Pass {silent: true} to the initial reset, then
manually trigger the reset event with
Collection.change()
• Another option is to use _.defer()
Slide 22
Slide 22 text
Moving models
• Listening for events on a collection's models
• For convenience, model events also show as
collection events
Slide 23
Slide 23 text
Moving models
• Bind to the change event but only update on
specific attributes using model.hasChanged()
and model.previousAttributes()
Slide 24
Slide 24 text
Moving models
• Listening to the change event instead of
change:attribute because change is fired last
Slide 25
Slide 25 text
Moving models
• Intermediary models can be used as pointers
to selected models
Moving views
• Most common change is from event binding
to event delegation
Slide 32
Slide 32 text
Moving views
• Splitting up views for the same element
Slide 33
Slide 33 text
Moving views
• Changing the top-level element of a view
• But don’t forget about the element on page if
you’re re-rendering the view
Slide 34
Slide 34 text
Folder view
Folder view
Folder view
Slide 35
Slide 35 text
No content
Slide 36
Slide 36 text
No content
Slide 37
Slide 37 text
No content
Slide 38
Slide 38 text
No content
Slide 39
Slide 39 text
Moving views
• View collections
Slide 40
Slide 40 text
No content
Slide 41
Slide 41 text
Moving views
• Traversing a view by keeping track of the
active view in the collection
Slide 42
Slide 42 text
Moving views
• Action hierarchy
• Delegate responsibility up the chain
Slide 43
Slide 43 text
Moving views
• No need for a model to back a view
Slide 44
Slide 44 text
Common pitfalls
Slide 45
Slide 45 text
Common pitfalls
• TypeError: 'undefined' is not an
object (evaluating 'func.bind')
• Comes from trying to bind to a
method that doesn't exist
Slide 46
Slide 46 text
Common pitfalls
• Firing a change event while still setting
up models and views
• Add {silent: true} to a model.set()
call if you're not ready to handle the
change events
• When views are all setup, blast out
a .change()
Slide 47
Slide 47 text
Common pitfalls
• Re-rendering the view just to get a
class toggled on or off
• Selectively re-render/toggle classes
based on specific change events
Slide 48
Slide 48 text
Common pitfalls
• Cleanup of ghost views
• The model still has bindings to the
destroyed view
Slide 49
Slide 49 text
Common pitfalls
• The disappearing view
Slide 50
Slide 50 text
Resources that I liked
• Developing Backbone.js Applications
by Addy Osmani
addyosmani.github.com/backbone-fundamentals
• Backbone Patterns
by Rico Sta. Cruz
ricostacruz.com/backbone-patterns
Slide 51
Slide 51 text
Thank you for listening
• Go ask @samuelclay more questions
• Get yourself on www.newsblur.com