2. Naresh Bhatia
CTO, Sapient Global Markets
Co-lead Visualization Practice
Experience
Trading and Risk Management applications using
JavaScript, Java and .NET
Founder Archfirst (http://archfirst.org)
A place for software developers to learn and compare
technologies through real world examples
15. Separate application state from
its presentation
Separate models from their views
Get the truth out of the DOM
16. MVC Philosophy – Get the truth out of the DOM
Doesn’t matter what flavor of MVC you are using
MVC, MVP, MVVM, MV*, MVWhatever
Models
Views
17. Introducing Backbone – A Lightweight MV* Framework
• Organize your interface into logical views backed by models
– Each view responsible for one DOM element
– Each view can be updated independently when the model changes
– Reduces DOM traversal, increasing performance
• See here for an example (slide 8)
• No need to dig into a JSON object, look up an element in the DOM, and
update the HTML by hand
– Bind your view's render function to the model's "change" event
– Now every view that displays this model is updated immediately on a change
19. Backbone Models
• Models are Backbone objects that contain “attributes”
• Whenever an attribute’s value changes, the model triggers a change event
// Define a model
var Tile = Backbone.Model.extend({
});
// Create an instance of the model
var tile = new Tile( );
// Set an attribute to fire the change event
tile.set({color: 0xF89F1B});
“change”
eventTile
color: F89F1B
20. Updating views from change events
tile
tileRectView
color: F89F1B
el:
model:
// 1. Create an instance of the model
var tile = new Tile( );
// 2. Create a view, attach it to the model & DOM
var tileRectView =
new TileRectView ({el: '#tile‘, model: tile});
// 3. (constructor) Bind view to model change event
this.model.on('change', this.render);
// 4. Change a model attribute
tile.set({color: 0xF89F1B});
// 5. Model fires a ‘change’ event
// 6. View catches the event & calls render( )
this.$el.css(
'background-color', '#' +
color2hex(this.model.get('color')));
1
2
render( )
4
‘change’
event
6
DOM
<div id="tile" ></div>
5
3
26. Classic Server-Side Layered Architecture
User Interface
Layer
Accepts user commands and presents
information back to the user
Application
Layer
Manages transactions, translates DTOs,
coordinates application activities, creates and
accesses domain objects
Domain
Layer
Contains the state and behavior of the domain
Infrastructure
Layer
Supports all other layers, includes repositories,
adapters, frameworks etc.
28. In-Application Messaging
• Interactions between table and chart
• If theses widgets interacted directly, the coupling would be too tight
• Use a message bus (a.k.a. pub/sub) to decouple the components
Account :
mouseover
30. How much of your application can
you hold in your head at once?
Bullsfirst is about 2000 lines of JS
31. Have you ever been in
Dependency Hell?
<script src="js/form2js.js"></script>
<script src="js/toObject.js"></script>
<script src="js/base64_encode.js"></script>
<script src="js/utf8_encode.js"></script>
<script src="js/format.js"></script>
<script src="js/treeTable.js"></script>
<script src="js/jalerts.js"></script>
32. AMD and RequireJS to the rescue
AMD: Asynchronous Module Definition
(an API for defining and loading JS modules)
RequireJS: A popular implementation of AMD
33. Modules allow you to break large
applications into bite-size chunks
Code reuse & separation of concerns
Complements the MVC pattern
35. Defining a Module
RequireJS loads all code relative to a baseUrl
(set to the same directory as the script used in a data-main)
// app/widgets/login/LoginWidget
// Defines a widget called LoginWidget
define(
[],
function() {
return BaseView.extend({
...
});
}
);
36. Using a Module
Defining dependency on a module makes sure that the
module is pulled in before the dependent code.
// app/pages/home/HomePage
// Defines the home page that uses the LoginWidget
define(
['app/widgets/login/LoginWidget'],
function(LoginWidget) {
return BaseView.extend({
postRender: function() {
this.addChild({
id: 'LoginWidget',
viewClass: LoginWidget,
parentElement: this.$el
});
}
...
});
}
);
38. Using templates defined in text modules
define(
['text!app/widgets/account-table/AccountTemplate.html'],
function(AccountTemplate) {
return BaseView.extend({
template: {
name: 'AccountTemplate',
source: AccountTemplate
},
...
});
}
);
AccountView.js
39. Optimizing for Production – The Build System
• A web application consisting of hundreds of JavaScript files could have
severe performance implications in a production environment
• RequireJS comes with an optimizer that walks the dependency tree and
concatenates all the required JavaScript files into one
• The Bullsfirst build system runs the RequireJS optimizer plus other
optimizations such as yuicompressor and uglifyjs to reduce the download
size of the application
– The build system is based on Grunt.js, a task-based command line build tool for
JavaScript projects
– It cuts down application load time to approximately 2 seconds on a 3 Mbps network
41. Summary
• Use the MVC pattern to enforce separation of concerns
• Compose your application using smaller Reusable Components
• Create a Domain Layer as a central place for views to access information
• Use In-Application Messaging to decouple application components
• Use Modules to break large applications into bite-size chunks
A strong architecture is key to building engaging web applications
43. References
• Backbone.js – https://github.com/documentcloud/backbone
• RequireJS – https://github.com/jrburke/requirejs
• Bullsfirst is an open-source project under http://archfirst.org
– Sharing best practices with the developer community
– Live demo at http://archfirst.org/apps/bullsfirst-jquery-backbone
– Source repository: https://github.com/archfirst/bullsfirst-jquery-backbone
– Discussion/feedback at http://archfirst.org/forums/general-discussion
43