JAZOON'13 - Pawel Wrzeszcz - Visibility Shift In Distributed Teams
Architecting non-trivial browser applications (Jazoon 2012)
-
Upload
marc-baechinger -
Category
Technology
-
view
1.805 -
download
0
Transcript of Architecting non-trivial browser applications (Jazoon 2012)
Architecting non-trivial browser applications
Marc BächingerZühlke Engineering AG1178
Wednesday, June 27, 12
2
a new paradigm of web application engineering
Wednesday, June 27, 12
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
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
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
2
Embrace complexityWednesday, June 27, 12
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
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
5
Architecture and design in browser applications
JavaScript applications needarchitecture and design
Wednesday, June 27, 12
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
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
2
MVC in JavaScript
Wednesday, June 27, 12
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
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
2MVC
Wednesday, June 27, 12
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
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
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
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
2MVC
Wednesday, June 27, 12
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
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
2
MVCWednesday, June 27, 12
2
Controllers - keeping things separated but together
Wednesday, June 27, 12
2
Controllers - keeping things separated but togethervar list = app.get("incidents");
Wednesday, June 27, 12
<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
<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
> 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
2
BIG BANG THEORY
Wednesday, June 27, 12
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
2
Birds view of an application
applicationModel
controller controllercontroller
view view view view
observe
observe
update
refresh
Wednesday, June 27, 12
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
2
Communication servicesWednesday, June 27, 12
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
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
@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
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
// 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
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
2
Untangled complexity
Wednesday, June 27, 12
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
/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
Just build it!http://addyosmani.github.com/todomvc/
Wednesday, June 27, 12
@marcbaechinger http://www.zuehlke.comZühlke Engineering AG [email protected]
Wednesday, June 27, 12
Backup slides
Marc BächingerZühlke Engineering AG1178
Wednesday, June 27, 12
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
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
5
Wednesday, June 27, 12
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
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
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
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
> 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
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
6
JAZOON COLOR SCHEME
> Primary colors
> Complementary colors
Wednesday, June 27, 12