From Mess to Success,
Refactoring Large Applications with Backbone
dev.Objective()
May 14, 2015
Stacy London
@stacylondoner
McWay Falls, Julia Pfeiffer Burns State Park - Big Sur, CA - 2015 by Stacy London
About Me
I’ve been making things for the web since 1998.
Currently I’m a Senior Application Architect focused on
Front-End Engineering at Northwestern Mutual.
@stacylondoner
Northwestern Mutual
Northwestern Mutual has been helping families and businesses achieve
financial security for nearly 160 years. Our financial representatives build
relationships with clients through a distinctive planning approach that integrates
risk management with wealth accumulation, preservation and distribution. With
more than $230 billion in assets, $27 billion in revenues, nearly $90 billion in
assets under management and more than $1.5 trillion worth of life insurance
protection in force, Northwestern Mutual delivers financial security to more than
4.3 million people who rely on us for insurance and investment
solutions, including life, disability and long-term care insurance; annuities; trust
services; mutual funds; and investment advisory products and services.
Northwestern Mutual is the marketing name for The Northwestern Mutual Life Insurance Company, Milwaukee, WI, and its
subsidiaries. Northwestern Mutual and its subsidiaries offer a comprehensive approach to financial security solutions including: life
insurance, long-term care insurance, disability income insurance, annuities, investment products, and advisory products and
services. Subsidiaries include Northwestern Mutual Investment Services, LLC, broker-dealer, registered investment adviser,
member FINRA and SIPC; the Northwestern Mutual Wealth Management Company, limited purpose federal savings bank; and
Northwestern Long Term Care Insurance Company.
What do I mean by large application?
• a multi-page web application (MPA) built with ASP.NET
MVC
• 1500+ files | 343,000+ lines of code
• UI (CSS / JS)
• 230+ files | 42,000+ lines of code
Development Culture
• JEE/Java shop turned .NET/C#
• view JS as a bit of a “toy” language
• as JS was being added it was just being added without much
thought to maintainability, extensibility, testability, patterns,
etc.
• app was going to be heavy with JS yet initially on a platform
that wasn’t optimized for this kind of app dev.
• path of least resistance was to just put everything in 

$(document).ready()
https://www.youtube.com/watch?v=J---aiyznGQ
http://starecat.com/kermit-typing-on-a-typewriter-like-crazy-animation/
$(document).ready(function() {
});
http://www.wikihow.com/Make-a-Quick-Italian-Spaghetti
Problems
• one large JavaScript file in the <head> (all code included
on every page regardless if it needed it)
• all JavaScript global and in $(document).ready()
• some pages had inline JavaScript
• not commented
• no unit tests
• unclear if a function / event was used on multiple pages
Iterative Refactoring
• big codebase
• large team working on 2 week sprints that couldn’t be
slowed down
• refactors had to fit into a sprint
Refactor Large applications with Backbone
Refactor Large applications with Backbone
Refactor, Iteration 1: Break Apart JS
• figure out what JS belongs with each page and move
that JS into a separate file for that page
• include that JS with the partial HTML
Refactor, Iteration 1: Start Adding Unit Tests
• start adding unit tests for original code then make sure it
passed after refactoring as a safety/confidence
mechanism
• to prepare for this journey of breaking code into smaller,
more testable chunks it was good to start early with
creating a test bed
• help make subsequent refactors less stressful
Refactor, Iteration 1: Start Adding Unit Tests
• picked Jasmine (BDD style) - http://
jasmine.github.io/
• a lot of the JS tied to DOM manipulation so not in
an ideal state for unit testing with Jasmine out of
the box
• needed DOM testing helper so added jquery-
jasmine library to add fixtures (HTML snippets
to run tests against)
• no external UI Regression tools (e.g. Selenium) in a
state to do this validation throughout the refactor
Refactor Large applications with Backbone
Refactor Large applications with Backbone
Refactor, Iteration 2: Namespacing & Object Literal
• create an app namespace to get custom code out of the global
namespace (window) to avoid collisions with external libs/
frameworks
• introduce an Object Literal notation style in preparation for
Backbone (which uses this pattern)
• helps to organize the code and parameters logically

“an object containing a collection of key:value pairs with a colon
separating each pair of keys and values where keys can also
represent new namespaces”
• add closures with Instantly Invoked Function Expressions
(IIFEs)
https://gist.github.com/stacylondon
;
var myApp = myApp || {};
(function($, myApp) {
'use strict';
$.extend(myApp, {
init: function() {
this.commonStuff();
},
commonStuff: function() {
// common code across many or all pages
}
});
})(window.jQuery, window.myApp);
$(document).ready(function() {
myApp.init();
});
my-app.js
my-app.js
with comments
// prefix with semi-colon as safety net against concatenated
// scripts and/or other plugins that are not closed properly
;
// check for existence of myApp in the global namespace
var myApp = myApp || {};
// Use IIFE to:
// * encapsulate app logic to protect it from global namespace
// * pass in namespace so can be modified locally and isn't
// overwritten outside of our function context
// * ensure $ only refers to window.jQuery (defensive programming)
// * $ passed through as local var rather than as globals and this
// (slightly) quickens the resolution process and can be more
// efficiently minified (especially if regularly referenced)
(function($, myApp) {
my-app.js
with comments
(function($, myApp) {
// Strict mode makes several changes to normal JavaScript semantics:
// * eliminates some JS silent errors by changing them to throw errors.
// * fixes mistakes that make it difficult for JavaScript engines to
// perform optimizations: strict mode code can sometimes be made to
// run faster than identical code that's not strict mode. Add inside
// the IIFE so it's defined for just the functions defined within and
// doesn't flip concatenating/minified code to strict inadvertently
'use strict';
// extend the namespace with more functionality
$.extend(myApp, {
;
var myApp = myApp || {};
myApp.pageOne = myApp.pageOne || {};
(function($, myApp) {
'use strict';
$.extend(myApp.pageOne, {
init: function() {
this.pageSpecificStuff();
},
pageSpecificStuff: function() {
// code specific to this page
}
});
})(window.jQuery, window.myApp);
$(document).ready(function() {
myApp.pageOne.init();
});
page-one.js
Better but not great
• code is aligned with the screen to which is pertains
• pages now have mid-page script includes which isn’t
good for performance / rendering
• still hand-wiring Ajax calls
• entire-page-JS is not very modular
• want to break screens down into smaller features and
keep events neatly associated
Backbone to the rescue
• wanted something that provided/enforced structure but in a
lightweight way
• it’s a MPA not a SPA so full-featured SPA frameworks didn’t make
sense (e.g. Angular, Ember)
• wanted to be able to use just a small feature of the library/
framework and add more full integration over time (refactor in
multiple iterations)
• for these reasons Backbone.js made sense - http://backbonejs.org/
Refactor Large applications with Backbone
Refactor, Iteration 3: Page Level Backbone Views
• reducing boilerplate code
• views enforce organization of events
• views enforce an Object Literal notation pattern
• views helped developers think about encapsulating pieces of the
screen
• starting with just Views gave the team time to start planning for
refactoring back-end data provided by ASP.NET MVC Controllers
into more RESTful web services (Web API) which is necessary to
take full advantage of Backbone.js Models/Collections
Refactor, Iteration 3: Page Level Backbone Views
• my-app.js - is now responsible for instantiating the app
namespace and setting up a super light-weight view
manager for Backbone.js
• instantiate all available views on the page upon DOM
ready.
• page-one-view.js - no longer namespaced individually
since being added to the views object of the app
namespace
Refactor Large applications with Backbone
my-app.js
var myApp = myApp || {};
(function($, myApp) {
'use strict';
$.extend(myApp, {
init: function() {
this.initializeViews();
},
// view manager code
});
})(window.jQuery, window.myApp);
$(document).ready(function() {
myApp.init();
});
my-app.js
view manager
views: {},
initializeViews: function() {
for (var view in this.views) {
if (typeof this.views[view] === 'function') {
this.views[view.substring(0, 1).toLowerCase() +
view.substring(1, view.length)] = new this.views[view]();
}
}
},
addView: function(key, view) {
if (this.views.hasOwnProperty(key)) {
throw (new Error('A view with that key already exists.'));
}
this.views[key] = view;
},
getView: function(key) {
if (!this.views.hasOwnProperty(key)) {
throw new Error('View does not exist in views collection.');
}
return this.views[key];
}
page-one-view.js;
(function($, _, Backbone, myApp) {
'use strict';
var PageOneView = Backbone.View.extend({
el: '#pageOneMainContainer',
events: {
'click .something': 'doSomething'
},
initialize: function() {
this.setupValidation();
},
setupValidation: function() {
},
doSomething: function() {
}
});
myApp.addView('PageOneView', PageOneView);
}(window.jQuery, window._, window.Backbone, window.myApp));
Refactor Large applications with Backbone
Refactor, Iteration 4: Sub-Page Backbone Views
• start breaking the large page views into sub-page views
so that you can get truly modular
• share modules/code if a module exists on more than
one page
Refactor Large applications with Backbone
Refactor Large applications with Backbone
Refactor, Iteration 5: Backbone Models, Collections
• move code that is getting data and doing any business
logic out of the Views and into Models and Collections
• e.g. move phone number formatting out of View and
into the Model
• remove hand written Ajax, use BB API (e.g. fetch)
• make sure server side controllers were written in a
RESTful way
• still not complete across the application
Refactor Large applications with Backbone
var PageOneView = Backbone.View.extend({
el: '#pageOneMainContainer',
initialize: function() {
this.getSomeData();
},
getSomeData: function() {
var self = this;
$.ajax({
type: 'GET',
url: 'SomeEndpoint',
data: formData,
dataType: 'json',
success: function(data, textStatus, jqXHR) {
self.displayResults(data);
},
error: function(jqXHR, textStatus, errorThrown) {
self.displayError();
}
});
},
displayResults: function(data) {
},
displayError: function() {
}
});
Hand-wiring Ajax
Use Backbone.js API
to get data
// initialize view
var pageOneView = new PageOneView({
collection: new PageOneCollection([]),
});
var PageOneView = Backbone.View.extend({
el: '#pageOneMainContainer',
template: _.template($('#page-one-template').html()),
initialize: function() {},
render: function() {
this.$el.html(this.template({'collection': this.collection}));
// maintain chainability
return this;
}
});
var PageOneCollection = Backbone.Collection.extend({
initialize: function(models, options) {},
model: PageOneModel,
// RESTful web service URL
url: '/SomeEndpoint'
});
Refactor Large applications with Backbone
Refactor, Iteration 6: Mini-SPA
• treat each page of the multi-page app (MPA) like it’s a
miniature single page app (SPA)
• each page has a single entry point (main.js)
• this will setup the code for a module loader / build system
so that we can finally move the JS to the bottom of the
page and remove mid-page scripts
• improve performance (time to first paint - how long it
takes between a user entering a URL into the browser
and when he/she sees visual activity on screen)
Refactor Large applications with Backbone
Refactor Large applications with Backbone
Refactor Large applications with Backbone
Refactor, Iteration 7: Modules
• current version of JavaScript (ECMA-262) doesn’t provide a
way to import modules of code like more traditional
programming languages do
• modules are proposed for the next version of JS (ES6/
ES2015/Harmony)
• to use modules and manage dependencies with the current
version of JS you can use community driven methodologies
• there are two popular styles with associated script
loaders / build systems
Refactor Large applications with Backbone
Refactor, Iteration 7: Modules - AMD
• AMD - Asynchronous Module Definition



“The Asynchronous Module Definition (AMD) API
specifies a mechanism for defining modules such that the
module and its dependencies can be asynchronously
loaded. This is particularly well suited for the browser
environment where synchronous loading of modules
incurs performance, usability, debugging, and cross-
domain access problems.”

https://github.com/amdjs/amdjs-api/wiki/AMD
Refactor, Iteration 7: Modules - CommonJS
• CommonJS’s module format was made popular for
server-side JavaScript development (namely for Node.js/
NPM)
• it’s synchronous
• syntax is a bit easier as it frees you from the define()
wrapper that AMD enforces
• requires a build in a JS runtime
Refactor, Iteration 7: Modules - RequireJS
• popular script loader written by James Burke that helps you load
multiple script files and define modules with or without
dependencies
• use RequireJS as first pass at module loading since async nature
means no build step during dev time (least disruption to the dev
team which is important because there is a learning curve)
• use almond (AMD API shim) so don’t have to add a special script
tag to load RequireJS and change any HTML
• this will move the code away from IIFEs to modules with
dependency management
my-app.js
// requireJS simplified commonJS wrapper
// do this so can use the commonJS style &
// make switch to browserify easier
define('app', function(require, exports, module) {
'use strict';
var $ = require('jquery');
var _ = require('underscore');
var Backbone = require('backbone');
var Modernizr = require('modernizr');
var HeaderController = require('./header-controller');
var FooterController = require('./footer-controller');
var app = new Backbone.Application();
module.exports = app;
});
(function() {
var $ = require('jquery');
var app = require('app');
// dom ready
$(function() {
app.start();
});
}());
;
(function() {
'use strict';
var $ = require('jquery');
var PageOneController = require('./page-one-controller');
var app = require('app');
// dom ready
$(function() {
app.start({
ScreenController: PageOneController
});
});
}());
page-one-main.js
define('page-one-controller', function(require, exports, module) {
'use strict';
var Backbone = require('backbone');
var PageOneView = require('PageOneView');
var PageOneController = Backbone.Controller.extend({
initialize: function(options) {
var pageOneView = new PageOneView();
}
});
module.exports = PageOneController;
});
page-one-controller.js
define('page-one-view', function(require, exports, module) {
'use strict';
var Backbone = require('backbone');
var PageOneView = Backbone.View.extend({
});
module.exports = PageOneView;
});
page-one-view.js
Refactor, Iteration 7: Modules - Browserify
• Browserify lets you require('modules') in the browser by
bundling up all of your dependencies during a build step
• it’s the end-state module loader because it allows for easy
bundle splitting
• figure out common/shared JS and create a common
bundle then a bundle for the unique code on each page
• by having a main.js for each screen this will act as an
entry point so Browserify can find all the modules
required and create a screen-specific bundle
Refactor, Iteration 7: Modules - Browserify
• means build during dev but we were already doing that
for our CSS with LESS
• “It’s great the dev community has
embraced compilation because it’s
inevitable.” - Brendan Eich at Fluent 2015
• the code will become very clean
'use strict';
var Backbone = require('backbone');
var PageOneView = Backbone.View.extend({
el: '#pageOneMainContainer',
initialize: function() {}
});
module.exports = PageOneView;
page-one-view.js
Summary
• the JavaScript is now modular and easier to maintain
• Backbone.js helps devs keep consistent with coding patterns and
organization (Object Literal notation, events)
• events are scoped to the smallest part of the page to which they matter
(Backbone.js)
• namespacing/IIFEs and then later module loader/build removes the
possibility of collisions with other frameworks/libs
• unit tests mean you can feel more confident to change things
• only sending JS to the browser that is necessary is good for
performance (think mobile)
http://ak-static.scoopon.com.au/scpn/deals/main/50000/50693_2.jpg
"The secret to building large apps is never
build large apps. Break your applications
into small pieces. Then, assemble those
testable, bite-sized pieces into your big
application"
- Justin Meyer, author JavaScriptMVC
Team Shout Out
• This was over the course of several years and I worked
with two other fantastic front-end engineers:
• Ryan Anklam ( @bittersweetryan )
• Zeek Chentnik ( http://ezekielchentnik.com )
JavaScript References
• “Patterns For Large-Scale JavaScript Application Architecture” by Addy
Osmani 

http://addyosmani.com/largescalejavascript/
• “Learning JavaScript Design Patterns” by Addy Osmani

http://addyosmani.com/resources/essentialjsdesignpatterns/book/
• “Using Objects to Organize Your Code” by Rebecca Murphey

http://rmurphey.com/blog/2009/10/15/using-objects-to-organize-your-code/
• “It’s time to start using JavaScript strict mode” by Nicholas Zakas

http://www.nczonline.net/blog/2012/03/13/its-time-to-start-using-javascript-strict-
mode/
• “Writing Modular JavaScript with AMD, CommonJS & ES Harmony” by Addy
Osmani

http://addyosmani.com/writing-modular-js/
Backbone.js References
• “Developing Backbone.js Applications” by Addy
Osmani

http://addyosmani.github.io/backbone-fundamentals/
• “Communicating Between Views in Client-Side
Apps” by Rebecca Murphey

http://bocoup.com/weblog/communicating-between-
views-in-client-side-apps/
• Talks from past Backbone Conferences are free/online:
http://backboneconf.com/

http://backboneconf.com/2013/
Thank You!
@stacylondoner
Code Samples:

https://gist.github.com/stacylondon

More Related Content

PDF
Refactoring Large Web Applications with Backbone.js
PDF
In The Trenches With Tomster, Upgrading Ember.js & Ember Data
PDF
Testdrive AngularJS with Spring 4
PDF
Modern JavaScript, without giving up on Rails
PDF
Ionic으로 모바일앱 만들기 #3
PDF
Introducing Rendr: Run your Backbone.js apps on the client and server
PDF
Hastening React SSR - Web Performance San Diego
PDF
The Point of Vue - Intro to Vue.js
Refactoring Large Web Applications with Backbone.js
In The Trenches With Tomster, Upgrading Ember.js & Ember Data
Testdrive AngularJS with Spring 4
Modern JavaScript, without giving up on Rails
Ionic으로 모바일앱 만들기 #3
Introducing Rendr: Run your Backbone.js apps on the client and server
Hastening React SSR - Web Performance San Diego
The Point of Vue - Intro to Vue.js

What's hot (19)

PDF
Modular Test-driven SPAs with Spring and AngularJS
PDF
Angular js
PDF
From Backbone to Ember and Back(bone) Again
PDF
Love at first Vue
PDF
introduction to Vue.js 3
PDF
Vue.js is boring - and that's a good thing
PDF
An introduction to Vue.js
PPTX
How to Build SPA with Vue Router 2.0
PDF
JavaScript Patterns and Principles
PPT
Building Single Page Application (SPA) with Symfony2 and AngularJS
PPTX
Vue 2.0 + Vuex Router & Vuex at Vue.js
PDF
Universal JS Web Applications with React - Luciano Mammino - Codemotion Rome ...
PDF
Create Restful Web Application With Node.js Express Framework
PDF
125 고성능 web view-deview 2013 발표 자료_공유용
PDF
The Art of AngularJS in 2015
PDF
Workshop 15: Ionic framework
PDF
Thinking in Components
PDF
Angular JS blog tutorial
Modular Test-driven SPAs with Spring and AngularJS
Angular js
From Backbone to Ember and Back(bone) Again
Love at first Vue
introduction to Vue.js 3
Vue.js is boring - and that's a good thing
An introduction to Vue.js
How to Build SPA with Vue Router 2.0
JavaScript Patterns and Principles
Building Single Page Application (SPA) with Symfony2 and AngularJS
Vue 2.0 + Vuex Router & Vuex at Vue.js
Universal JS Web Applications with React - Luciano Mammino - Codemotion Rome ...
Create Restful Web Application With Node.js Express Framework
125 고성능 web view-deview 2013 발표 자료_공유용
The Art of AngularJS in 2015
Workshop 15: Ionic framework
Thinking in Components
Angular JS blog tutorial
Ad

Viewers also liked (20)

PDF
Java scriptconfusingbits
PPTX
Load Balancing, Failover and Scalability with ColdFusion
PDF
API Management from the Trenches
PDF
Java scriptconfusingbits
PDF
Setting up your multiengine environment Apache Railo ColdFusion
PDF
Emberjs building-ambitious-web-applications
PDF
Test box bdd
PPTX
Workflows and Digital Signatures
PDF
In The Trenches With Tomster, Upgrading Ember.js & Ember Data
PPTX
Cold fusion is racecar fast
PDF
2015 in tothebox-introtddbdd
PDF
Solving Frequent ColdFusion Server Problems in New and Better Ways
PPTX
2014 cf summit_clustering
PDF
Realtime with-websockets-2015
PDF
Multiply like rabbits with rabbit mq
PPTX
Intro to JavaScript Tooling in Visual Studio Code
PDF
I am-designer
PPTX
Preso slidedeck
PDF
PDF
Accessible Video Anywhere with ColdFusion an AWS
Java scriptconfusingbits
Load Balancing, Failover and Scalability with ColdFusion
API Management from the Trenches
Java scriptconfusingbits
Setting up your multiengine environment Apache Railo ColdFusion
Emberjs building-ambitious-web-applications
Test box bdd
Workflows and Digital Signatures
In The Trenches With Tomster, Upgrading Ember.js & Ember Data
Cold fusion is racecar fast
2015 in tothebox-introtddbdd
Solving Frequent ColdFusion Server Problems in New and Better Ways
2014 cf summit_clustering
Realtime with-websockets-2015
Multiply like rabbits with rabbit mq
Intro to JavaScript Tooling in Visual Studio Code
I am-designer
Preso slidedeck
Accessible Video Anywhere with ColdFusion an AWS
Ad

Similar to Refactor Large applications with Backbone (20)

PDF
Rp 6 session 2 naresh bhatia
PDF
WebNet Conference 2012 - Designing complex applications using html5 and knock...
PDF
Os Haase
PPTX
React Basic and Advance || React Basic
KEY
Play Support in Cloud Foundry
PDF
Building Isomorphic Apps (JSConf.Asia 2014)
PPTX
Google app engine by example
KEY
Android Workshop
PPTX
Code Generation in Magento 2
PPTX
Full Stack_Reac web Development and Application
PPT
Advanced Web Development
PDF
Full Stack React Workshop [CSSC x GDSC]
PDF
Developing large scale JavaScript applications
PPTX
Mean stack Magics
PDF
Html5 and beyond the next generation of mobile web applications - Touch Tou...
PDF
Java Web Programming on Google Cloud Platform [3/3] : Google Web Toolkit
PDF
Front End Development for Back End Developers - UberConf 2017
PDF
Google Web Toolkit
PDF
jQuery Mobile and JavaScript
PPTX
Advanced #6 clean architecture
Rp 6 session 2 naresh bhatia
WebNet Conference 2012 - Designing complex applications using html5 and knock...
Os Haase
React Basic and Advance || React Basic
Play Support in Cloud Foundry
Building Isomorphic Apps (JSConf.Asia 2014)
Google app engine by example
Android Workshop
Code Generation in Magento 2
Full Stack_Reac web Development and Application
Advanced Web Development
Full Stack React Workshop [CSSC x GDSC]
Developing large scale JavaScript applications
Mean stack Magics
Html5 and beyond the next generation of mobile web applications - Touch Tou...
Java Web Programming on Google Cloud Platform [3/3] : Google Web Toolkit
Front End Development for Back End Developers - UberConf 2017
Google Web Toolkit
jQuery Mobile and JavaScript
Advanced #6 clean architecture

More from ColdFusionConference (20)

PDF
Api manager preconference
PDF
PDF
Building better SQL Server Databases
PDF
API Economy, Realizing the Business Value of APIs
PDF
Don't just pdf, Smart PDF
PDF
Crafting ColdFusion Applications like an Architect
PDF
Security And Access Control For APIS using CF API Manager
PDF
Monetizing Business Models: ColdFusion and APIS
PDF
Become a Security Rockstar with ColdFusion 2016
PDF
ColdFusion in Transit action
PDF
Developer Insights for Application Upgrade to ColdFusion 2016
PDF
Where is cold fusion headed
PDF
ColdFusion Keynote: Building the Agile Web Since 1995
PDF
Instant ColdFusion with Vagrant
PPT
Restful services with ColdFusion
PDF
Super Fast Application development with Mura CMS
PDF
Build your own secure and real-time dashboard for mobile and web
PDF
Why Everyone else writes bad code
PDF
Securing applications
PDF
Testing automaton
Api manager preconference
Building better SQL Server Databases
API Economy, Realizing the Business Value of APIs
Don't just pdf, Smart PDF
Crafting ColdFusion Applications like an Architect
Security And Access Control For APIS using CF API Manager
Monetizing Business Models: ColdFusion and APIS
Become a Security Rockstar with ColdFusion 2016
ColdFusion in Transit action
Developer Insights for Application Upgrade to ColdFusion 2016
Where is cold fusion headed
ColdFusion Keynote: Building the Agile Web Since 1995
Instant ColdFusion with Vagrant
Restful services with ColdFusion
Super Fast Application development with Mura CMS
Build your own secure and real-time dashboard for mobile and web
Why Everyone else writes bad code
Securing applications
Testing automaton

Recently uploaded (20)

PPTX
Modernising the Digital Integration Hub
PDF
WOOl fibre morphology and structure.pdf for textiles
PPTX
Web Crawler for Trend Tracking Gen Z Insights.pptx
PDF
sustainability-14-14877-v2.pddhzftheheeeee
PPT
What is a Computer? Input Devices /output devices
PDF
Hybrid model detection and classification of lung cancer
PDF
Univ-Connecticut-ChatGPT-Presentaion.pdf
PDF
A review of recent deep learning applications in wood surface defect identifi...
PPTX
Tartificialntelligence_presentation.pptx
PDF
CloudStack 4.21: First Look Webinar slides
PPTX
observCloud-Native Containerability and monitoring.pptx
PDF
NewMind AI Weekly Chronicles – August ’25 Week III
PPTX
The various Industrial Revolutions .pptx
PPTX
MicrosoftCybserSecurityReferenceArchitecture-April-2025.pptx
PDF
Hybrid horned lizard optimization algorithm-aquila optimizer for DC motor
PPTX
Chapter 5: Probability Theory and Statistics
PDF
Unlock new opportunities with location data.pdf
PDF
DASA ADMISSION 2024_FirstRound_FirstRank_LastRank.pdf
PDF
Enhancing emotion recognition model for a student engagement use case through...
PDF
TrustArc Webinar - Click, Consent, Trust: Winning the Privacy Game
Modernising the Digital Integration Hub
WOOl fibre morphology and structure.pdf for textiles
Web Crawler for Trend Tracking Gen Z Insights.pptx
sustainability-14-14877-v2.pddhzftheheeeee
What is a Computer? Input Devices /output devices
Hybrid model detection and classification of lung cancer
Univ-Connecticut-ChatGPT-Presentaion.pdf
A review of recent deep learning applications in wood surface defect identifi...
Tartificialntelligence_presentation.pptx
CloudStack 4.21: First Look Webinar slides
observCloud-Native Containerability and monitoring.pptx
NewMind AI Weekly Chronicles – August ’25 Week III
The various Industrial Revolutions .pptx
MicrosoftCybserSecurityReferenceArchitecture-April-2025.pptx
Hybrid horned lizard optimization algorithm-aquila optimizer for DC motor
Chapter 5: Probability Theory and Statistics
Unlock new opportunities with location data.pdf
DASA ADMISSION 2024_FirstRound_FirstRank_LastRank.pdf
Enhancing emotion recognition model for a student engagement use case through...
TrustArc Webinar - Click, Consent, Trust: Winning the Privacy Game

Refactor Large applications with Backbone

  • 1. From Mess to Success, Refactoring Large Applications with Backbone dev.Objective() May 14, 2015 Stacy London @stacylondoner McWay Falls, Julia Pfeiffer Burns State Park - Big Sur, CA - 2015 by Stacy London
  • 2. About Me I’ve been making things for the web since 1998. Currently I’m a Senior Application Architect focused on Front-End Engineering at Northwestern Mutual. @stacylondoner
  • 3. Northwestern Mutual Northwestern Mutual has been helping families and businesses achieve financial security for nearly 160 years. Our financial representatives build relationships with clients through a distinctive planning approach that integrates risk management with wealth accumulation, preservation and distribution. With more than $230 billion in assets, $27 billion in revenues, nearly $90 billion in assets under management and more than $1.5 trillion worth of life insurance protection in force, Northwestern Mutual delivers financial security to more than 4.3 million people who rely on us for insurance and investment solutions, including life, disability and long-term care insurance; annuities; trust services; mutual funds; and investment advisory products and services. Northwestern Mutual is the marketing name for The Northwestern Mutual Life Insurance Company, Milwaukee, WI, and its subsidiaries. Northwestern Mutual and its subsidiaries offer a comprehensive approach to financial security solutions including: life insurance, long-term care insurance, disability income insurance, annuities, investment products, and advisory products and services. Subsidiaries include Northwestern Mutual Investment Services, LLC, broker-dealer, registered investment adviser, member FINRA and SIPC; the Northwestern Mutual Wealth Management Company, limited purpose federal savings bank; and Northwestern Long Term Care Insurance Company.
  • 4. What do I mean by large application? • a multi-page web application (MPA) built with ASP.NET MVC • 1500+ files | 343,000+ lines of code • UI (CSS / JS) • 230+ files | 42,000+ lines of code
  • 5. Development Culture • JEE/Java shop turned .NET/C# • view JS as a bit of a “toy” language • as JS was being added it was just being added without much thought to maintainability, extensibility, testability, patterns, etc. • app was going to be heavy with JS yet initially on a platform that wasn’t optimized for this kind of app dev. • path of least resistance was to just put everything in 
 $(document).ready()
  • 9. Problems • one large JavaScript file in the <head> (all code included on every page regardless if it needed it) • all JavaScript global and in $(document).ready() • some pages had inline JavaScript • not commented • no unit tests • unclear if a function / event was used on multiple pages
  • 10. Iterative Refactoring • big codebase • large team working on 2 week sprints that couldn’t be slowed down • refactors had to fit into a sprint
  • 13. Refactor, Iteration 1: Break Apart JS • figure out what JS belongs with each page and move that JS into a separate file for that page • include that JS with the partial HTML
  • 14. Refactor, Iteration 1: Start Adding Unit Tests • start adding unit tests for original code then make sure it passed after refactoring as a safety/confidence mechanism • to prepare for this journey of breaking code into smaller, more testable chunks it was good to start early with creating a test bed • help make subsequent refactors less stressful
  • 15. Refactor, Iteration 1: Start Adding Unit Tests • picked Jasmine (BDD style) - http:// jasmine.github.io/ • a lot of the JS tied to DOM manipulation so not in an ideal state for unit testing with Jasmine out of the box • needed DOM testing helper so added jquery- jasmine library to add fixtures (HTML snippets to run tests against) • no external UI Regression tools (e.g. Selenium) in a state to do this validation throughout the refactor
  • 18. Refactor, Iteration 2: Namespacing & Object Literal • create an app namespace to get custom code out of the global namespace (window) to avoid collisions with external libs/ frameworks • introduce an Object Literal notation style in preparation for Backbone (which uses this pattern) • helps to organize the code and parameters logically
 “an object containing a collection of key:value pairs with a colon separating each pair of keys and values where keys can also represent new namespaces” • add closures with Instantly Invoked Function Expressions (IIFEs)
  • 20. ; var myApp = myApp || {}; (function($, myApp) { 'use strict'; $.extend(myApp, { init: function() { this.commonStuff(); }, commonStuff: function() { // common code across many or all pages } }); })(window.jQuery, window.myApp); $(document).ready(function() { myApp.init(); }); my-app.js
  • 21. my-app.js with comments // prefix with semi-colon as safety net against concatenated // scripts and/or other plugins that are not closed properly ; // check for existence of myApp in the global namespace var myApp = myApp || {}; // Use IIFE to: // * encapsulate app logic to protect it from global namespace // * pass in namespace so can be modified locally and isn't // overwritten outside of our function context // * ensure $ only refers to window.jQuery (defensive programming) // * $ passed through as local var rather than as globals and this // (slightly) quickens the resolution process and can be more // efficiently minified (especially if regularly referenced) (function($, myApp) {
  • 22. my-app.js with comments (function($, myApp) { // Strict mode makes several changes to normal JavaScript semantics: // * eliminates some JS silent errors by changing them to throw errors. // * fixes mistakes that make it difficult for JavaScript engines to // perform optimizations: strict mode code can sometimes be made to // run faster than identical code that's not strict mode. Add inside // the IIFE so it's defined for just the functions defined within and // doesn't flip concatenating/minified code to strict inadvertently 'use strict'; // extend the namespace with more functionality $.extend(myApp, {
  • 23. ; var myApp = myApp || {}; myApp.pageOne = myApp.pageOne || {}; (function($, myApp) { 'use strict'; $.extend(myApp.pageOne, { init: function() { this.pageSpecificStuff(); }, pageSpecificStuff: function() { // code specific to this page } }); })(window.jQuery, window.myApp); $(document).ready(function() { myApp.pageOne.init(); }); page-one.js
  • 24. Better but not great • code is aligned with the screen to which is pertains • pages now have mid-page script includes which isn’t good for performance / rendering • still hand-wiring Ajax calls • entire-page-JS is not very modular • want to break screens down into smaller features and keep events neatly associated
  • 25. Backbone to the rescue • wanted something that provided/enforced structure but in a lightweight way • it’s a MPA not a SPA so full-featured SPA frameworks didn’t make sense (e.g. Angular, Ember) • wanted to be able to use just a small feature of the library/ framework and add more full integration over time (refactor in multiple iterations) • for these reasons Backbone.js made sense - http://backbonejs.org/
  • 27. Refactor, Iteration 3: Page Level Backbone Views • reducing boilerplate code • views enforce organization of events • views enforce an Object Literal notation pattern • views helped developers think about encapsulating pieces of the screen • starting with just Views gave the team time to start planning for refactoring back-end data provided by ASP.NET MVC Controllers into more RESTful web services (Web API) which is necessary to take full advantage of Backbone.js Models/Collections
  • 28. Refactor, Iteration 3: Page Level Backbone Views • my-app.js - is now responsible for instantiating the app namespace and setting up a super light-weight view manager for Backbone.js • instantiate all available views on the page upon DOM ready. • page-one-view.js - no longer namespaced individually since being added to the views object of the app namespace
  • 30. my-app.js var myApp = myApp || {}; (function($, myApp) { 'use strict'; $.extend(myApp, { init: function() { this.initializeViews(); }, // view manager code }); })(window.jQuery, window.myApp); $(document).ready(function() { myApp.init(); });
  • 31. my-app.js view manager views: {}, initializeViews: function() { for (var view in this.views) { if (typeof this.views[view] === 'function') { this.views[view.substring(0, 1).toLowerCase() + view.substring(1, view.length)] = new this.views[view](); } } }, addView: function(key, view) { if (this.views.hasOwnProperty(key)) { throw (new Error('A view with that key already exists.')); } this.views[key] = view; }, getView: function(key) { if (!this.views.hasOwnProperty(key)) { throw new Error('View does not exist in views collection.'); } return this.views[key]; }
  • 32. page-one-view.js; (function($, _, Backbone, myApp) { 'use strict'; var PageOneView = Backbone.View.extend({ el: '#pageOneMainContainer', events: { 'click .something': 'doSomething' }, initialize: function() { this.setupValidation(); }, setupValidation: function() { }, doSomething: function() { } }); myApp.addView('PageOneView', PageOneView); }(window.jQuery, window._, window.Backbone, window.myApp));
  • 34. Refactor, Iteration 4: Sub-Page Backbone Views • start breaking the large page views into sub-page views so that you can get truly modular • share modules/code if a module exists on more than one page
  • 37. Refactor, Iteration 5: Backbone Models, Collections • move code that is getting data and doing any business logic out of the Views and into Models and Collections • e.g. move phone number formatting out of View and into the Model • remove hand written Ajax, use BB API (e.g. fetch) • make sure server side controllers were written in a RESTful way • still not complete across the application
  • 39. var PageOneView = Backbone.View.extend({ el: '#pageOneMainContainer', initialize: function() { this.getSomeData(); }, getSomeData: function() { var self = this; $.ajax({ type: 'GET', url: 'SomeEndpoint', data: formData, dataType: 'json', success: function(data, textStatus, jqXHR) { self.displayResults(data); }, error: function(jqXHR, textStatus, errorThrown) { self.displayError(); } }); }, displayResults: function(data) { }, displayError: function() { } }); Hand-wiring Ajax
  • 40. Use Backbone.js API to get data // initialize view var pageOneView = new PageOneView({ collection: new PageOneCollection([]), }); var PageOneView = Backbone.View.extend({ el: '#pageOneMainContainer', template: _.template($('#page-one-template').html()), initialize: function() {}, render: function() { this.$el.html(this.template({'collection': this.collection})); // maintain chainability return this; } }); var PageOneCollection = Backbone.Collection.extend({ initialize: function(models, options) {}, model: PageOneModel, // RESTful web service URL url: '/SomeEndpoint' });
  • 42. Refactor, Iteration 6: Mini-SPA • treat each page of the multi-page app (MPA) like it’s a miniature single page app (SPA) • each page has a single entry point (main.js) • this will setup the code for a module loader / build system so that we can finally move the JS to the bottom of the page and remove mid-page scripts • improve performance (time to first paint - how long it takes between a user entering a URL into the browser and when he/she sees visual activity on screen)
  • 46. Refactor, Iteration 7: Modules • current version of JavaScript (ECMA-262) doesn’t provide a way to import modules of code like more traditional programming languages do • modules are proposed for the next version of JS (ES6/ ES2015/Harmony) • to use modules and manage dependencies with the current version of JS you can use community driven methodologies • there are two popular styles with associated script loaders / build systems
  • 48. Refactor, Iteration 7: Modules - AMD • AMD - Asynchronous Module Definition
 
 “The Asynchronous Module Definition (AMD) API specifies a mechanism for defining modules such that the module and its dependencies can be asynchronously loaded. This is particularly well suited for the browser environment where synchronous loading of modules incurs performance, usability, debugging, and cross- domain access problems.”
 https://github.com/amdjs/amdjs-api/wiki/AMD
  • 49. Refactor, Iteration 7: Modules - CommonJS • CommonJS’s module format was made popular for server-side JavaScript development (namely for Node.js/ NPM) • it’s synchronous • syntax is a bit easier as it frees you from the define() wrapper that AMD enforces • requires a build in a JS runtime
  • 50. Refactor, Iteration 7: Modules - RequireJS • popular script loader written by James Burke that helps you load multiple script files and define modules with or without dependencies • use RequireJS as first pass at module loading since async nature means no build step during dev time (least disruption to the dev team which is important because there is a learning curve) • use almond (AMD API shim) so don’t have to add a special script tag to load RequireJS and change any HTML • this will move the code away from IIFEs to modules with dependency management
  • 51. my-app.js // requireJS simplified commonJS wrapper // do this so can use the commonJS style & // make switch to browserify easier define('app', function(require, exports, module) { 'use strict'; var $ = require('jquery'); var _ = require('underscore'); var Backbone = require('backbone'); var Modernizr = require('modernizr'); var HeaderController = require('./header-controller'); var FooterController = require('./footer-controller'); var app = new Backbone.Application(); module.exports = app; }); (function() { var $ = require('jquery'); var app = require('app'); // dom ready $(function() { app.start(); }); }());
  • 52. ; (function() { 'use strict'; var $ = require('jquery'); var PageOneController = require('./page-one-controller'); var app = require('app'); // dom ready $(function() { app.start({ ScreenController: PageOneController }); }); }()); page-one-main.js
  • 53. define('page-one-controller', function(require, exports, module) { 'use strict'; var Backbone = require('backbone'); var PageOneView = require('PageOneView'); var PageOneController = Backbone.Controller.extend({ initialize: function(options) { var pageOneView = new PageOneView(); } }); module.exports = PageOneController; }); page-one-controller.js
  • 54. define('page-one-view', function(require, exports, module) { 'use strict'; var Backbone = require('backbone'); var PageOneView = Backbone.View.extend({ }); module.exports = PageOneView; }); page-one-view.js
  • 55. Refactor, Iteration 7: Modules - Browserify • Browserify lets you require('modules') in the browser by bundling up all of your dependencies during a build step • it’s the end-state module loader because it allows for easy bundle splitting • figure out common/shared JS and create a common bundle then a bundle for the unique code on each page • by having a main.js for each screen this will act as an entry point so Browserify can find all the modules required and create a screen-specific bundle
  • 56. Refactor, Iteration 7: Modules - Browserify • means build during dev but we were already doing that for our CSS with LESS • “It’s great the dev community has embraced compilation because it’s inevitable.” - Brendan Eich at Fluent 2015 • the code will become very clean
  • 57. 'use strict'; var Backbone = require('backbone'); var PageOneView = Backbone.View.extend({ el: '#pageOneMainContainer', initialize: function() {} }); module.exports = PageOneView; page-one-view.js
  • 58. Summary • the JavaScript is now modular and easier to maintain • Backbone.js helps devs keep consistent with coding patterns and organization (Object Literal notation, events) • events are scoped to the smallest part of the page to which they matter (Backbone.js) • namespacing/IIFEs and then later module loader/build removes the possibility of collisions with other frameworks/libs • unit tests mean you can feel more confident to change things • only sending JS to the browser that is necessary is good for performance (think mobile)
  • 60. "The secret to building large apps is never build large apps. Break your applications into small pieces. Then, assemble those testable, bite-sized pieces into your big application" - Justin Meyer, author JavaScriptMVC
  • 61. Team Shout Out • This was over the course of several years and I worked with two other fantastic front-end engineers: • Ryan Anklam ( @bittersweetryan ) • Zeek Chentnik ( http://ezekielchentnik.com )
  • 62. JavaScript References • “Patterns For Large-Scale JavaScript Application Architecture” by Addy Osmani 
 http://addyosmani.com/largescalejavascript/ • “Learning JavaScript Design Patterns” by Addy Osmani
 http://addyosmani.com/resources/essentialjsdesignpatterns/book/ • “Using Objects to Organize Your Code” by Rebecca Murphey
 http://rmurphey.com/blog/2009/10/15/using-objects-to-organize-your-code/ • “It’s time to start using JavaScript strict mode” by Nicholas Zakas
 http://www.nczonline.net/blog/2012/03/13/its-time-to-start-using-javascript-strict- mode/ • “Writing Modular JavaScript with AMD, CommonJS & ES Harmony” by Addy Osmani
 http://addyosmani.com/writing-modular-js/
  • 63. Backbone.js References • “Developing Backbone.js Applications” by Addy Osmani
 http://addyosmani.github.io/backbone-fundamentals/ • “Communicating Between Views in Client-Side Apps” by Rebecca Murphey
 http://bocoup.com/weblog/communicating-between- views-in-client-side-apps/ • Talks from past Backbone Conferences are free/online: http://backboneconf.com/
 http://backboneconf.com/2013/