Building Web Applications
Laurynas Veržukauskas
@Im0rtality
2014
Javascript
- "just" Javascript
- jQueryUI Widgets
- + Templating
- + Databinding
- Frameworks
- AngularJS
Simple javascript
-
Writing
-
fast short-term solutions
- Debuging
-
easy (no library magic)
- Maintenance
- painful
- OOP
- in reality - none
- DOM manipulation
-
manual ->
fragile
jQueryUI widgets
-
Writing
- somewhat faster
- Debuging
- somewhat harder
- Maintenance
- better, but still bad-ish
- OOP
- objects
- DOM manipulation
- manual -> fragile
+ Templating (1/2)
Use templates to generate HTML
Still manual injection to DOM
- dust.js (by LinkedIn)
-
Hogan.js (by Twitter)
-
Mustache.js
- pure.js
- Handlebars.js
+ Templating (2/2)
-
Writing
- faster
- Debuging
- easier
- Maintenance
- even better
- OOP
- objects, views
- DOM manipulation
- semi-auto -> fragile
+ Databinding (1/3)
-
Ractive.js
- Rivets.js
- Epoxy.js (for Backbone)
- Knockout.js
No more DOM manipulation by hand!*

* - Unless we want it explicitly
+ Databinding (2/3)
-
Writing
- same
- Debuging
- easier
- Maintenance
- even better again
- OOP
- objects, views, models
- DOM manipulation
- auto -> NOT fragile
+Databinding (3/3)
Problems
- Philosophy is VERY different from jQuery
- view <-> data separation
- test driven development
- jQuery becomes obsolete
Frameworks (1/3)
Model-View-Whatever
Objects + Templating + Databinding
One package
- AngularJS (by Google)
-
Backbone
- Ember.js
Frameworks (2/3)
-
Writing
- faster (less boilerplate)
- Debuging
- easier (decoupled code)
- Maintenance
- easier (highly testable)
- OOP
- views, models, controllers, services
- DOM manipulation
- auto -> NOT fragile
Frameworks (3/3)
Problems
- Learning curve
- jQuery philosophy difference (inherits)
What to choose?
-
Backbone - DIY framework, lot of boilerplate
- Angular - structured, short, clean, mocks, DI, easiest start
- Ember - includes a LOT of utils, enforces specific structure
- Initial release back in 2009
- MV* framework
-
Huge community (StackOverflow 74k questions)
-
jQuery not even required
- Actively developed
- Clean code
- Testable
- IE 8+
How it came to be
- Miško Hevery's bet with manager
- Goole Feedback
- 17k LOC -> 3 weeks -> 1,5k LOC
Objectives
- Decoupling (DOM <-> Logic)
- Decoupling (Frontend <-> Backend)
- Testability
Built with
- Youtube on PS3 (by Google)
- Plunker
- VEVO
- DoubleClick (by Google)
- ...
index.html
<!doctype html><html lang="en" ng-app="myApp"><head><meta charset="utf-8"><title>My AngularJS App</title><link rel="stylesheet" href="css/app.css"/></head><body><ul class="menu"><li><a href="#/view1">view1</a></li><li><a href="#/view2">view2</a></li></ul><div ng-view></div><script src="lib/angular/angular.js"></script><script src="lib/angular/angular-route.js"></script><script src="js/app.js"></script><script src="js/controllers.js"></script></body></html>
app.js
'use strict';angular.module('myApp', ['ngRoute','myApp.controllers']).config(['$routeProvider', function($routeProvider) {$routeProvider.when('/view1', {templateUrl: 'partials/partial1.html',controller: 'MyCtrl1'}).when('/view2', {templateUrl: 'partials/partial2.html',controller: 'MyCtrl2'}).otherwise({redirectTo: '/view1'});}]);
controllers.js
'use strict';angular.module('myApp.controllers', [])
.controller('MyCtrl1', [function() {}]).controller('MyCtrl2', [function($scope) {$scope.messages = [{from: 'batman', body: 'nana nana nana nana batman!'},{from: 'joker', body: 'why so serious?'}];
}]);
partial1.html
<p>This is the partial for view 1.</p>
partial2.html
<p ng-repeat="message in messages">
{{ message.from }}: {{ message.body }}</p>
filters.js
'use strict';
angular.module('myApp.filters', []).filter('strlen', [function() {return function(text) {return String(text).length;}}]);
partial2.html
<p ng-repeat="message in messages">
{{ message.from }}:[ {{ message.body | strlen }} characters]
</p>
<p ng-repeat="message in messages">{{ message.from }}:[ {{ message.body | strlen }} characters]</p>
- Unit Testing
- Midway Testing
-
E2E Testing
filtersSpec.js
'use strict';describe('filter', function() {beforeEach(module('myApp.filters'));describe('strlen', function() {it('should get string length',inject(function(strlenFilter) {
expect(strlenFilter('nana')).toEqual(4);}));});});
scenarios.js
'use strict';describe('my app', function() {
browser.get('index.html');it('should automatically redirect to /view1 when location hash/fragment is empty', function() {
expect(browser.getLocationAbsUrl()).toMatch("/view1");});describe('view1', function() {beforeEach(function() {browser.get('index.html#/view1');});it('should render view1 when user navigates to /view1',
function() {expect(element.all(by.css('[ng-view] p')).first().getText()).toMatch(/partial for view 1/);});});
Gotchas
-
Organize your files
-
Lazy-load your code
-
Serialize application state to the URL
-
Derive application state from the URL
-
Manage a Model layer
-
Do smart caching
-
Work with a RESTful interface (for real)
- Use a 3rd-party lib with Angular
Resources
Questions?
Building Web Applications
By Laurynas Veržukauskas
Building Web Applications
- 627