Architecting non-trivial browser applications (Jazoon 2012)

55

Transcript of Architecting non-trivial browser applications (Jazoon 2012)

Page 1: Architecting non-trivial browser applications (Jazoon 2012)

Architecting non-trivial browser applications

Marc BächingerZühlke Engineering AG1178

Wednesday, June 27, 12

Page 2: Architecting non-trivial browser applications (Jazoon 2012)

2

a new paradigm of web application engineering

Wednesday, June 27, 12

Page 3: Architecting non-trivial browser applications (Jazoon 2012)

5

Modern web application paradigm

Webbrowser Applicationserver DB

- request pages- display markup- send form data

- access remote services- access local data

- maintain user state- process business logic- process UI logic- render markup tmpls

- serve page assets

- authentication- authorization- access data storage- enterprise integration

- provide services

- CRUD

GET/POST/PUT/DELETEtext/json

HTTP GETtext/html

Frontend logic

Wednesday, June 27, 12

Page 4: Architecting non-trivial browser applications (Jazoon 2012)

5

Basic lifecycle of a modern HTML5 application

UI setup(augmentation) application use cases state synchronization

GET /index.html HTTP/1.1

DOMContentLoaded

onload onbeforeunload onunload

time

Wednesday, June 27, 12

Page 5: Architecting non-trivial browser applications (Jazoon 2012)

3

Consequences of shift in architecture

> Better user experience/usability

> Unified REST API on the server side

> Increasing complexity on the client side

Wednesday, June 27, 12

Page 6: Architecting non-trivial browser applications (Jazoon 2012)

2

Embrace complexityWednesday, June 27, 12

Page 7: Architecting non-trivial browser applications (Jazoon 2012)

2

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

Wednesday, June 27, 12

Page 8: Architecting non-trivial browser applications (Jazoon 2012)

5

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

Wednesday, June 27, 12

Page 9: Architecting non-trivial browser applications (Jazoon 2012)

5

Architecture and design in browser applications

JavaScript applications needarchitecture and design

Wednesday, June 27, 12

Page 10: Architecting non-trivial browser applications (Jazoon 2012)

2

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);};

Wednesday, June 27, 12

Page 11: Architecting non-trivial browser applications (Jazoon 2012)

2

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– provides UI to edit the data

> Controller– connect model and view– listens for view events– triggers model changes– synchronizes model and view

Model View

Controller

Wednesday, June 27, 12

Page 12: Architecting non-trivial browser applications (Jazoon 2012)

2

MVC in JavaScript

Wednesday, June 27, 12

Page 13: Architecting non-trivial browser applications (Jazoon 2012)

2

Technology stacks - All in one

extJS, SproutCore

business logic and plumping code

All-in-one framework

application code

Mobile or desktop browser FF, IE, Chrome, Safari, Opera

Wednesday, June 27, 12

Page 14: Architecting non-trivial browser applications (Jazoon 2012)

Technology stacks - best of breed

CSS Framework

Browser facade

MVC framework

application code

Micros libraries

andcomponent

s

Twitter bootstrap, Zurb foundation

jQuery, zepto.js

Backbone.js, Spine.js, Knockout.jsember.js, JavaScriptMVC

GMap, OSM, raphael, jQuery UI, Twitter bootstrap.js, mustache, jade

business logic and plumping code

Mobile or desktop browser FF, IE, Chrome, Safari, Opera

Wednesday, June 27, 12

Page 15: Architecting non-trivial browser applications (Jazoon 2012)

2MVC

Wednesday, June 27, 12

Page 16: Architecting non-trivial browser applications (Jazoon 2012)

2

A Model in JavaScript (pseudo code)

var Person = function(spec) {

Model.call(this, spec);};

Person.prototype = new Model();

var person = new Person({name: "Rui"});

person.bind("change", function(changedData, model) { // do something

});

person.set({ name: "Marc" });

1

2

3

derive base functionality by an inheritance technique

create an instance and register callback to be called on change

data changes trigger registered callbacks

Wednesday, June 27, 12

Page 17: Architecting non-trivial browser applications (Jazoon 2012)

2

A Model with backbone.js

// derive constructor Person

var Person = Backbone.Model.extend({setName: function(name) {

this.set({name: name});}

});

1

// create an instance of Personvar person = new Person();

// listen for a change of the name fieldperson.on("change:name", function(model, name) { $("#name").text(name);});

var name = prompt("enter name");person.setName(name);

2

3

Wednesday, June 27, 12

Page 18: Architecting non-trivial browser applications (Jazoon 2012)

Collections of Models (Backbone.js)

var PersonList = Backbone.Collection.extend({ model: Person});

1

var musicians = new PersonList();

musicians.on("add", function(person) { console.log(person.get("name"), "added to musicians");});

2

musicians.add([{ name: "Gnarls Barkley"}]);

3

Wednesday, June 27, 12

Page 19: Architecting non-trivial browser applications (Jazoon 2012)

2

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)

Wednesday, June 27, 12

Page 20: Architecting non-trivial browser applications (Jazoon 2012)

2MVC

Wednesday, June 27, 12

Page 21: Architecting non-trivial browser applications (Jazoon 2012)

2

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

Wednesday, June 27, 12

Page 22: Architecting non-trivial browser applications (Jazoon 2012)

2

Rendering views with a template library

<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>

// get the template text from a script elementvar template = $("#incidents-tmpl").text();

// render the template with datavar htmlMarkup = Mustache.render(template, model.get());

// insert output into DOM$("#target").html(htmlMarkup);

Mustache template

Mustache engine

Wednesday, June 27, 12

Page 23: Architecting non-trivial browser applications (Jazoon 2012)

2

MVCWednesday, June 27, 12

Page 24: Architecting non-trivial browser applications (Jazoon 2012)

2

Controllers - keeping things separated but together

Wednesday, June 27, 12

Page 25: Architecting non-trivial browser applications (Jazoon 2012)

2

Controllers - keeping things separated but togethervar list = app.get("incidents");

Wednesday, June 27, 12

Page 26: Architecting non-trivial browser applications (Jazoon 2012)

<div id="incident-list"></div>

<script id="incident-list-tmpl"> <label>Incidents</label>

<ul>

{{#incidents}}

<li><label>{{title}}</label></li>

{{/incidents}}

</ul>

</script>

2

Controllers - keeping things separated but togethervar list = app.get("incidents");

Wednesday, June 27, 12

Page 27: Architecting non-trivial browser applications (Jazoon 2012)

<div id="incident-list"></div>

<script id="incident-list-tmpl"> <label>Incidents</label>

<ul>

{{#incidents}}

<li><label>{{title}}</label></li>

{{/incidents}}

</ul>

</script>

2

Controllers - keeping things separated but together

var listCtrl = new Controller({

id: "incident-list", model: list

});

var list = app.get("incidents");

Wednesday, June 27, 12

Page 28: Architecting non-trivial browser applications (Jazoon 2012)

> UI setup (augmentation)• render template • register model/UI callbacks

> listen for UI events (user interaction)• emit events/update model

> listen for model events• connect model events to view rendering

> unregister and destroy

2

Controller tasks and lifecycle

setup

runtime

clean up

Wednesday, June 27, 12

Page 29: Architecting non-trivial browser applications (Jazoon 2012)

2

BIG BANG THEORY

Wednesday, June 27, 12

Page 30: Architecting non-trivial browser applications (Jazoon 2012)

2

Application bootstrap and wiring

controller

application

controllerservice

applicationModel

controllercontrollercontroller

1

2 application services - persistence - routing (deep links) - public-subscribe - authentication

3 MV controllers - application logic - layout managers

application model

create

create

create

Wednesday, June 27, 12

Page 31: Architecting non-trivial browser applications (Jazoon 2012)

2

Birds view of an application

applicationModel

controller controllercontroller

view view view view

observe

observe

update

refresh

Wednesday, June 27, 12

Page 32: Architecting non-trivial browser applications (Jazoon 2012)

var applicationController = new Controller({

containerId: "body",

init: function() {this.model = new ApplicationModel("/rest/api");this.crudService = new PersistenceService(”/crud/”); this.controllers = [new SidebarController(model),new EmailEditorController(model, this.crudService),new ListController(model.get(“inbox”))

];},render: function() {$.each(this.controllers, function() {this.render(); // delegate rendering

});}[...]

}); 2

Wire up an application

Wednesday, June 27, 12

Page 33: Architecting non-trivial browser applications (Jazoon 2012)

2

Communication servicesWednesday, June 27, 12

Page 34: Architecting non-trivial browser applications (Jazoon 2012)

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

CRUD services using a REST API

> CRUD support (create, read, update, delete)

Wednesday, June 27, 12

Page 35: Architecting non-trivial browser applications (Jazoon 2012)

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

Connect to a REST API with jQuery

Wednesday, June 27, 12

Page 36: Architecting non-trivial browser applications (Jazoon 2012)

@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

JAX-RS on the server side

Wednesday, June 27, 12

Page 37: Architecting non-trivial browser applications (Jazoon 2012)

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

Model events trigger service calls

Wednesday, June 27, 12

Page 38: Architecting non-trivial browser applications (Jazoon 2012)

// create a bookvar book = new Backbone.Model({ title: "Structure and change in economic history", author: "Douglass C. North"});

book.save(); // triggers Backbone.sync("create", book);

2

Using REST with Backbone.js

> built-in support for local persistence> built-in support for remote persistence

Backbone.sync = function(method, model) { // adapt to your REST API};

> adapt to own REST style by overriding Backbone.sync

Wednesday, June 27, 12

Page 39: Architecting non-trivial browser applications (Jazoon 2012)

2

Backbone.js/Spine.js REST protocol

> read ! GET /collection> create ! POST /collection> update ! PUT /collection/id> destroy ! DELETE /collection/id

POST /address HTTP/1.1Host: localhost:3080Origin: http://localhost:3080Content-Length: 59Content-Type: application/json

{"id":"E537616F-F5C3-4C2B-8537-7661C7AC101E","name":"Marc"}

raw HTTP request of an address creation

Wednesday, June 27, 12

Page 40: Architecting non-trivial browser applications (Jazoon 2012)

2

Untangled complexity

Wednesday, June 27, 12

Page 41: Architecting non-trivial browser applications (Jazoon 2012)

2

Components of a MVC browser application

application

controllercontrollerservices

applicationModel

controllercontrollercontroller

templateEngine

viewviewview

create

create

use

create/use

observe/update

observe

renderuse

Wednesday, June 27, 12

Page 42: Architecting non-trivial browser applications (Jazoon 2012)

/index.html

/main.js/css/layout.css/css/application.css

/src/application.js /src/application-model.js/src/sidebar-controller.js/src/email-editor-controller.js

2

Directory listing

/modules/model/model-collection.js/modules/controller/controller.js/modules/controller/list-controller.js/modules/service/persistence.js/modules/service/persistence-jaxrs.js/modules/service/routing.js/modules/util.js

referenced in index.html

dependency mgmt

dependency mgmtor3-rd party library

reusable assets

Wednesday, June 27, 12

Page 43: Architecting non-trivial browser applications (Jazoon 2012)

Just build it!http://addyosmani.github.com/todomvc/

Wednesday, June 27, 12

Page 44: Architecting non-trivial browser applications (Jazoon 2012)

@marcbaechinger http://www.zuehlke.comZühlke Engineering AG [email protected]

Wednesday, June 27, 12

Page 45: Architecting non-trivial browser applications (Jazoon 2012)

Backup slides

Marc BächingerZühlke Engineering AG1178

Wednesday, June 27, 12

Page 46: Architecting non-trivial browser applications (Jazoon 2012)

5

Traditional web application paradigm

Presentation layer (eg. JSF)

Business layer (eg. Session bean, Spring beans)

Integration layer (eg. JPA, JAX-WS)

GET/POST HTML

Wednesday, June 27, 12

Page 47: Architecting non-trivial browser applications (Jazoon 2012)

5

Traditional web application paradigm

Webbrowser Applicationserver DB

- request pages- display markup- send form data

- serve page assets

- authentication- authorization- access data storage- enterprise integration

- maintain user state- process business logic- process UI logic- render markup tplts

- CRUD- (stored procedures)

HTTP GET/POST SQL

text/html

Frontend logic

Wednesday, June 27, 12

Page 48: Architecting non-trivial browser applications (Jazoon 2012)

5

Wednesday, June 27, 12

Page 49: Architecting non-trivial browser applications (Jazoon 2012)

5

REST service API paradigm

Remoting layer (eg. JAX-RS)

Service layer (eg. Session bean, Spring beans)

Integration layer (eg. JPA, JAX-WS)

GET/POST/PUT/DELETE JSON

Wednesday, June 27, 12

Page 50: Architecting non-trivial browser applications (Jazoon 2012)

3

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

Wednesday, June 27, 12

Page 51: Architecting non-trivial browser applications (Jazoon 2012)

5

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

Wednesday, June 27, 12

Page 52: Architecting non-trivial browser applications (Jazoon 2012)

2

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();

});

Wednesday, June 27, 12

Page 53: Architecting non-trivial browser applications (Jazoon 2012)

> 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

Capturing user interaction

Wednesday, June 27, 12

Page 54: Architecting non-trivial browser applications (Jazoon 2012)

var ListController = Spine.Controller.sub({ events: {"click .incident": "click"}

click: function(event){ // use spines observable implementation

this.trigger("selected"); }});

2

Spine.js controller

Wednesday, June 27, 12

Page 55: Architecting non-trivial browser applications (Jazoon 2012)

6

JAZOON COLOR SCHEME

> Primary colors

> Complementary colors

Wednesday, June 27, 12