1. Architecting non-trivial
browser applications
Marc Bächinger
Zühlke Engineering AG
1178
Wednesday, June 27, 12
2. a new paradigm of
web application engineering
2
Wednesday, June 27, 12
3. Modern web application paradigm
HTTP GET
text/html
Application
Webbrowser
server DB
GET/POST/PUT/DELETE
text/json
- request pages - serve page assets - CRUD
- display markup
- send form data - authentication
- authorization
- access remote services - access data storage
- access local data - enterprise integration
- provide services
- maintain user state
- process business logic
- process UI logic Frontend logic
- render markup tmpls
5
Wednesday, June 27, 12
4. Basic lifecycle of a modern HTML5 application
DOMContentLoaded
onload onbeforeunload onunload
UI setup
application use cases state synchronization
(augmentation)
GET /index.html HTTP/1.1
time
5
Wednesday, June 27, 12
5. Consequences of shift in architecture
> Better user experience/usability
> Unified REST API on the server side
> Increasing complexity on the client side
3
Wednesday, June 27, 12
7. Goals and advantages to achieve
> reusable and extendible software artifacts
> encapsulation and low coupling for flexibility
> components can quickly be (re-)assembled and combined
> applications and components which are easy to maintain
> separation of concerns to support testing parts in isolation
> sustainable and efficient development of complex JS applications
2
Wednesday, June 27, 12
8. Craftsmanship
> automated build for HTML applications
– JSLint/JSHint to assess code quality
– a unit test framework (e.g. quint, jasmine)
– W3C validators
– dependency resolving of JavaScript files
– transform and minimize JavaScript code
– CSS preprocessor (e.g. less, sass)
> use a version control system
– source code (html, js, json, css, assets)
– configuration management
> automated testing, continuous integration
5
Wednesday, June 27, 12
9. Architecture and design in browser applications
JavaScript applications need
architecture and design
5
Wednesday, June 27, 12
10. Observable pattern
– very simple but powerful pattern to tie objects together
– generic communication infrastructure
– low coupling between interacting entities
// bind a callback function to ‘add’ event
observable.bind("add", function(addedItem) {
// do something when called back
});
// emit an event to anonymous observers
AnObservable.prototype.addItem = function(item) {
this.items.push(item);
this.emit("add", item);
};
2
Wednesday, June 27, 12
11. Model-View-Controller
> a widely used pattern in UI development
> many derivates and “MVC-look-a-likes”
> Model
– defines data an application/component is about
– offers functions to manipulate model data
> View
– displays model data
Controller
– provides UI to edit the data
> Controller
– connect model and view
– listens for view events
Model View
– triggers model changes
– synchronizes model and view
2
Wednesday, June 27, 12
13. Technology stacks - All in one
application code business logic and plumping code
All-in-one framework extJS, SproutCore
Mobile or desktop browser FF, IE, Chrome, Safari, Opera
2
Wednesday, June 27, 12
14. Technology stacks - best of breed
application code business logic and plumping code
CSS Framework Twitter bootstrap, Zurb foundation
jQuery, zepto.js
Micros
libraries Backbone.js, Spine.js, Knockout.js
Browser MVC
and ember.js, JavaScriptMVC
facade framework
component
s
GMap, OSM, raphael, jQuery UI, Twitter
bootstrap.js, mustache, jade
Mobile or desktop browser FF, IE, Chrome, Safari, Opera
Wednesday, June 27, 12
16. A Model in JavaScript (pseudo code)
derive base functionality by an inheritance technique
1
var Person = function(spec) {
Model.call(this, spec);
};
Person.prototype = new Model();
create an instance and register callback to be called on change
2
var person = new Person({name: "Rui"});
person.bind("change", function(changedData, model) {
// do something
});
data changes trigger registered callbacks
3
person.set({ name: "Marc" });
2
Wednesday, June 27, 12
17. A Model with backbone.js
1
// derive constructor Person
var Person = Backbone.Model.extend({
setName: function(name) {
this.set({name: name});
}
});
2
// create an instance of Person
var person = new Person();
// listen for a change of the name field
person.on("change:name", function(model, name) {
$("#name").text(name);
});
3
var name = prompt("enter name");
person.setName(name);
2
Wednesday, June 27, 12
18. Collections of Models (Backbone.js)
1
var PersonList = Backbone.Collection.extend({
model: Person
});
2
var musicians = new PersonList();
musicians.on("add", function(person) {
console.log(person.get("name"), "added to musicians");
});
3
musicians.add([{
name: "Gnarls Barkley"
}]);
Wednesday, June 27, 12
19. Model wrap-up
> models represent the data of an application or component
> a model is observable
> ‘public API’ of a model is expressed by firing events to callbacks
> the model doesn’t know the DOM (can be tested outside the browser)
2
Wednesday, June 27, 12
21. Views in a browser application
> view technology of a browser
application is usually the
Document Object Model (DOM)
> convenient DOM access by using a
DOM facade (like jQuery)
> leveraging client side templates to
render views
> re-render templates of a component
on Model events
> using templates decouples DOM
structures from render logic
2
Wednesday, June 27, 12
22. Rendering views with a template library
Mustache template
<script id="incidents-tmpl" type="text/template">
<h3>Incidents</h3>
<ul>
{{#incidents}}
<li data-id="{{id}}" class="incident">
<span class="label>{{title}}</span></li>
</li>
{{/incidents}}
</ul>
</script>
Mustache engine
// get the template text from a script element
var template = $("#incidents-tmpl").text();
// render the template with data
var htmlMarkup = Mustache.render(template, model.get());
// insert output into DOM
$("#target").html(htmlMarkup); 2
Wednesday, June 27, 12
25. Controllers - keeping things separated but together
var list = app.get("incidents");
2
Wednesday, June 27, 12
26. Controllers - keeping things separated but together
var list = app.get("incidents");
<div id="incident-list"></div>
<script id="incident-list-tmpl">
<label>Incidents</label>
<ul>
{{#incidents}}
<li><label>{{title}}</label></li>
{{/incidents}}
</ul>
</script>
2
Wednesday, June 27, 12
27. Controllers - keeping things separated but together
var list = app.get("incidents");
<div id="incident-list"></div>
<script id="incident-list-tmpl">
<label>Incidents</label>
<ul>
{{#incidents}}
<li><label>{{title}}</label></li>
{{/incidents}}
</ul>
</script>
var listCtrl = new Controller({
id: "incident-list",
model: list
}); 2
Wednesday, June 27, 12
28. Controller tasks and lifecycle
setup > UI setup (augmentation)
• render template
• register model/UI callbacks
runtime > listen for UI events (user interaction)
• emit events/update model
> listen for model events
• connect model events to view rendering
clean up > unregister and destroy
2
Wednesday, June 27, 12
34. CRUD services using a REST API
> CRUD support (create, read, update, delete)
var PersistenceService = function(baseUrl) {
this.url = baseUrl;
return this;
};
PersistenceService.prototype.create = function(type, data, cb) {
};
PersistenceService.prototype.get = function(type, callback) {
};
PersistenceService.prototype.update = function(type, data, cb) {
};
PersistenceService.prototype.remove = function(type, id, cb) {
};
2
Wednesday, June 27, 12
35. Connect to a REST API with jQuery
PersistenceService.prototype.update(type, data, callback) {
$.ajax({
type: "PUT",
url: this.url + "/" + type + "/" + data.id,
data: JSON.stringify(data),
contentType: "application/json;charset=utf8",
dataType: "json",
success: function(respData) {
if (callback) {
callback(respData);
}
}
});
};
2
Wednesday, June 27, 12
36. JAX-RS on the server side
@Path("/address")
public class AddressService {
@PUT
@Produces("application/json")
@Consumes("application/json")
public Address update(Address address) {
// update address using JPA
return address;
}
@POST
@Produces("application/json")
@Consumes("application/json")
public Address create(Address address) {
// create address using JPA
return address;
}
// [...]
2
Wednesday, June 27, 12
37. Model events trigger service calls
ApplicationController.prototype.initPersistence = function() {
var service = new PersistenceService("/jaxrs");
this.addresses.bind("add", function(entry) {
service.create("address", entry, function() {
// async: handle response (error handling)
});
});
this.addresses.bind("remove", function(entry) {
service.remove("address", entry.id, function() {
// async: handle response (error handling)
});
});
};
2
Wednesday, June 27, 12
38. Using REST with Backbone.js
> built-in support for local persistence
> built-in support for remote persistence
// create a book
var book = new Backbone.Model({
title: "Structure and change in economic history",
author: "Douglass C. North"
});
book.save(); // triggers Backbone.sync("create", book);
> adapt to own REST style by overriding Backbone.sync
Backbone.sync = function(method, model) {
// adapt to your REST API
};
2
Wednesday, June 27, 12
39. Backbone.js/Spine.js REST protocol
> read ! GET /collection
> create ! POST /collection
> update ! PUT /collection/id
> destroy ! DELETE /collection/id
raw HTTP request of an address creation
POST /address HTTP/1.1
Host: localhost:3080
Origin: http://localhost:3080
Content-Length: 59
Content-Type: application/json
{"id":"E537616F-F5C3-4C2B-8537-7661C7AC101E","name":"Marc"}
2
Wednesday, June 27, 12
41. Components of a MVC browser application
create
application applicationModel
create observe/update
create/
use
use observe
controller view
controller controller view
controller
services controller view
use render
templateEngine
2
Wednesday, June 27, 12
42. Directory listing
/index.html
/main.js
/css/layout.css referenced in index.html
/css/application.css
/src/application.js
/src/application-model.js
dependency mgmt
/src/sidebar-controller.js
/src/email-editor-controller.js
reusable assets
/modules/model/model-collection.js
/modules/controller/controller.js
/modules/controller/list-controller.js dependency mgmt
/modules/service/persistence.js or
/modules/service/persistence-jaxrs.js 3-rd party library
/modules/service/routing.js
/modules/util.js
2
Wednesday, June 27, 12
43. Just build it!
http://addyosmani.github.com/todomvc/
Wednesday, June 27, 12
44. @marcbaechinger http://www.zuehlke.com
Zühlke Engineering AG bae@zuehlke.com
Wednesday, June 27, 12
45. Backup slides
Marc Bächinger
Zühlke Engineering AG
1178
Wednesday, June 27, 12
46. Traditional web application paradigm
GET/POST HTML
Presentation layer (eg. JSF)
Business layer (eg. Session bean, Spring beans)
Integration layer (eg. JPA, JAX-WS)
5
Wednesday, June 27, 12
47. Traditional web application paradigm
HTTP GET/POST Application SQL
Webbrowser
server DB
text/html
- request pages - serve page assets - CRUD
- display markup - (stored procedures)
- send form data - authentication
- authorization
- access data storage
- enterprise integration
- maintain user state
- process business logic
Frontend logic
- process UI logic
- render markup tplts
5
Wednesday, June 27, 12
49. REST service API paradigm
GET/POST/PUT/DELETE JSON
Remoting layer (eg. JAX-RS)
Service layer (eg. Session bean, Spring beans)
Integration layer (eg. JPA, JAX-WS)
5
Wednesday, June 27, 12
50. Consequences of shift in architecture
> Increased complexity on the client side
– complex life-cycle of an application
– multiple use cases without reloading the entire document
– maintain user and UI state
– call REST APIs
– render templates
– read from/write to local storage
– integration of 3rd-party components (dialogs, data tables, maps)
– support navigation (back button support)
> Unified REST API on the server side
– leveraging standard based HTTP verbs
– unifies backend infrastructure of browser and mobile OS
3
Wednesday, June 27, 12
51. Architecture and design in browser applications
> meet non functional requirements (-ilities)
– Extensibility
– Reusability
– Testability
– Maintainability
– Manageability
– ...
> provides a mental modal about how an application is designed to work
– intentional decomposition of a system into subsystems
– definition and description of relationships between entities
– may be documented
– always exists as an individual mental model of developers and architects
5
Wednesday, June 27, 12
52. A sample application model (pseudo code)
var applicationModel = new Model(),
inbox = new Collection(),
sentMails = new Collection();
// populate model properties
applicationModel.set(“inbox”, inbox);
applicationModel.set(“sentMails”, sentMails);
applicationModel.set(“selectedEmail”, inbox.get(0));
// register listeners
applicationModel.on(“change:selectedEmail”, function(email) {
renderMailView(email);
});
inbox.on(“add”, function() {
renderInboxList();
});
2
Wednesday, June 27, 12
53. Capturing user interaction
> efficient event handling by delegation
> capture bubbling events at the top element only
var controller = new Controller({
id: "incident-list",
"ui-events": {
"click ul li.incident": function (ev) {
// user selected a list entry
},
"click button.delete": function (ev) {
// user clicked delete button
}
}
});
2
Wednesday, June 27, 12
54. Spine.js controller
var ListController = Spine.Controller.sub({
events: {"click .incident": "click"}
click: function(event){
// use spines observable implementation
this.trigger("selected");
}
});
2
Wednesday, June 27, 12
55. JAZOON COLOR SCHEME
> Primary colors
> Complementary colors
6
Wednesday, June 27, 12