SlideShare a Scribd company logo
WRITING
MAINTAINABLE
JAVASCRIPT
Yet Another Conference 2013

@jonbretman
jonbretman.co.uk

Mobile Web Developer @ Badoo
http://techblog.badoo.com
@BadooTech
 1"
2"
<!doctype html>!
<html>!
<head>!
<title>My Awesome App</title>!
<script src="App.js"></script>!
</head>!
<body>!
</body>!
</html>"
3"
4"
What is
maintainability?
5"
In engineering, maintainability is the ease with
which a product can be maintained in order
to...
h(p://en.wikipedia.org/wiki/Maintainability"
6"
In engineering, maintainability is the ease with
which a product can be maintained in order
to...
isolate defects or their cause
h(p://en.wikipedia.org/wiki/Maintainability"
7"
In engineering, maintainability is the ease with
which a product can be maintained in order
to...
correct defects or their cause
h(p://en.wikipedia.org/wiki/Maintainability"
8"
In engineering, maintainability is the ease with
which a product can be maintained in order
to...
prevent unexpected breakdowns
h(p://en.wikipedia.org/wiki/Maintainability"
9"
In engineering, maintainability is the ease with
which a product can be maintained in order
to...
make future maintenance easier
h(p://en.wikipedia.org/wiki/Maintainability"
10"
It's about making
our lives easier
11"
It's about making
our work pass the
test of time
12"
for(B=i=y=u=b=i=5-5,x=10,I=[],l=[];B++<304;I[B-1]=B%x?B/x%x<2|B%x<2?7:B/x&4?!
0:l[i++]="ECDFBDCEAAAAAAAAIIIIIIIIMKLNJLKM@G@TSb~?A6J57IKJT576,+-48HLSUmgukgg " +!
"OJNMLK IDHGFE".charCodeAt(y++)-64:7);function X(c,h,e,s){c^=8;for(var o,!
S,C,A,R,T,G,d=e&&X(c,0)>1e4,n,N=-1e8,O=20,K=78-h<<9;++O<99;)if((o=I[T=O])&&!
(G=o^c)<7){A=G--&2?8:4;C=o-9?l[61+G]:49;do if(!(R=I[T+=l[C]])&&!!G|A<3||!
(R+1^c)>9&&G|A>2){if(!(R-2&7))return K;n=G|(c?T>29:T<91)?o:6^c;S=!
(R&&l[R&7|32]*2-h-G)+(n-o?110:!G&&(A<2)+1);if(e>h||1<e&e==h&&S>2|d)!
{I[T]=n;I[O]=0;S-=X(c,h+1,e,S-N);if(!(h||e-1|B-O|T-b|S<-1e4))return W(),!
c&&setTimeout("X(8,0,2),X(8,0,1)",75);I[O]=o;I[T]=R}if(S>N||!h&S==N&&!
Math.random()<.5)if(N=S,e>1)if(h?s-S<0:(B=O,b=T,0))break}while(!R&G>2||(T=O,!
(G||A>2|(c?O>78:O<41)&!R)&&++C*--A))}return-K+768<N|d&&N}function W(){!
i="<table>";for(u=18;u<99;document.body.innerHTML=i+=++u%x-9?!
"<th width=60 height=60 onclick='I[b="+u+"]>8?W():X(0,0,1)'style='font-size:50px'bgcolor=#"!
+(u-B?u*.9&1||9:"d")+"0f0e0>&#"+(I[u]?9808+l[67+I[u]]:160):u++&&"<tr>")B=b}W()"
h(p://js1k.com/2010Efirst/demo/750"
13"
14"
•  Mobile Web Team - 4 developers
15"
•  Mobile Web Team - 4 developers
•  JavaScript, jsDoc, JSHint, Closure Compiler, JsTestDriver
16"
•  Mobile Web Team - 4 developers
•  JavaScript, jsDoc, JSHint, Closure Compiler, JsTestDriver
•  60,000+ lines of JavaScript
17"
•  Mobile Web Team - 4 developers
•  JavaScript, jsDoc, JSHint, Closure Compiler, JsTestDriver
•  60,000+ lines of JavaScript
•  ~500,000 daily active users
18"
•  Mobile Web Team - 4 developers
•  JavaScript, jsDoc, JSHint, Closure Compiler, JsTestDriver
•  60,000+ lines of JavaScript
•  ~500,000 daily active users
•  Code maintainability is key!
var topics = [!
'Type Checking',!
'Classes and Inheritance’,!
'Asynchronous Code',!
'Performance'!
];!
" 19"
topics.shift();!
"Type Checking"!
!
20"
<!doctype html>!
<html>!
<head>!
<title>My Awesome App</title>!
<script src="App.js"></script>!
</head>!
<body>!
</body>!
</html>"
21"
Api.get('/conversations', function (conversations) {!
!
var intros = conversations.map(function (c) {!
var name = c.theirName;!
var mostRecent = c.messages[0].text.substring(0, 30);!
return name + ': ' + mostRecent;!
});!
!
App.renderMessages(intros);!
!
});!
22"
Api.get('/conversations', function (conversations) {!
!
var intros = conversations.map(function (c) {!
var name = c.theirName;!
var mostRecent = c.messages[0].text.substring(0, 30);!
return name + ': ' + mostRecent;!
});!
!
App.renderMessages(intros);!
!
});!
23"
Api.get('/conversations', function (err, conversations) {!
!
var intros = conversations.map(function (c) {!
var name = c.theirName;!
var mostRecent = c.messages[0].text.substring(0, 30);!
return name + ': ' + mostRecent;!
});!
!
App.renderMessages(intros);!
!
});!
A lot of things have to go right here
24"
25"
Exceptions
if (data.value) {!
callback(data.value);!
}!
!
!
TypeError: Cannot read property 'value' of null!
!
!
!
!
" 26"
if (data && data.callback) {!
var result = data.callback();!
}!
!
!
TypeError: Property 'callback' of object #<Object>
is not a function"
"
27"
if (data && data.value) {!
var index = data.value.indexOf('something');!
}!
!
!
TypeError: Object #<Object> has no method ‘indexOf’
!
!
!
!
! 28"
typeof {};!
"object"!
!
typeof 'hello';!
"string"!
!
typeof 5;!
"number”!
typeof function () {};!
"function"!
!
typeof undefined;!
"undefined"!
!
typeof true;!
"boolean"!
! 29"
typeof [];!
"object"!
!
typeof null;!
"object"!
!
typeof new Date();!
"object"!
typeof /jsconf/;!
"object"!
!
typeof document.body;!
"object"!
!
typeof NaN;!
"number"!
! 30"
Object.prototype.toString()!
!
"
"
"
31"
Object.prototype.toString()!
!
"
"
"
32"
WHY?
•  If the this value is undefined, return "[object
Undefined]".!
!
33"
•  If the this value is undefined, return "[object
Undefined]".!
•  If the this value is null, return "[object Null]".!
!
34"
•  If the this value is undefined, return "[object
Undefined]".!
•  If the this value is null, return "[object Null]".!
•  Let class be the value of the [[Class]] property of this.
!
35"
•  If the this value is undefined, return "[object
Undefined]".!
•  If the this value is null, return "[object Null]".!
•  Let class be the value of the [[Class]] property of this.
•  Return the String value that is the result of concatenating
the three Strings "[object ", class, and "]".
36"
•  If the this value is undefined, return "[object
Undefined]".!
•  If the this value is null, return "[object Null]".!
•  Let class be the value of the [[Class]] property of this.
•  Return the String value that is the result of concatenating
the three Strings "[object ", class, and "]".
37"
Function.prototype.call()!
or!
Function.prototype.apply()!
var toString = Object.prototype.toString;!
var regex = /[object (.*?)]/;!
!
var type = function (o) {!
var match = toString.call(o).match(regex);!
return match[1].toLowerCase();!
};!
38"
var toString = Object.prototype.toString;!
var regex = /[object (.*?)]/;!
!
var type = function (o) {!
var match = toString.call(o).match(regex);!
return match[1].toLowerCase();!
};!
39"
this === o"
type({});!
"object"!
!
type('hello');!
"string"!
!
type(5);!
"number”!
type(function () {});!
"function"!
!
type(undefined);!
"undefined"!
!
type(true);!
"boolean"!
!
40"
type([]);!
"array"!
!
type(null);!
"null"!
!
type(new Date());!
"date"!
type(/jsconf/);!
"regex"!
!
type(document.body);!
"htmlbodyelement"!
!
type(NaN);!
"number"!
!
41"
type([]);!
"array"!
!
type(null);!
"null"!
!
type(new Date());!
"date"!
type(/jsconf/);!
"regex"!
!
type(document.body);!
"htmlbodyelement"!
!
type(NaN);!
"number"!
!
42"
???
var toString = Object.prototype.toString;!
var regex = /[object (.*?)]/;!
!
var type = function (o) {!
!
if (o && o.nodeType === 1) {!
return 'element';!
}!
!
var match = toString.call(o).match(regex);!
var _type = match[1].toLowerCase();!
!
if (_type === 'number' && isNaN(o)) {!
return 'nan';!
}!
!
return _type;!
};! 43"
var toString = Object.prototype.toString;!
var regex = /[object (.*?)]/;!
!
var type = function (o) {!
!
if (o && o.nodeType === 1) {!
return 'element';!
}!
!
var match = toString.call(o).match(regex);!
var _type = match[1].toLowerCase();!
!
if (_type === 'number' && isNaN(o)) {!
return 'nan';!
}!
!
return _type;!
};! 44"
Special case for DOM elements
var toString = Object.prototype.toString;!
var regex = /[object (.*?)]/;!
!
var type = function (o) {!
!
if (o && o.nodeType === 1) {!
return 'element';!
}!
!
var match = toString.call(o).match(regex);!
var _type = match[1].toLowerCase();!
!
if (_type === 'number' && isNaN(o)) {!
return 'nan';!
}!
!
return _type;!
};! 45"
Special case for NaN
46"
Now what?
Api.get('/conversations', function (conversations) {!
!
if (type(conversations) !== 'array') {!
App.renderMessages([]);!
return;!
}!
!
var intros = conversations.map(function (c) {!
!
if (type(c) !== 'object') {!
return '';!
}!
!
var name = type(c.theirName) === 'string' ? c.theirName : '';!
var mostRecent = '';!
!
if (type(c.messages) === 'array' ||!
type(c.messages[0]) === 'object' ||!
type(c.messages[0].text) === 'string') {!
mostRecent = c.messages[0].text.substring(0, 30);!
}!
!
return name + ': ' + mostRecent;!
});!
!
App.renderMessages(intros);!
!
});"
47"
Api.get("/conversations",function(e){var t=e.map(function(e){var
t=e.theirName;var n=e.messages[0].text.substring(0,30);return t+":
"+n});App.renderMessages(t)})!
!
!
!
!
!
!
!
!
!
Api.get("/conversations",function(e){if(type(e)!=="array")
{App.renderMessages([]);return}var t=e.map(function(e){if(type(e)!
=="object"){return""}var t=type(e.theirName)==="string"?
e.theirName:"";var n="";if(type(e.messages)==="array"||
type(e.messages[0])==="object"||type(e.messages[0].text)==="string")
{n=e.messages[0].text.substring(0,30)}return t+":
"+n});App.renderMessages(t)})"
+ 137%
48"
49"
How does this
help
maintainability?
50"
Prevents unexpected breakdowns
51"
Prevents unexpected breakdowns

Makes future maintenance easier
topics.shift();!
"Classes and Inheritance"!
!
52"
53"
Why classes?
54"
var Controller = {!
!
init: function () {!
// do some initialization!
},!
!
loadView: function () {!
!
}!
!
};!
!
// somewhere else in the app!
Controller.init();!
Controller.loadView();"
55"
var Controller = {!
!
init: function () {!
// do some initialization!
},!
!
loadView: function () {!
!
}!
!
};!
!
// somewhere else in the app!
Controller.init();!
Controller.loadView();"
Feels messy
56"
var ChatController = {};!
!
for (var key in Controller) {!
ChatController[key] = Controller;!
}!
!
ChatController.loadView = function () {!
!
Controller.loadView.apply(this, arguments);
// do some additional stuff!
!
};!
"
57"
var ChatController = {};!
!
for (var key in Controller) {!
ChatController[key] = Controller;!
}!
!
ChatController.loadView = function () {!
!
Controller.loadView.apply(this, arguments);
// do some additional stuff!
!
};!
"
Not proper inheritance
58"
What do we
want?
class Controller {!
!!
public Controller () {!
// do some initialization!
}!
!!
! public void loadView () {!
! !!
! }!
!
}!
!
class ChatController extends Controller {!
!!
! public void loadView () {!
! ! super.loadView();!
! ! // do some additional stuff!
! }!
!!
}" 59"
class Controller {!
!
constructor () {!
// do some initialization!
}!
!
loadView () {!
!
}!
!
}!
!
class ChatController extends Controller {!
!
loadView () {!
super.loadView();!
// do some additional stuff!
}!
!
}" 60"
class Controller!
!
constructor: () ->!
# do some initialization!
!
loadView: () ->!
!
!
class ChatController extends Controller!
!
loadView: () ->!
super!
# do some initialization"
61"
var ChatController, Controller, _ref,!
__hasProp = {}.hasOwnProperty,!
__extends = function(child, parent) {!
for (var key in parent) {!
if (__hasProp.call(parent, key))!
child[key] = parent[key];!
}!
function ctor() {!
this.constructor = child;!
}!
ctor.prototype = parent.prototype;!
child.prototype = new ctor();!
child.__super__ = parent.prototype;!
return child;!
};!
!
Controller = (function() {!
function Controller() {}!
Controller.prototype.loadView = function() {};!
return Controller;!
})();!
!
ChatController = (function(_super) {!
__extends(ChatController, _super);!
!
function ChatController() {!
_ref = ChatController.__super__.constructor.apply(this, arguments);!
return _ref;!
}!
!
ChatController.prototype.loadView = function() {!
return ChatController.__super__.loadView.apply(this, arguments);!
};!
!
return ChatController;!
})(Controller);" 62"
var ChatController, Controller, _ref,!
__hasProp = {}.hasOwnProperty,!
__extends = function(child, parent) {!
for (var key in parent) {!
if (__hasProp.call(parent, key))!
child[key] = parent[key];!
}!
function ctor() {!
this.constructor = child;!
}!
ctor.prototype = parent.prototype;!
child.prototype = new ctor();!
child.__super__ = parent.prototype;!
return child;!
};!
!
Controller = (function() {!
function Controller() {}!
Controller.prototype.loadView = function() {};!
return Controller;!
})();!
!
ChatController = (function(_super) {!
__extends(ChatController, _super);!
!
function ChatController() {!
_ref = ChatController.__super__.constructor.apply(this, arguments);!
return _ref;!
}!
!
ChatController.prototype.loadView = function() {!
return ChatController.__super__.loadView.apply(this, arguments);!
};!
!
return ChatController;!
})(Controller);" 63"
Utility method
var ChatController, Controller, _ref,!
__hasProp = {}.hasOwnProperty,!
__extends = function(child, parent) {!
for (var key in parent) {!
if (__hasProp.call(parent, key))!
child[key] = parent[key];!
}!
function ctor() {!
this.constructor = child;!
}!
ctor.prototype = parent.prototype;!
child.prototype = new ctor();!
child.__super__ = parent.prototype;!
return child;!
};!
!
Controller = (function() {!
function Controller() {}!
Controller.prototype.loadView = function() {};!
return Controller;!
})();!
!
ChatController = (function(_super) {!
__extends(ChatController, _super);!
!
function ChatController() {!
_ref = ChatController.__super__.constructor.apply(this, arguments);!
return _ref;!
}!
!
ChatController.prototype.loadView = function() {!
return ChatController.__super__.loadView.apply(this, arguments);!
};!
!
return ChatController;!
})(Controller);" 64"
Class Definitions
var Controller = function () {!
// do some initialization!
};!
!
Controller.prototype.loadView = function() {!
!
};!
!
var ChatController = function (name) {!
Controller.apply(this, arguments);!
};!
!
ChatController.prototype.loadView = function () {!
ChatController._super.loadView.apply(this, arguments);!
// do some additional stuff!
}!
!
extends(ChatController, Controller);"
65"
var Controller = function () {!
// do some initialization!
};!
!
Controller.prototype.loadView = function() {!
!
};!
!
var ChatController = function (name) {!
Controller.apply(this, arguments);!
};!
!
ChatController.prototype.loadView = function () {!
ChatController._super.loadView.apply(this, arguments);!
// do some additional stuff!
}!
!
extends(ChatController, Controller);"
66"
The magic bit
67"
There is no such
thing as magic.
var extends = function(child, parent) {!
for (var key in parent) {!
if (parent.hasOwnProperty(key)) {!
child[key] = parent[key];!
}!
}!
function ctor() { !
this.constructor = child; !
}!
ctor.prototype = parent.prototype;!
child.prototype = new ctor();!
child._super = parent.prototype;!
return child;!
};" 68"
var extends = function(child, parent) {!
for (var key in parent) {!
if (parent.hasOwnProperty(key)) {!
child[key] = parent[key];!
}!
}!
function ctor() { !
this.constructor = child; !
}!
ctor.prototype = parent.prototype;!
child.prototype = new ctor();!
child._super = parent.prototype;!
return child;!
};" 69"
Copy static properties / methods
var extends = function(child, parent) {!
for (var key in parent) {!
if (parent.hasOwnProperty(key)) {!
child[key] = parent[key];!
}!
}!
function ctor() { !
this.constructor = child; !
}!
ctor.prototype = parent.prototype;!
child.prototype = new ctor();!
child._super = parent.prototype;!
return child;!
};" 70"
Set up prototype chain
var extends = function(child, parent) {!
for (var key in parent) {!
if (parent.hasOwnProperty(key)) {!
child[key] = parent[key];!
}!
}!
!
!
ctor.prototype = Object.create(parent.prototype);!
!
!
child._super = parent.prototype;!
return child;!
};" 71"
ECMAScript 5
var extends = function(child, parent) {!
for (var key in parent) {!
if (parent.hasOwnProperty(key)) {!
child[key] = parent[key];!
}!
}!
function ctor() { !
this.constructor = child; !
}!
ctor.prototype = parent.prototype;!
child.prototype = new ctor();!
child._super = parent.prototype;!
return child;!
};" 72"
Add shorthand to super
var controller = new Controller();!
var chat = new ChatController();!
!
controller instanceof Controller; // true!
!
chat instanceof Controller; // true!
chat instanceof ChatController; // true"
73"
74"
The rest is about
good practice
Use getter and setter methods
alert(jon.name);!
jon.name = 'John';!
!
!
alert(jon.getName());!
jon.setName('John');!
jon.set('name', 'John');" 75"
Define all properties on the
prototype, even if they are null.

/**!
* The persons age.!
* @type {Number}!
*/!
Person.prototype.age = null;"
76"
Mark private methods with a
leading or trailing underscore

// somethings are best kept private :)!
Person.prototype._singInShower = function () {!
!
};"
77"
Use static methods / properties
Person.prototype.EVENTS = {!
WALK: 'WALK',!
TALK: 'TALK'!
};!
!
Person.EVENTS = {!
WALK: 'WALK',!
TALK: 'TALK'!
};"
78"
79"
How does this
help
maintainability?
80"
Correct defects or their causes
81"
Correct defects or their causes

Makes future maintenance easier
topics.shift();!
"Asynchronous Code"!
!
82"
83"
The big
question...
Callbacks 
or
Promises
 84"
Promises

•  Requires a library to provide the functionality
85"
Promises

•  Requires a library to provide the functionality
•  Different implementations
•  jQuery Deferred api.jquery.com/category/deferred-object/
•  rsvp.js github.com/tildeio/rsvp.js
•  when.js github.com/cujojs/when
•  promise.js github.com/then/promise
86"
Promises

•  Requires a library to provide the functionality
•  Different implementations
•  jQuery Deferred api.jquery.com/category/deferred-object/
•  rsvp.js github.com/tildeio/rsvp.js
•  when.js github.com/cujojs/when
•  promise.js github.com/then/promise
•  Kind of complicated…
87"
h(p://promisesEaplus.github.io/promisesEspec/"
88"
89"
TL;DR
90"
But that must
mean...
Callback
Hell 91"
92"
load: function () {!
!
Api.get('/profile/own', _.bind(function (ownProfile) {!
!
this.ownProfile = ownProfile;!
!
Api.get('/profile/' + id, _.bind(function (theirProfile) {!
!
this.theirProfile = theirProfile;!
!
Api.get('/chatMessages', _.bind(function (messages) {!
!
this.messages = messages;!
this.render();!
!
}, this), _.bind(function (err) {!
this.onError();!
}, this));!
}, this), _.bind(function (err) {!
this.onError();!
}, this));!
}, this), _.bind(function (err) {!
this.onError();!
}, this));!
}!
93"
load: function () {!
!
Api.get('/profile/own', _.bind(function (ownProfile) {!
!
this.ownProfile = ownProfile;!
!
Api.get('/profile/' + id, _.bind(function (theirProfile) {!
!
this.theirProfile = theirProfile;!
!
Api.get('/chatMessages', _.bind(function (messages) {!
!
this.messages = messages;!
this.render();!
!
}, this), _.bind(function (err) {!
this.onError();!
}, this));!
}, this), _.bind(function (err) {!
this.onError();!
}, this));!
}, this), _.bind(function (err) {!
this.onError();!
}, this));!
}!
94"
load: function () {!
!
Api.get('/profile/own', _.bind(function (ownProfile) {!
!
this.ownProfile = ownProfile;!
!
Api.get('/profile/' + id, _.bind(function (theirProfile) {!
!
this.theirProfile = theirProfile;!
!
Api.get('/chatMessages', _.bind(function (messages) {!
!
this.messages = messages;!
this.render();!
!
}, this), _.bind(function (err) {!
this.onError();!
}, this));!
}, this), _.bind(function (err) {!
this.onError();!
}, this));!
}, this), _.bind(function (err) {!
this.onError();!
}, this));!
}!
Action
Error Handling
95"
No.
“I’ve come to the conclusion
that callback hell is a design
choice and not an inherent flaw
in the concept of asynchronous
function and callback” 
http://blog.caplin.com/2013/03/13/callback-hell-is-a-design-choice/ 96"
doSomething(function (err, response) {!
!
});"
97"
98"
var handler = function (err, response) {!
!
};!
!
doSomething(handler);"
99"
!
load: function (id) {!
this.id = id;!
Api.get('/profile/own', this.onOwnProfile);!
},!
!
onOwnProfile: function (err, ownProfile) {!
if (err) return this.onError();!
this.ownProfile = ownProfile;!
Api.get('/profile/' + this.id, this.onTheirProfile);!
},!
!
onTheirProfile: function (err, theirProfile) {!
if (err) return this.onError();!
this.theirProfile = theirProfile;!
Api.get('/chatMessages', this.onMessages);!
},!
!
onMessages: function (err, messages) {!
if (err) return this.onError();!
this.messages = messages;!
this.render();!
}!
100"
!
load: function (id) {!
this.id = id;!
Api.get('/profile/own', this.onOwnProfile);!
},!
!
onOwnProfile: function (err, ownProfile) {!
if (err) return this.onError();!
this.ownProfile = ownProfile;!
Api.get('/profile/' + this.id, this.onTheirProfile);!
},!
!
onTheirProfile: function (err, theirProfile) {!
if (err) return this.onError();!
this.theirProfile = theirProfile;!
Api.get('/chatMessages', this.onMessages);!
},!
!
onMessages: function (err, messages) {!
if (err) return this.onError();!
this.messages = messages;!
this.render();!
}!
101"
!
load: function (id) {!
this.id = id;!
Api.get('/profile/own', this.onOwnProfile);!
},!
!
onOwnProfile: function (err, ownProfile) {!
if (err) return this.onError();!
this.ownProfile = ownProfile;!
Api.get('/profile/' + this.id, this.onTheirProfile);!
},!
!
onTheirProfile: function (err, theirProfile) {!
if (err) return this.onError();!
this.theirProfile = theirProfile;!
Api.get('/chatMessages', this.onMessages);!
},!
!
onMessages: function (err, messages) {!
if (err) return this.onError();!
this.messages = messages;!
this.render();!
}!
102"
!
load: function (id) {!
this.id = id;!
Api.get('/profile/own', this.onOwnProfile);!
},!
!
onOwnProfile: function (err, ownProfile) {!
if (err) return this.onError();!
this.ownProfile = ownProfile;!
Api.get('/profile/' + this.id, this.onTheirProfile);!
},!
!
onTheirProfile: function (err, theirProfile) {!
if (err) return this.onError();!
this.theirProfile = theirProfile;!
Api.get('/chatMessages', this.onMessages);!
},!
!
onMessages: function (err, messages) {!
if (err) return this.onError();!
this.messages = messages;!
this.render();!
}!
Reusable
Avoid anonymous functions
103"
Avoid anonymous functions
104"
Useless stack traces
Avoid anonymous functions
105"
Useless stack traces

Sign of poor structure
Keep things shallow

106"
Keep things shallow

107"
Means you are probably
using anonymous functions
Keep things shallow

108"
Means you are probably
using anonymous functions

Everyone will hate you
109"
How does this
help
maintainability?
110"
Isolate defects or their causes
111"
Isolate defects or their causes

Makes future maintenance easier
112"
Isolate defects or their causes

Makes future maintenance easier

Prevent unexpected breakdowns
topics.shift();!
"Performance"!
!
113"
var i = 0;!
var thing;!
for (; i < things.length; i++) {!
thing = things[i];!
}"
things.forEach(function (thing, i) {!
!
});"
114"
or…
115"
http://jsperf.com/foreachvsloop
24x faster
13x faster
13x Faster
350,000 operations per second
$('a').on('click', function (e) {!
!
});!
!
!
!
!
!
$('#container').on('click', 'a', function (e) {!
!
});"
or…
116"
117"
http://jsperf.com/domevents
21x faster
19x faster
21x Faster
Only 1000 operations per second
118"
$('#container').append('<ul></ul>');!
for (var i = 0; i < messages.length; i++) {!
$('#container')!
.find('ul')!
.append('<li>' + messages[i].text + '</li>');!
}"
!
!
!
!
var html = '<ul>';!
for (var i = 0; i < messages.length; i++) {!
html += '<li>' + messages[i].text + '</li>';!
}!
html += '</ul>';!
$('#container').html(html);!
or…
119"
http://jsperf.com/renderinghtml
48x Faster
44x faster
15x faster
Less than 200 operations per second!
DOM operations
120"
DOM operations

Iteration / function calls
121"
122"
Beware of
premature
optimizations
123"
Bottlenecks
var cache = {!
!
get: function (key) {!
return localStorage.getItem(key);!
},!
!
set: function (key, value) {!
localStorage.setItem(key, value);!
}!
!
};"
124"
var cache = {!
!
get: function (key) {!
return localStorage.getItem(key);!
},!
!
set: function (key, value) {!
localStorage.setItem(key, value);!
}!
!
};"
125"
Disc IO
var cache = {!
!
data_: {},!
!
get: function (key) {!
!
if (this.data_.hasOwnProperty(key)) {!
return this.data_[key];!
}!
!
var value = localStorage.getItem(key);!
!
if (value !== null) {!
this.data_[key] = value;!
return value;!
}!
!
return null;!
},!
set: function (key, value) {!
this.data_[key] = value;!
localStorage.setItem(key, value);!
}!
};"
126"
var cache = {!
!
data_: {},!
!
get: function (key) {!
!
if (this.data_.hasOwnProperty(key)) {!
return this.data_[key];!
}!
!
var value = localStorage.getItem(key);!
!
if (value !== null) {!
this.data_[key] = value;!
return value;!
}!
!
return null;!
},!
set: function (key, value) {!
this.data_[key] = value;!
localStorage.setItem(key, value);!
}!
};"
127"
Memory
var cache = {!
!
data_: {},!
!
get: function (key) {!
!
if (this.data_.hasOwnProperty(key)) {!
return this.data_[key];!
}!
!
var value = localStorage.getItem(key);!
!
if (value !== null) {!
this.data_[key] = value;!
return value;!
}!
!
return null;!
},!
set: function (key, value) {!
this.data_[key] = value;!
localStorage.setItem(key, value);!
}!
};"
128"
Quicker reading
var cache = {!
!
data_: {},!
!
get: function (key) {!
!
if (this.data_.hasOwnProperty(key)) {!
return this.data_[key];!
}!
!
var value = localStorage.getItem(key);!
!
if (value !== null) {!
this.data_[key] = value;!
return value;!
}!
!
return null;!
},!
set: function (key, value) {!
this.data_[key] = value;!
localStorage.setItem(key, value);!
}!
};"
129"
Saving for later
130"
http://jsperf.com/localstoragevsmemory
3x faster
About the same
131"
How does this
help
maintainability?
132"
Makes future maintenance easier
133"
Makes future maintenance easier

Prevent unexpected breakdowns
134"
topics.shift();!
undefined"
135"
What is
maintainability?
136"
It's about making
our lives easier
137"
It's about making
our work pass the
test of time
Thank you!
138"
Yet Another Conference 2013

@jonbretman
jonbretman.co.uk

Mobile Web Developer @ Badoo
http://techblog.badoo.com
@BadooTech

More Related Content

What's hot

What is systemd? Why use it? how does it work? - breizhcamp
What is systemd? Why use it? how does it work? - breizhcampWhat is systemd? Why use it? how does it work? - breizhcamp
What is systemd? Why use it? how does it work? - breizhcamp
Quentin Adam
 
What is systemd? Why use it? how does it work? - devoxx france 2017
What is systemd? Why use it? how does it work? - devoxx france 2017What is systemd? Why use it? how does it work? - devoxx france 2017
What is systemd? Why use it? how does it work? - devoxx france 2017
Quentin Adam
 
Java Script
Java ScriptJava Script
Active Record Form Helpers, Season 1
Active Record Form Helpers, Season 1Active Record Form Helpers, Season 1
Active Record Form Helpers, Season 1
RORLAB
 
Merb jQuery
Merb jQueryMerb jQuery
Merb jQuery
Yehuda Katz
 
JavaScript Needn't Hurt!
JavaScript Needn't Hurt!JavaScript Needn't Hurt!
JavaScript Needn't Hurt!
Thomas Kjeldahl Nilsson
 
Expoによるモバイルアプリ開発入門
Expoによるモバイルアプリ開発入門Expoによるモバイルアプリ開発入門
Expoによるモバイルアプリ開発入門
Takayuki Goto
 
Crafting Quality PHP Applications: an overview (PHPSW March 2018)
Crafting Quality PHP Applications: an overview (PHPSW March 2018)Crafting Quality PHP Applications: an overview (PHPSW March 2018)
Crafting Quality PHP Applications: an overview (PHPSW March 2018)
James Titcumb
 
jQuery Presentation to Rails Developers
jQuery Presentation to Rails DevelopersjQuery Presentation to Rails Developers
jQuery Presentation to Rails Developers
Yehuda Katz
 
Building Complex GUI Apps The Right Way. With Ample SDK - SWDC2010
Building Complex GUI Apps The Right Way. With Ample SDK - SWDC2010Building Complex GUI Apps The Right Way. With Ample SDK - SWDC2010
Building Complex GUI Apps The Right Way. With Ample SDK - SWDC2010
Sergey Ilinsky
 

What's hot (10)

What is systemd? Why use it? how does it work? - breizhcamp
What is systemd? Why use it? how does it work? - breizhcampWhat is systemd? Why use it? how does it work? - breizhcamp
What is systemd? Why use it? how does it work? - breizhcamp
 
What is systemd? Why use it? how does it work? - devoxx france 2017
What is systemd? Why use it? how does it work? - devoxx france 2017What is systemd? Why use it? how does it work? - devoxx france 2017
What is systemd? Why use it? how does it work? - devoxx france 2017
 
Java Script
Java ScriptJava Script
Java Script
 
Active Record Form Helpers, Season 1
Active Record Form Helpers, Season 1Active Record Form Helpers, Season 1
Active Record Form Helpers, Season 1
 
Merb jQuery
Merb jQueryMerb jQuery
Merb jQuery
 
JavaScript Needn't Hurt!
JavaScript Needn't Hurt!JavaScript Needn't Hurt!
JavaScript Needn't Hurt!
 
Expoによるモバイルアプリ開発入門
Expoによるモバイルアプリ開発入門Expoによるモバイルアプリ開発入門
Expoによるモバイルアプリ開発入門
 
Crafting Quality PHP Applications: an overview (PHPSW March 2018)
Crafting Quality PHP Applications: an overview (PHPSW March 2018)Crafting Quality PHP Applications: an overview (PHPSW March 2018)
Crafting Quality PHP Applications: an overview (PHPSW March 2018)
 
jQuery Presentation to Rails Developers
jQuery Presentation to Rails DevelopersjQuery Presentation to Rails Developers
jQuery Presentation to Rails Developers
 
Building Complex GUI Apps The Right Way. With Ample SDK - SWDC2010
Building Complex GUI Apps The Right Way. With Ample SDK - SWDC2010Building Complex GUI Apps The Right Way. With Ample SDK - SWDC2010
Building Complex GUI Apps The Right Way. With Ample SDK - SWDC2010
 

Similar to "Writing Maintainable JavaScript". Jon Bretman, Badoo

FrontInBahia 2014: 10 dicas de desempenho para apps mobile híbridas
FrontInBahia 2014: 10 dicas de desempenho para apps mobile híbridasFrontInBahia 2014: 10 dicas de desempenho para apps mobile híbridas
FrontInBahia 2014: 10 dicas de desempenho para apps mobile híbridas
Loiane Groner
 
"Javascript" por Tiago Rodrigues
"Javascript" por Tiago Rodrigues"Javascript" por Tiago Rodrigues
Serializing EMF models with Xtext
Serializing EMF models with XtextSerializing EMF models with Xtext
Serializing EMF models with Xtext
meysholdt
 
Es.next
Es.nextEs.next
Es.next
Ignacio Gil
 
RubyConf Portugal 2014 - Why ruby must go!
RubyConf Portugal 2014 - Why ruby must go!RubyConf Portugal 2014 - Why ruby must go!
RubyConf Portugal 2014 - Why ruby must go!
Gautam Rege
 
Javascript MVC & Backbone Tips & Tricks
Javascript MVC & Backbone Tips & TricksJavascript MVC & Backbone Tips & Tricks
Javascript MVC & Backbone Tips & Tricks
Hjörtur Hilmarsson
 
Maintainable JavaScript 2012
Maintainable JavaScript 2012Maintainable JavaScript 2012
Maintainable JavaScript 2012
Nicholas Zakas
 
Programming Paradigms Which One Is The Best?
Programming Paradigms Which One Is The Best?Programming Paradigms Which One Is The Best?
Programming Paradigms Which One Is The Best?
Netguru
 
Symfony + GraphQL
Symfony + GraphQLSymfony + GraphQL
Symfony + GraphQL
Alex Demchenko
 
Graphql + Symfony | Александр Демченко | CODEiD
Graphql + Symfony | Александр Демченко | CODEiDGraphql + Symfony | Александр Демченко | CODEiD
Graphql + Symfony | Александр Демченко | CODEiD
CODEiD PHP Community
 
Feed Normalization with Ember Data 1.0
Feed Normalization with Ember Data 1.0Feed Normalization with Ember Data 1.0
Feed Normalization with Ember Data 1.0
Jeremy Gillick
 
C# 6 and 7 and Futures 20180607
C# 6 and 7 and Futures 20180607C# 6 and 7 and Futures 20180607
C# 6 and 7 and Futures 20180607
Kevin Hazzard
 
Error Handling in Swift
Error Handling in SwiftError Handling in Swift
Error Handling in Swift
Make School
 
RubyMotion
RubyMotionRubyMotion
RubyMotion
Mark
 
Beyond MVC: from Model to Domain
Beyond MVC: from Model to DomainBeyond MVC: from Model to Domain
Beyond MVC: from Model to Domain
Jeremy Cook
 
Maintainable JavaScript 2011
Maintainable JavaScript 2011Maintainable JavaScript 2011
Maintainable JavaScript 2011
Nicholas Zakas
 
Ushahidi
UshahidiUshahidi
Ushahidi
bezrabotni
 
Turn your spaghetti code into ravioli with JavaScript modules
Turn your spaghetti code into ravioli with JavaScript modulesTurn your spaghetti code into ravioli with JavaScript modules
Turn your spaghetti code into ravioli with JavaScript modules
jerryorr
 
The go-start webframework (GTUG Vienna 27.03.2012)
The go-start webframework (GTUG Vienna 27.03.2012)The go-start webframework (GTUG Vienna 27.03.2012)
The go-start webframework (GTUG Vienna 27.03.2012)
ungerik
 
Getting Started with Microsoft Bot Framework
Getting Started with Microsoft Bot FrameworkGetting Started with Microsoft Bot Framework
Getting Started with Microsoft Bot Framework
Sarah Sexton
 

Similar to "Writing Maintainable JavaScript". Jon Bretman, Badoo (20)

FrontInBahia 2014: 10 dicas de desempenho para apps mobile híbridas
FrontInBahia 2014: 10 dicas de desempenho para apps mobile híbridasFrontInBahia 2014: 10 dicas de desempenho para apps mobile híbridas
FrontInBahia 2014: 10 dicas de desempenho para apps mobile híbridas
 
"Javascript" por Tiago Rodrigues
"Javascript" por Tiago Rodrigues"Javascript" por Tiago Rodrigues
"Javascript" por Tiago Rodrigues
 
Serializing EMF models with Xtext
Serializing EMF models with XtextSerializing EMF models with Xtext
Serializing EMF models with Xtext
 
Es.next
Es.nextEs.next
Es.next
 
RubyConf Portugal 2014 - Why ruby must go!
RubyConf Portugal 2014 - Why ruby must go!RubyConf Portugal 2014 - Why ruby must go!
RubyConf Portugal 2014 - Why ruby must go!
 
Javascript MVC & Backbone Tips & Tricks
Javascript MVC & Backbone Tips & TricksJavascript MVC & Backbone Tips & Tricks
Javascript MVC & Backbone Tips & Tricks
 
Maintainable JavaScript 2012
Maintainable JavaScript 2012Maintainable JavaScript 2012
Maintainable JavaScript 2012
 
Programming Paradigms Which One Is The Best?
Programming Paradigms Which One Is The Best?Programming Paradigms Which One Is The Best?
Programming Paradigms Which One Is The Best?
 
Symfony + GraphQL
Symfony + GraphQLSymfony + GraphQL
Symfony + GraphQL
 
Graphql + Symfony | Александр Демченко | CODEiD
Graphql + Symfony | Александр Демченко | CODEiDGraphql + Symfony | Александр Демченко | CODEiD
Graphql + Symfony | Александр Демченко | CODEiD
 
Feed Normalization with Ember Data 1.0
Feed Normalization with Ember Data 1.0Feed Normalization with Ember Data 1.0
Feed Normalization with Ember Data 1.0
 
C# 6 and 7 and Futures 20180607
C# 6 and 7 and Futures 20180607C# 6 and 7 and Futures 20180607
C# 6 and 7 and Futures 20180607
 
Error Handling in Swift
Error Handling in SwiftError Handling in Swift
Error Handling in Swift
 
RubyMotion
RubyMotionRubyMotion
RubyMotion
 
Beyond MVC: from Model to Domain
Beyond MVC: from Model to DomainBeyond MVC: from Model to Domain
Beyond MVC: from Model to Domain
 
Maintainable JavaScript 2011
Maintainable JavaScript 2011Maintainable JavaScript 2011
Maintainable JavaScript 2011
 
Ushahidi
UshahidiUshahidi
Ushahidi
 
Turn your spaghetti code into ravioli with JavaScript modules
Turn your spaghetti code into ravioli with JavaScript modulesTurn your spaghetti code into ravioli with JavaScript modules
Turn your spaghetti code into ravioli with JavaScript modules
 
The go-start webframework (GTUG Vienna 27.03.2012)
The go-start webframework (GTUG Vienna 27.03.2012)The go-start webframework (GTUG Vienna 27.03.2012)
The go-start webframework (GTUG Vienna 27.03.2012)
 
Getting Started with Microsoft Bot Framework
Getting Started with Microsoft Bot FrameworkGetting Started with Microsoft Bot Framework
Getting Started with Microsoft Bot Framework
 

More from Yandex

Предсказание оттока игроков из World of Tanks
Предсказание оттока игроков из World of TanksПредсказание оттока игроков из World of Tanks
Предсказание оттока игроков из World of Tanks
Yandex
 
Как принять/организовать работу по поисковой оптимизации сайта, Сергей Царик,...
Как принять/организовать работу по поисковой оптимизации сайта, Сергей Царик,...Как принять/организовать работу по поисковой оптимизации сайта, Сергей Царик,...
Как принять/организовать работу по поисковой оптимизации сайта, Сергей Царик,...
Yandex
 
Структурированные данные, Юлия Тихоход, лекция в Школе вебмастеров Яндекса
Структурированные данные, Юлия Тихоход, лекция в Школе вебмастеров ЯндексаСтруктурированные данные, Юлия Тихоход, лекция в Школе вебмастеров Яндекса
Структурированные данные, Юлия Тихоход, лекция в Школе вебмастеров Яндекса
Yandex
 
Представление сайта в поиске, Сергей Лысенко, лекция в Школе вебмастеров Яндекса
Представление сайта в поиске, Сергей Лысенко, лекция в Школе вебмастеров ЯндексаПредставление сайта в поиске, Сергей Лысенко, лекция в Школе вебмастеров Яндекса
Представление сайта в поиске, Сергей Лысенко, лекция в Школе вебмастеров Яндекса
Yandex
 
Плохие методы продвижения сайта, Екатерины Гладких, лекция в Школе вебмастеро...
Плохие методы продвижения сайта, Екатерины Гладких, лекция в Школе вебмастеро...Плохие методы продвижения сайта, Екатерины Гладких, лекция в Школе вебмастеро...
Плохие методы продвижения сайта, Екатерины Гладких, лекция в Школе вебмастеро...
Yandex
 
Основные принципы ранжирования, Сергей Царик и Антон Роменский, лекция в Школ...
Основные принципы ранжирования, Сергей Царик и Антон Роменский, лекция в Школ...Основные принципы ранжирования, Сергей Царик и Антон Роменский, лекция в Школ...
Основные принципы ранжирования, Сергей Царик и Антон Роменский, лекция в Школ...
Yandex
 
Основные принципы индексирования сайта, Александр Смирнов, лекция в Школе веб...
Основные принципы индексирования сайта, Александр Смирнов, лекция в Школе веб...Основные принципы индексирования сайта, Александр Смирнов, лекция в Школе веб...
Основные принципы индексирования сайта, Александр Смирнов, лекция в Школе веб...
Yandex
 
Мобильное приложение: как и зачем, Александр Лукин, лекция в Школе вебмастеро...
Мобильное приложение: как и зачем, Александр Лукин, лекция в Школе вебмастеро...Мобильное приложение: как и зачем, Александр Лукин, лекция в Школе вебмастеро...
Мобильное приложение: как и зачем, Александр Лукин, лекция в Школе вебмастеро...
Yandex
 
Сайты на мобильных устройствах, Олег Ножичкин, лекция в Школе вебмастеров Янд...
Сайты на мобильных устройствах, Олег Ножичкин, лекция в Школе вебмастеров Янд...Сайты на мобильных устройствах, Олег Ножичкин, лекция в Школе вебмастеров Янд...
Сайты на мобильных устройствах, Олег Ножичкин, лекция в Школе вебмастеров Янд...
Yandex
 
Качественная аналитика сайта, Юрий Батиевский, лекция в Школе вебмастеров Янд...
Качественная аналитика сайта, Юрий Батиевский, лекция в Школе вебмастеров Янд...Качественная аналитика сайта, Юрий Батиевский, лекция в Школе вебмастеров Янд...
Качественная аналитика сайта, Юрий Батиевский, лекция в Школе вебмастеров Янд...
Yandex
 
Что можно и что нужно измерять на сайте, Петр Аброськин, лекция в Школе вебма...
Что можно и что нужно измерять на сайте, Петр Аброськин, лекция в Школе вебма...Что можно и что нужно измерять на сайте, Петр Аброськин, лекция в Школе вебма...
Что можно и что нужно измерять на сайте, Петр Аброськин, лекция в Школе вебма...
Yandex
 
Как правильно поставить ТЗ на создание сайта, Алексей Бородкин, лекция в Школ...
Как правильно поставить ТЗ на создание сайта, Алексей Бородкин, лекция в Школ...Как правильно поставить ТЗ на создание сайта, Алексей Бородкин, лекция в Школ...
Как правильно поставить ТЗ на создание сайта, Алексей Бородкин, лекция в Школ...
Yandex
 
Как защитить свой сайт, Пётр Волков, лекция в Школе вебмастеров
Как защитить свой сайт, Пётр Волков, лекция в Школе вебмастеровКак защитить свой сайт, Пётр Волков, лекция в Школе вебмастеров
Как защитить свой сайт, Пётр Волков, лекция в Школе вебмастеров
Yandex
 
Как правильно составить структуру сайта, Дмитрий Сатин, лекция в Школе вебмас...
Как правильно составить структуру сайта, Дмитрий Сатин, лекция в Школе вебмас...Как правильно составить структуру сайта, Дмитрий Сатин, лекция в Школе вебмас...
Как правильно составить структуру сайта, Дмитрий Сатин, лекция в Школе вебмас...
Yandex
 
Технические особенности создания сайта, Дмитрий Васильева, лекция в Школе веб...
Технические особенности создания сайта, Дмитрий Васильева, лекция в Школе веб...Технические особенности создания сайта, Дмитрий Васильева, лекция в Школе веб...
Технические особенности создания сайта, Дмитрий Васильева, лекция в Школе веб...
Yandex
 
Конструкторы для отдельных элементов сайта, Елена Першина, лекция в Школе веб...
Конструкторы для отдельных элементов сайта, Елена Першина, лекция в Школе веб...Конструкторы для отдельных элементов сайта, Елена Першина, лекция в Школе веб...
Конструкторы для отдельных элементов сайта, Елена Першина, лекция в Школе веб...
Yandex
 
Контент для интернет-магазинов, Катерина Ерошина, лекция в Школе вебмастеров ...
Контент для интернет-магазинов, Катерина Ерошина, лекция в Школе вебмастеров ...Контент для интернет-магазинов, Катерина Ерошина, лекция в Школе вебмастеров ...
Контент для интернет-магазинов, Катерина Ерошина, лекция в Школе вебмастеров ...
Yandex
 
Как написать хороший текст для сайта, Катерина Ерошина, лекция в Школе вебмас...
Как написать хороший текст для сайта, Катерина Ерошина, лекция в Школе вебмас...Как написать хороший текст для сайта, Катерина Ерошина, лекция в Школе вебмас...
Как написать хороший текст для сайта, Катерина Ерошина, лекция в Школе вебмас...
Yandex
 
Usability и дизайн - как не помешать пользователю, Алексей Иванов, лекция в Ш...
Usability и дизайн - как не помешать пользователю, Алексей Иванов, лекция в Ш...Usability и дизайн - как не помешать пользователю, Алексей Иванов, лекция в Ш...
Usability и дизайн - как не помешать пользователю, Алексей Иванов, лекция в Ш...
Yandex
 
Cайт. Зачем он и каким должен быть, Алексей Иванов, лекция в Школе вебмастеро...
Cайт. Зачем он и каким должен быть, Алексей Иванов, лекция в Школе вебмастеро...Cайт. Зачем он и каким должен быть, Алексей Иванов, лекция в Школе вебмастеро...
Cайт. Зачем он и каким должен быть, Алексей Иванов, лекция в Школе вебмастеро...
Yandex
 

More from Yandex (20)

Предсказание оттока игроков из World of Tanks
Предсказание оттока игроков из World of TanksПредсказание оттока игроков из World of Tanks
Предсказание оттока игроков из World of Tanks
 
Как принять/организовать работу по поисковой оптимизации сайта, Сергей Царик,...
Как принять/организовать работу по поисковой оптимизации сайта, Сергей Царик,...Как принять/организовать работу по поисковой оптимизации сайта, Сергей Царик,...
Как принять/организовать работу по поисковой оптимизации сайта, Сергей Царик,...
 
Структурированные данные, Юлия Тихоход, лекция в Школе вебмастеров Яндекса
Структурированные данные, Юлия Тихоход, лекция в Школе вебмастеров ЯндексаСтруктурированные данные, Юлия Тихоход, лекция в Школе вебмастеров Яндекса
Структурированные данные, Юлия Тихоход, лекция в Школе вебмастеров Яндекса
 
Представление сайта в поиске, Сергей Лысенко, лекция в Школе вебмастеров Яндекса
Представление сайта в поиске, Сергей Лысенко, лекция в Школе вебмастеров ЯндексаПредставление сайта в поиске, Сергей Лысенко, лекция в Школе вебмастеров Яндекса
Представление сайта в поиске, Сергей Лысенко, лекция в Школе вебмастеров Яндекса
 
Плохие методы продвижения сайта, Екатерины Гладких, лекция в Школе вебмастеро...
Плохие методы продвижения сайта, Екатерины Гладких, лекция в Школе вебмастеро...Плохие методы продвижения сайта, Екатерины Гладких, лекция в Школе вебмастеро...
Плохие методы продвижения сайта, Екатерины Гладких, лекция в Школе вебмастеро...
 
Основные принципы ранжирования, Сергей Царик и Антон Роменский, лекция в Школ...
Основные принципы ранжирования, Сергей Царик и Антон Роменский, лекция в Школ...Основные принципы ранжирования, Сергей Царик и Антон Роменский, лекция в Школ...
Основные принципы ранжирования, Сергей Царик и Антон Роменский, лекция в Школ...
 
Основные принципы индексирования сайта, Александр Смирнов, лекция в Школе веб...
Основные принципы индексирования сайта, Александр Смирнов, лекция в Школе веб...Основные принципы индексирования сайта, Александр Смирнов, лекция в Школе веб...
Основные принципы индексирования сайта, Александр Смирнов, лекция в Школе веб...
 
Мобильное приложение: как и зачем, Александр Лукин, лекция в Школе вебмастеро...
Мобильное приложение: как и зачем, Александр Лукин, лекция в Школе вебмастеро...Мобильное приложение: как и зачем, Александр Лукин, лекция в Школе вебмастеро...
Мобильное приложение: как и зачем, Александр Лукин, лекция в Школе вебмастеро...
 
Сайты на мобильных устройствах, Олег Ножичкин, лекция в Школе вебмастеров Янд...
Сайты на мобильных устройствах, Олег Ножичкин, лекция в Школе вебмастеров Янд...Сайты на мобильных устройствах, Олег Ножичкин, лекция в Школе вебмастеров Янд...
Сайты на мобильных устройствах, Олег Ножичкин, лекция в Школе вебмастеров Янд...
 
Качественная аналитика сайта, Юрий Батиевский, лекция в Школе вебмастеров Янд...
Качественная аналитика сайта, Юрий Батиевский, лекция в Школе вебмастеров Янд...Качественная аналитика сайта, Юрий Батиевский, лекция в Школе вебмастеров Янд...
Качественная аналитика сайта, Юрий Батиевский, лекция в Школе вебмастеров Янд...
 
Что можно и что нужно измерять на сайте, Петр Аброськин, лекция в Школе вебма...
Что можно и что нужно измерять на сайте, Петр Аброськин, лекция в Школе вебма...Что можно и что нужно измерять на сайте, Петр Аброськин, лекция в Школе вебма...
Что можно и что нужно измерять на сайте, Петр Аброськин, лекция в Школе вебма...
 
Как правильно поставить ТЗ на создание сайта, Алексей Бородкин, лекция в Школ...
Как правильно поставить ТЗ на создание сайта, Алексей Бородкин, лекция в Школ...Как правильно поставить ТЗ на создание сайта, Алексей Бородкин, лекция в Школ...
Как правильно поставить ТЗ на создание сайта, Алексей Бородкин, лекция в Школ...
 
Как защитить свой сайт, Пётр Волков, лекция в Школе вебмастеров
Как защитить свой сайт, Пётр Волков, лекция в Школе вебмастеровКак защитить свой сайт, Пётр Волков, лекция в Школе вебмастеров
Как защитить свой сайт, Пётр Волков, лекция в Школе вебмастеров
 
Как правильно составить структуру сайта, Дмитрий Сатин, лекция в Школе вебмас...
Как правильно составить структуру сайта, Дмитрий Сатин, лекция в Школе вебмас...Как правильно составить структуру сайта, Дмитрий Сатин, лекция в Школе вебмас...
Как правильно составить структуру сайта, Дмитрий Сатин, лекция в Школе вебмас...
 
Технические особенности создания сайта, Дмитрий Васильева, лекция в Школе веб...
Технические особенности создания сайта, Дмитрий Васильева, лекция в Школе веб...Технические особенности создания сайта, Дмитрий Васильева, лекция в Школе веб...
Технические особенности создания сайта, Дмитрий Васильева, лекция в Школе веб...
 
Конструкторы для отдельных элементов сайта, Елена Першина, лекция в Школе веб...
Конструкторы для отдельных элементов сайта, Елена Першина, лекция в Школе веб...Конструкторы для отдельных элементов сайта, Елена Першина, лекция в Школе веб...
Конструкторы для отдельных элементов сайта, Елена Першина, лекция в Школе веб...
 
Контент для интернет-магазинов, Катерина Ерошина, лекция в Школе вебмастеров ...
Контент для интернет-магазинов, Катерина Ерошина, лекция в Школе вебмастеров ...Контент для интернет-магазинов, Катерина Ерошина, лекция в Школе вебмастеров ...
Контент для интернет-магазинов, Катерина Ерошина, лекция в Школе вебмастеров ...
 
Как написать хороший текст для сайта, Катерина Ерошина, лекция в Школе вебмас...
Как написать хороший текст для сайта, Катерина Ерошина, лекция в Школе вебмас...Как написать хороший текст для сайта, Катерина Ерошина, лекция в Школе вебмас...
Как написать хороший текст для сайта, Катерина Ерошина, лекция в Школе вебмас...
 
Usability и дизайн - как не помешать пользователю, Алексей Иванов, лекция в Ш...
Usability и дизайн - как не помешать пользователю, Алексей Иванов, лекция в Ш...Usability и дизайн - как не помешать пользователю, Алексей Иванов, лекция в Ш...
Usability и дизайн - как не помешать пользователю, Алексей Иванов, лекция в Ш...
 
Cайт. Зачем он и каким должен быть, Алексей Иванов, лекция в Школе вебмастеро...
Cайт. Зачем он и каким должен быть, Алексей Иванов, лекция в Школе вебмастеро...Cайт. Зачем он и каким должен быть, Алексей Иванов, лекция в Школе вебмастеро...
Cайт. Зачем он и каким должен быть, Алексей Иванов, лекция в Школе вебмастеро...
 

Recently uploaded

5th LF Energy Power Grid Model Meet-up Slides
5th LF Energy Power Grid Model Meet-up Slides5th LF Energy Power Grid Model Meet-up Slides
5th LF Energy Power Grid Model Meet-up Slides
DanBrown980551
 
Webinar: Designing a schema for a Data Warehouse
Webinar: Designing a schema for a Data WarehouseWebinar: Designing a schema for a Data Warehouse
Webinar: Designing a schema for a Data Warehouse
Federico Razzoli
 
20240607 QFM018 Elixir Reading List May 2024
20240607 QFM018 Elixir Reading List May 202420240607 QFM018 Elixir Reading List May 2024
20240607 QFM018 Elixir Reading List May 2024
Matthew Sinclair
 
20240609 QFM020 Irresponsible AI Reading List May 2024
20240609 QFM020 Irresponsible AI Reading List May 202420240609 QFM020 Irresponsible AI Reading List May 2024
20240609 QFM020 Irresponsible AI Reading List May 2024
Matthew Sinclair
 
UiPath Test Automation using UiPath Test Suite series, part 6
UiPath Test Automation using UiPath Test Suite series, part 6UiPath Test Automation using UiPath Test Suite series, part 6
UiPath Test Automation using UiPath Test Suite series, part 6
DianaGray10
 
Unlock the Future of Search with MongoDB Atlas_ Vector Search Unleashed.pdf
Unlock the Future of Search with MongoDB Atlas_ Vector Search Unleashed.pdfUnlock the Future of Search with MongoDB Atlas_ Vector Search Unleashed.pdf
Unlock the Future of Search with MongoDB Atlas_ Vector Search Unleashed.pdf
Malak Abu Hammad
 
みなさんこんにちはこれ何文字まで入るの?40文字以下不可とか本当に意味わからないけどこれ限界文字数書いてないからマジでやばい文字数いけるんじゃないの?えこ...
みなさんこんにちはこれ何文字まで入るの?40文字以下不可とか本当に意味わからないけどこれ限界文字数書いてないからマジでやばい文字数いけるんじゃないの?えこ...みなさんこんにちはこれ何文字まで入るの?40文字以下不可とか本当に意味わからないけどこれ限界文字数書いてないからマジでやばい文字数いけるんじゃないの?えこ...
みなさんこんにちはこれ何文字まで入るの?40文字以下不可とか本当に意味わからないけどこれ限界文字数書いてないからマジでやばい文字数いけるんじゃないの?えこ...
名前 です男
 
Energy Efficient Video Encoding for Cloud and Edge Computing Instances
Energy Efficient Video Encoding for Cloud and Edge Computing InstancesEnergy Efficient Video Encoding for Cloud and Edge Computing Instances
Energy Efficient Video Encoding for Cloud and Edge Computing Instances
Alpen-Adria-Universität
 
Digital Marketing Trends in 2024 | Guide for Staying Ahead
Digital Marketing Trends in 2024 | Guide for Staying AheadDigital Marketing Trends in 2024 | Guide for Staying Ahead
Digital Marketing Trends in 2024 | Guide for Staying Ahead
Wask
 
OpenID AuthZEN Interop Read Out - Authorization
OpenID AuthZEN Interop Read Out - AuthorizationOpenID AuthZEN Interop Read Out - Authorization
OpenID AuthZEN Interop Read Out - Authorization
David Brossard
 
Fueling AI with Great Data with Airbyte Webinar
Fueling AI with Great Data with Airbyte WebinarFueling AI with Great Data with Airbyte Webinar
Fueling AI with Great Data with Airbyte Webinar
Zilliz
 
Project Management Semester Long Project - Acuity
Project Management Semester Long Project - AcuityProject Management Semester Long Project - Acuity
Project Management Semester Long Project - Acuity
jpupo2018
 
Monitoring and Managing Anomaly Detection on OpenShift.pdf
Monitoring and Managing Anomaly Detection on OpenShift.pdfMonitoring and Managing Anomaly Detection on OpenShift.pdf
Monitoring and Managing Anomaly Detection on OpenShift.pdf
Tosin Akinosho
 
Building Production Ready Search Pipelines with Spark and Milvus
Building Production Ready Search Pipelines with Spark and MilvusBuilding Production Ready Search Pipelines with Spark and Milvus
Building Production Ready Search Pipelines with Spark and Milvus
Zilliz
 
Recommendation System using RAG Architecture
Recommendation System using RAG ArchitectureRecommendation System using RAG Architecture
Recommendation System using RAG Architecture
fredae14
 
WeTestAthens: Postman's AI & Automation Techniques
WeTestAthens: Postman's AI & Automation TechniquesWeTestAthens: Postman's AI & Automation Techniques
WeTestAthens: Postman's AI & Automation Techniques
Postman
 
Best 20 SEO Techniques To Improve Website Visibility In SERP
Best 20 SEO Techniques To Improve Website Visibility In SERPBest 20 SEO Techniques To Improve Website Visibility In SERP
Best 20 SEO Techniques To Improve Website Visibility In SERP
Pixlogix Infotech
 
National Security Agency - NSA mobile device best practices
National Security Agency - NSA mobile device best practicesNational Security Agency - NSA mobile device best practices
National Security Agency - NSA mobile device best practices
Quotidiano Piemontese
 
June Patch Tuesday
June Patch TuesdayJune Patch Tuesday
June Patch Tuesday
Ivanti
 
Mariano G Tinti - Decoding SpaceX
Mariano G Tinti - Decoding SpaceXMariano G Tinti - Decoding SpaceX
Mariano G Tinti - Decoding SpaceX
Mariano Tinti
 

Recently uploaded (20)

5th LF Energy Power Grid Model Meet-up Slides
5th LF Energy Power Grid Model Meet-up Slides5th LF Energy Power Grid Model Meet-up Slides
5th LF Energy Power Grid Model Meet-up Slides
 
Webinar: Designing a schema for a Data Warehouse
Webinar: Designing a schema for a Data WarehouseWebinar: Designing a schema for a Data Warehouse
Webinar: Designing a schema for a Data Warehouse
 
20240607 QFM018 Elixir Reading List May 2024
20240607 QFM018 Elixir Reading List May 202420240607 QFM018 Elixir Reading List May 2024
20240607 QFM018 Elixir Reading List May 2024
 
20240609 QFM020 Irresponsible AI Reading List May 2024
20240609 QFM020 Irresponsible AI Reading List May 202420240609 QFM020 Irresponsible AI Reading List May 2024
20240609 QFM020 Irresponsible AI Reading List May 2024
 
UiPath Test Automation using UiPath Test Suite series, part 6
UiPath Test Automation using UiPath Test Suite series, part 6UiPath Test Automation using UiPath Test Suite series, part 6
UiPath Test Automation using UiPath Test Suite series, part 6
 
Unlock the Future of Search with MongoDB Atlas_ Vector Search Unleashed.pdf
Unlock the Future of Search with MongoDB Atlas_ Vector Search Unleashed.pdfUnlock the Future of Search with MongoDB Atlas_ Vector Search Unleashed.pdf
Unlock the Future of Search with MongoDB Atlas_ Vector Search Unleashed.pdf
 
みなさんこんにちはこれ何文字まで入るの?40文字以下不可とか本当に意味わからないけどこれ限界文字数書いてないからマジでやばい文字数いけるんじゃないの?えこ...
みなさんこんにちはこれ何文字まで入るの?40文字以下不可とか本当に意味わからないけどこれ限界文字数書いてないからマジでやばい文字数いけるんじゃないの?えこ...みなさんこんにちはこれ何文字まで入るの?40文字以下不可とか本当に意味わからないけどこれ限界文字数書いてないからマジでやばい文字数いけるんじゃないの?えこ...
みなさんこんにちはこれ何文字まで入るの?40文字以下不可とか本当に意味わからないけどこれ限界文字数書いてないからマジでやばい文字数いけるんじゃないの?えこ...
 
Energy Efficient Video Encoding for Cloud and Edge Computing Instances
Energy Efficient Video Encoding for Cloud and Edge Computing InstancesEnergy Efficient Video Encoding for Cloud and Edge Computing Instances
Energy Efficient Video Encoding for Cloud and Edge Computing Instances
 
Digital Marketing Trends in 2024 | Guide for Staying Ahead
Digital Marketing Trends in 2024 | Guide for Staying AheadDigital Marketing Trends in 2024 | Guide for Staying Ahead
Digital Marketing Trends in 2024 | Guide for Staying Ahead
 
OpenID AuthZEN Interop Read Out - Authorization
OpenID AuthZEN Interop Read Out - AuthorizationOpenID AuthZEN Interop Read Out - Authorization
OpenID AuthZEN Interop Read Out - Authorization
 
Fueling AI with Great Data with Airbyte Webinar
Fueling AI with Great Data with Airbyte WebinarFueling AI with Great Data with Airbyte Webinar
Fueling AI with Great Data with Airbyte Webinar
 
Project Management Semester Long Project - Acuity
Project Management Semester Long Project - AcuityProject Management Semester Long Project - Acuity
Project Management Semester Long Project - Acuity
 
Monitoring and Managing Anomaly Detection on OpenShift.pdf
Monitoring and Managing Anomaly Detection on OpenShift.pdfMonitoring and Managing Anomaly Detection on OpenShift.pdf
Monitoring and Managing Anomaly Detection on OpenShift.pdf
 
Building Production Ready Search Pipelines with Spark and Milvus
Building Production Ready Search Pipelines with Spark and MilvusBuilding Production Ready Search Pipelines with Spark and Milvus
Building Production Ready Search Pipelines with Spark and Milvus
 
Recommendation System using RAG Architecture
Recommendation System using RAG ArchitectureRecommendation System using RAG Architecture
Recommendation System using RAG Architecture
 
WeTestAthens: Postman's AI & Automation Techniques
WeTestAthens: Postman's AI & Automation TechniquesWeTestAthens: Postman's AI & Automation Techniques
WeTestAthens: Postman's AI & Automation Techniques
 
Best 20 SEO Techniques To Improve Website Visibility In SERP
Best 20 SEO Techniques To Improve Website Visibility In SERPBest 20 SEO Techniques To Improve Website Visibility In SERP
Best 20 SEO Techniques To Improve Website Visibility In SERP
 
National Security Agency - NSA mobile device best practices
National Security Agency - NSA mobile device best practicesNational Security Agency - NSA mobile device best practices
National Security Agency - NSA mobile device best practices
 
June Patch Tuesday
June Patch TuesdayJune Patch Tuesday
June Patch Tuesday
 
Mariano G Tinti - Decoding SpaceX
Mariano G Tinti - Decoding SpaceXMariano G Tinti - Decoding SpaceX
Mariano G Tinti - Decoding SpaceX
 

"Writing Maintainable JavaScript". Jon Bretman, Badoo

  • 1. WRITING MAINTAINABLE JAVASCRIPT Yet Another Conference 2013 @jonbretman jonbretman.co.uk Mobile Web Developer @ Badoo http://techblog.badoo.com @BadooTech 1"
  • 2. 2"
  • 3. <!doctype html>! <html>! <head>! <title>My Awesome App</title>! <script src="App.js"></script>! </head>! <body>! </body>! </html>" 3"
  • 5. 5" In engineering, maintainability is the ease with which a product can be maintained in order to... h(p://en.wikipedia.org/wiki/Maintainability"
  • 6. 6" In engineering, maintainability is the ease with which a product can be maintained in order to... isolate defects or their cause h(p://en.wikipedia.org/wiki/Maintainability"
  • 7. 7" In engineering, maintainability is the ease with which a product can be maintained in order to... correct defects or their cause h(p://en.wikipedia.org/wiki/Maintainability"
  • 8. 8" In engineering, maintainability is the ease with which a product can be maintained in order to... prevent unexpected breakdowns h(p://en.wikipedia.org/wiki/Maintainability"
  • 9. 9" In engineering, maintainability is the ease with which a product can be maintained in order to... make future maintenance easier h(p://en.wikipedia.org/wiki/Maintainability"
  • 11. 11" It's about making our work pass the test of time
  • 12. 12" for(B=i=y=u=b=i=5-5,x=10,I=[],l=[];B++<304;I[B-1]=B%x?B/x%x<2|B%x<2?7:B/x&4?! 0:l[i++]="ECDFBDCEAAAAAAAAIIIIIIIIMKLNJLKM@G@TSb~?A6J57IKJT576,+-48HLSUmgukgg " +! "OJNMLK IDHGFE".charCodeAt(y++)-64:7);function X(c,h,e,s){c^=8;for(var o,! S,C,A,R,T,G,d=e&&X(c,0)>1e4,n,N=-1e8,O=20,K=78-h<<9;++O<99;)if((o=I[T=O])&&! (G=o^c)<7){A=G--&2?8:4;C=o-9?l[61+G]:49;do if(!(R=I[T+=l[C]])&&!!G|A<3||! (R+1^c)>9&&G|A>2){if(!(R-2&7))return K;n=G|(c?T>29:T<91)?o:6^c;S=! (R&&l[R&7|32]*2-h-G)+(n-o?110:!G&&(A<2)+1);if(e>h||1<e&e==h&&S>2|d)! {I[T]=n;I[O]=0;S-=X(c,h+1,e,S-N);if(!(h||e-1|B-O|T-b|S<-1e4))return W(),! c&&setTimeout("X(8,0,2),X(8,0,1)",75);I[O]=o;I[T]=R}if(S>N||!h&S==N&&! Math.random()<.5)if(N=S,e>1)if(h?s-S<0:(B=O,b=T,0))break}while(!R&G>2||(T=O,! (G||A>2|(c?O>78:O<41)&!R)&&++C*--A))}return-K+768<N|d&&N}function W(){! i="<table>";for(u=18;u<99;document.body.innerHTML=i+=++u%x-9?! "<th width=60 height=60 onclick='I[b="+u+"]>8?W():X(0,0,1)'style='font-size:50px'bgcolor=#"! +(u-B?u*.9&1||9:"d")+"0f0e0>&#"+(I[u]?9808+l[67+I[u]]:160):u++&&"<tr>")B=b}W()" h(p://js1k.com/2010Efirst/demo/750"
  • 13. 13"
  • 14. 14" •  Mobile Web Team - 4 developers
  • 15. 15" •  Mobile Web Team - 4 developers •  JavaScript, jsDoc, JSHint, Closure Compiler, JsTestDriver
  • 16. 16" •  Mobile Web Team - 4 developers •  JavaScript, jsDoc, JSHint, Closure Compiler, JsTestDriver •  60,000+ lines of JavaScript
  • 17. 17" •  Mobile Web Team - 4 developers •  JavaScript, jsDoc, JSHint, Closure Compiler, JsTestDriver •  60,000+ lines of JavaScript •  ~500,000 daily active users
  • 18. 18" •  Mobile Web Team - 4 developers •  JavaScript, jsDoc, JSHint, Closure Compiler, JsTestDriver •  60,000+ lines of JavaScript •  ~500,000 daily active users •  Code maintainability is key!
  • 19. var topics = [! 'Type Checking',! 'Classes and Inheritance’,! 'Asynchronous Code',! 'Performance'! ];! " 19"
  • 21. <!doctype html>! <html>! <head>! <title>My Awesome App</title>! <script src="App.js"></script>! </head>! <body>! </body>! </html>" 21"
  • 22. Api.get('/conversations', function (conversations) {! ! var intros = conversations.map(function (c) {! var name = c.theirName;! var mostRecent = c.messages[0].text.substring(0, 30);! return name + ': ' + mostRecent;! });! ! App.renderMessages(intros);! ! });! 22"
  • 23. Api.get('/conversations', function (conversations) {! ! var intros = conversations.map(function (c) {! var name = c.theirName;! var mostRecent = c.messages[0].text.substring(0, 30);! return name + ': ' + mostRecent;! });! ! App.renderMessages(intros);! ! });! 23"
  • 24. Api.get('/conversations', function (err, conversations) {! ! var intros = conversations.map(function (c) {! var name = c.theirName;! var mostRecent = c.messages[0].text.substring(0, 30);! return name + ': ' + mostRecent;! });! ! App.renderMessages(intros);! ! });! A lot of things have to go right here 24"
  • 26. if (data.value) {! callback(data.value);! }! ! ! TypeError: Cannot read property 'value' of null! ! ! ! ! " 26"
  • 27. if (data && data.callback) {! var result = data.callback();! }! ! ! TypeError: Property 'callback' of object #<Object> is not a function" " 27"
  • 28. if (data && data.value) {! var index = data.value.indexOf('something');! }! ! ! TypeError: Object #<Object> has no method ‘indexOf’ ! ! ! ! ! 28"
  • 29. typeof {};! "object"! ! typeof 'hello';! "string"! ! typeof 5;! "number”! typeof function () {};! "function"! ! typeof undefined;! "undefined"! ! typeof true;! "boolean"! ! 29"
  • 30. typeof [];! "object"! ! typeof null;! "object"! ! typeof new Date();! "object"! typeof /jsconf/;! "object"! ! typeof document.body;! "object"! ! typeof NaN;! "number"! ! 30"
  • 33. •  If the this value is undefined, return "[object Undefined]".! ! 33"
  • 34. •  If the this value is undefined, return "[object Undefined]".! •  If the this value is null, return "[object Null]".! ! 34"
  • 35. •  If the this value is undefined, return "[object Undefined]".! •  If the this value is null, return "[object Null]".! •  Let class be the value of the [[Class]] property of this. ! 35"
  • 36. •  If the this value is undefined, return "[object Undefined]".! •  If the this value is null, return "[object Null]".! •  Let class be the value of the [[Class]] property of this. •  Return the String value that is the result of concatenating the three Strings "[object ", class, and "]". 36"
  • 37. •  If the this value is undefined, return "[object Undefined]".! •  If the this value is null, return "[object Null]".! •  Let class be the value of the [[Class]] property of this. •  Return the String value that is the result of concatenating the three Strings "[object ", class, and "]". 37" Function.prototype.call()! or! Function.prototype.apply()!
  • 38. var toString = Object.prototype.toString;! var regex = /[object (.*?)]/;! ! var type = function (o) {! var match = toString.call(o).match(regex);! return match[1].toLowerCase();! };! 38"
  • 39. var toString = Object.prototype.toString;! var regex = /[object (.*?)]/;! ! var type = function (o) {! var match = toString.call(o).match(regex);! return match[1].toLowerCase();! };! 39" this === o"
  • 43. var toString = Object.prototype.toString;! var regex = /[object (.*?)]/;! ! var type = function (o) {! ! if (o && o.nodeType === 1) {! return 'element';! }! ! var match = toString.call(o).match(regex);! var _type = match[1].toLowerCase();! ! if (_type === 'number' && isNaN(o)) {! return 'nan';! }! ! return _type;! };! 43"
  • 44. var toString = Object.prototype.toString;! var regex = /[object (.*?)]/;! ! var type = function (o) {! ! if (o && o.nodeType === 1) {! return 'element';! }! ! var match = toString.call(o).match(regex);! var _type = match[1].toLowerCase();! ! if (_type === 'number' && isNaN(o)) {! return 'nan';! }! ! return _type;! };! 44" Special case for DOM elements
  • 45. var toString = Object.prototype.toString;! var regex = /[object (.*?)]/;! ! var type = function (o) {! ! if (o && o.nodeType === 1) {! return 'element';! }! ! var match = toString.call(o).match(regex);! var _type = match[1].toLowerCase();! ! if (_type === 'number' && isNaN(o)) {! return 'nan';! }! ! return _type;! };! 45" Special case for NaN
  • 47. Api.get('/conversations', function (conversations) {! ! if (type(conversations) !== 'array') {! App.renderMessages([]);! return;! }! ! var intros = conversations.map(function (c) {! ! if (type(c) !== 'object') {! return '';! }! ! var name = type(c.theirName) === 'string' ? c.theirName : '';! var mostRecent = '';! ! if (type(c.messages) === 'array' ||! type(c.messages[0]) === 'object' ||! type(c.messages[0].text) === 'string') {! mostRecent = c.messages[0].text.substring(0, 30);! }! ! return name + ': ' + mostRecent;! });! ! App.renderMessages(intros);! ! });" 47"
  • 48. Api.get("/conversations",function(e){var t=e.map(function(e){var t=e.theirName;var n=e.messages[0].text.substring(0,30);return t+": "+n});App.renderMessages(t)})! ! ! ! ! ! ! ! ! ! Api.get("/conversations",function(e){if(type(e)!=="array") {App.renderMessages([]);return}var t=e.map(function(e){if(type(e)! =="object"){return""}var t=type(e.theirName)==="string"? e.theirName:"";var n="";if(type(e.messages)==="array"|| type(e.messages[0])==="object"||type(e.messages[0].text)==="string") {n=e.messages[0].text.substring(0,30)}return t+": "+n});App.renderMessages(t)})" + 137% 48"
  • 51. 51" Prevents unexpected breakdowns Makes future maintenance easier
  • 54. 54" var Controller = {! ! init: function () {! // do some initialization! },! ! loadView: function () {! ! }! ! };! ! // somewhere else in the app! Controller.init();! Controller.loadView();"
  • 55. 55" var Controller = {! ! init: function () {! // do some initialization! },! ! loadView: function () {! ! }! ! };! ! // somewhere else in the app! Controller.init();! Controller.loadView();" Feels messy
  • 56. 56" var ChatController = {};! ! for (var key in Controller) {! ChatController[key] = Controller;! }! ! ChatController.loadView = function () {! ! Controller.loadView.apply(this, arguments); // do some additional stuff! ! };! "
  • 57. 57" var ChatController = {};! ! for (var key in Controller) {! ChatController[key] = Controller;! }! ! ChatController.loadView = function () {! ! Controller.loadView.apply(this, arguments); // do some additional stuff! ! };! " Not proper inheritance
  • 59. class Controller {! !! public Controller () {! // do some initialization! }! !! ! public void loadView () {! ! !! ! }! ! }! ! class ChatController extends Controller {! !! ! public void loadView () {! ! ! super.loadView();! ! ! // do some additional stuff! ! }! !! }" 59"
  • 60. class Controller {! ! constructor () {! // do some initialization! }! ! loadView () {! ! }! ! }! ! class ChatController extends Controller {! ! loadView () {! super.loadView();! // do some additional stuff! }! ! }" 60"
  • 61. class Controller! ! constructor: () ->! # do some initialization! ! loadView: () ->! ! ! class ChatController extends Controller! ! loadView: () ->! super! # do some initialization" 61"
  • 62. var ChatController, Controller, _ref,! __hasProp = {}.hasOwnProperty,! __extends = function(child, parent) {! for (var key in parent) {! if (__hasProp.call(parent, key))! child[key] = parent[key];! }! function ctor() {! this.constructor = child;! }! ctor.prototype = parent.prototype;! child.prototype = new ctor();! child.__super__ = parent.prototype;! return child;! };! ! Controller = (function() {! function Controller() {}! Controller.prototype.loadView = function() {};! return Controller;! })();! ! ChatController = (function(_super) {! __extends(ChatController, _super);! ! function ChatController() {! _ref = ChatController.__super__.constructor.apply(this, arguments);! return _ref;! }! ! ChatController.prototype.loadView = function() {! return ChatController.__super__.loadView.apply(this, arguments);! };! ! return ChatController;! })(Controller);" 62"
  • 63. var ChatController, Controller, _ref,! __hasProp = {}.hasOwnProperty,! __extends = function(child, parent) {! for (var key in parent) {! if (__hasProp.call(parent, key))! child[key] = parent[key];! }! function ctor() {! this.constructor = child;! }! ctor.prototype = parent.prototype;! child.prototype = new ctor();! child.__super__ = parent.prototype;! return child;! };! ! Controller = (function() {! function Controller() {}! Controller.prototype.loadView = function() {};! return Controller;! })();! ! ChatController = (function(_super) {! __extends(ChatController, _super);! ! function ChatController() {! _ref = ChatController.__super__.constructor.apply(this, arguments);! return _ref;! }! ! ChatController.prototype.loadView = function() {! return ChatController.__super__.loadView.apply(this, arguments);! };! ! return ChatController;! })(Controller);" 63" Utility method
  • 64. var ChatController, Controller, _ref,! __hasProp = {}.hasOwnProperty,! __extends = function(child, parent) {! for (var key in parent) {! if (__hasProp.call(parent, key))! child[key] = parent[key];! }! function ctor() {! this.constructor = child;! }! ctor.prototype = parent.prototype;! child.prototype = new ctor();! child.__super__ = parent.prototype;! return child;! };! ! Controller = (function() {! function Controller() {}! Controller.prototype.loadView = function() {};! return Controller;! })();! ! ChatController = (function(_super) {! __extends(ChatController, _super);! ! function ChatController() {! _ref = ChatController.__super__.constructor.apply(this, arguments);! return _ref;! }! ! ChatController.prototype.loadView = function() {! return ChatController.__super__.loadView.apply(this, arguments);! };! ! return ChatController;! })(Controller);" 64" Class Definitions
  • 65. var Controller = function () {! // do some initialization! };! ! Controller.prototype.loadView = function() {! ! };! ! var ChatController = function (name) {! Controller.apply(this, arguments);! };! ! ChatController.prototype.loadView = function () {! ChatController._super.loadView.apply(this, arguments);! // do some additional stuff! }! ! extends(ChatController, Controller);" 65"
  • 66. var Controller = function () {! // do some initialization! };! ! Controller.prototype.loadView = function() {! ! };! ! var ChatController = function (name) {! Controller.apply(this, arguments);! };! ! ChatController.prototype.loadView = function () {! ChatController._super.loadView.apply(this, arguments);! // do some additional stuff! }! ! extends(ChatController, Controller);" 66" The magic bit
  • 67. 67" There is no such thing as magic.
  • 68. var extends = function(child, parent) {! for (var key in parent) {! if (parent.hasOwnProperty(key)) {! child[key] = parent[key];! }! }! function ctor() { ! this.constructor = child; ! }! ctor.prototype = parent.prototype;! child.prototype = new ctor();! child._super = parent.prototype;! return child;! };" 68"
  • 69. var extends = function(child, parent) {! for (var key in parent) {! if (parent.hasOwnProperty(key)) {! child[key] = parent[key];! }! }! function ctor() { ! this.constructor = child; ! }! ctor.prototype = parent.prototype;! child.prototype = new ctor();! child._super = parent.prototype;! return child;! };" 69" Copy static properties / methods
  • 70. var extends = function(child, parent) {! for (var key in parent) {! if (parent.hasOwnProperty(key)) {! child[key] = parent[key];! }! }! function ctor() { ! this.constructor = child; ! }! ctor.prototype = parent.prototype;! child.prototype = new ctor();! child._super = parent.prototype;! return child;! };" 70" Set up prototype chain
  • 71. var extends = function(child, parent) {! for (var key in parent) {! if (parent.hasOwnProperty(key)) {! child[key] = parent[key];! }! }! ! ! ctor.prototype = Object.create(parent.prototype);! ! ! child._super = parent.prototype;! return child;! };" 71" ECMAScript 5
  • 72. var extends = function(child, parent) {! for (var key in parent) {! if (parent.hasOwnProperty(key)) {! child[key] = parent[key];! }! }! function ctor() { ! this.constructor = child; ! }! ctor.prototype = parent.prototype;! child.prototype = new ctor();! child._super = parent.prototype;! return child;! };" 72" Add shorthand to super
  • 73. var controller = new Controller();! var chat = new ChatController();! ! controller instanceof Controller; // true! ! chat instanceof Controller; // true! chat instanceof ChatController; // true" 73"
  • 74. 74" The rest is about good practice
  • 75. Use getter and setter methods alert(jon.name);! jon.name = 'John';! ! ! alert(jon.getName());! jon.setName('John');! jon.set('name', 'John');" 75"
  • 76. Define all properties on the prototype, even if they are null. /**! * The persons age.! * @type {Number}! */! Person.prototype.age = null;" 76"
  • 77. Mark private methods with a leading or trailing underscore // somethings are best kept private :)! Person.prototype._singInShower = function () {! ! };" 77"
  • 78. Use static methods / properties Person.prototype.EVENTS = {! WALK: 'WALK',! TALK: 'TALK'! };! ! Person.EVENTS = {! WALK: 'WALK',! TALK: 'TALK'! };" 78"
  • 80. 80" Correct defects or their causes
  • 81. 81" Correct defects or their causes Makes future maintenance easier
  • 85. Promises •  Requires a library to provide the functionality 85"
  • 86. Promises •  Requires a library to provide the functionality •  Different implementations •  jQuery Deferred api.jquery.com/category/deferred-object/ •  rsvp.js github.com/tildeio/rsvp.js •  when.js github.com/cujojs/when •  promise.js github.com/then/promise 86"
  • 87. Promises •  Requires a library to provide the functionality •  Different implementations •  jQuery Deferred api.jquery.com/category/deferred-object/ •  rsvp.js github.com/tildeio/rsvp.js •  when.js github.com/cujojs/when •  promise.js github.com/then/promise •  Kind of complicated… 87"
  • 92. 92" load: function () {! ! Api.get('/profile/own', _.bind(function (ownProfile) {! ! this.ownProfile = ownProfile;! ! Api.get('/profile/' + id, _.bind(function (theirProfile) {! ! this.theirProfile = theirProfile;! ! Api.get('/chatMessages', _.bind(function (messages) {! ! this.messages = messages;! this.render();! ! }, this), _.bind(function (err) {! this.onError();! }, this));! }, this), _.bind(function (err) {! this.onError();! }, this));! }, this), _.bind(function (err) {! this.onError();! }, this));! }!
  • 93. 93" load: function () {! ! Api.get('/profile/own', _.bind(function (ownProfile) {! ! this.ownProfile = ownProfile;! ! Api.get('/profile/' + id, _.bind(function (theirProfile) {! ! this.theirProfile = theirProfile;! ! Api.get('/chatMessages', _.bind(function (messages) {! ! this.messages = messages;! this.render();! ! }, this), _.bind(function (err) {! this.onError();! }, this));! }, this), _.bind(function (err) {! this.onError();! }, this));! }, this), _.bind(function (err) {! this.onError();! }, this));! }!
  • 94. 94" load: function () {! ! Api.get('/profile/own', _.bind(function (ownProfile) {! ! this.ownProfile = ownProfile;! ! Api.get('/profile/' + id, _.bind(function (theirProfile) {! ! this.theirProfile = theirProfile;! ! Api.get('/chatMessages', _.bind(function (messages) {! ! this.messages = messages;! this.render();! ! }, this), _.bind(function (err) {! this.onError();! }, this));! }, this), _.bind(function (err) {! this.onError();! }, this));! }, this), _.bind(function (err) {! this.onError();! }, this));! }! Action Error Handling
  • 96. “I’ve come to the conclusion that callback hell is a design choice and not an inherent flaw in the concept of asynchronous function and callback” http://blog.caplin.com/2013/03/13/callback-hell-is-a-design-choice/ 96"
  • 98. 98" var handler = function (err, response) {! ! };! ! doSomething(handler);"
  • 99. 99" ! load: function (id) {! this.id = id;! Api.get('/profile/own', this.onOwnProfile);! },! ! onOwnProfile: function (err, ownProfile) {! if (err) return this.onError();! this.ownProfile = ownProfile;! Api.get('/profile/' + this.id, this.onTheirProfile);! },! ! onTheirProfile: function (err, theirProfile) {! if (err) return this.onError();! this.theirProfile = theirProfile;! Api.get('/chatMessages', this.onMessages);! },! ! onMessages: function (err, messages) {! if (err) return this.onError();! this.messages = messages;! this.render();! }!
  • 100. 100" ! load: function (id) {! this.id = id;! Api.get('/profile/own', this.onOwnProfile);! },! ! onOwnProfile: function (err, ownProfile) {! if (err) return this.onError();! this.ownProfile = ownProfile;! Api.get('/profile/' + this.id, this.onTheirProfile);! },! ! onTheirProfile: function (err, theirProfile) {! if (err) return this.onError();! this.theirProfile = theirProfile;! Api.get('/chatMessages', this.onMessages);! },! ! onMessages: function (err, messages) {! if (err) return this.onError();! this.messages = messages;! this.render();! }!
  • 101. 101" ! load: function (id) {! this.id = id;! Api.get('/profile/own', this.onOwnProfile);! },! ! onOwnProfile: function (err, ownProfile) {! if (err) return this.onError();! this.ownProfile = ownProfile;! Api.get('/profile/' + this.id, this.onTheirProfile);! },! ! onTheirProfile: function (err, theirProfile) {! if (err) return this.onError();! this.theirProfile = theirProfile;! Api.get('/chatMessages', this.onMessages);! },! ! onMessages: function (err, messages) {! if (err) return this.onError();! this.messages = messages;! this.render();! }!
  • 102. 102" ! load: function (id) {! this.id = id;! Api.get('/profile/own', this.onOwnProfile);! },! ! onOwnProfile: function (err, ownProfile) {! if (err) return this.onError();! this.ownProfile = ownProfile;! Api.get('/profile/' + this.id, this.onTheirProfile);! },! ! onTheirProfile: function (err, theirProfile) {! if (err) return this.onError();! this.theirProfile = theirProfile;! Api.get('/chatMessages', this.onMessages);! },! ! onMessages: function (err, messages) {! if (err) return this.onError();! this.messages = messages;! this.render();! }! Reusable
  • 105. Avoid anonymous functions 105" Useless stack traces Sign of poor structure
  • 107. Keep things shallow 107" Means you are probably using anonymous functions
  • 108. Keep things shallow 108" Means you are probably using anonymous functions Everyone will hate you
  • 110. 110" Isolate defects or their causes
  • 111. 111" Isolate defects or their causes Makes future maintenance easier
  • 112. 112" Isolate defects or their causes Makes future maintenance easier Prevent unexpected breakdowns
  • 114. var i = 0;! var thing;! for (; i < things.length; i++) {! thing = things[i];! }" things.forEach(function (thing, i) {! ! });" 114" or…
  • 115. 115" http://jsperf.com/foreachvsloop 24x faster 13x faster 13x Faster 350,000 operations per second
  • 116. $('a').on('click', function (e) {! ! });! ! ! ! ! ! $('#container').on('click', 'a', function (e) {! ! });" or… 116"
  • 117. 117" http://jsperf.com/domevents 21x faster 19x faster 21x Faster Only 1000 operations per second
  • 118. 118" $('#container').append('<ul></ul>');! for (var i = 0; i < messages.length; i++) {! $('#container')! .find('ul')! .append('<li>' + messages[i].text + '</li>');! }" ! ! ! ! var html = '<ul>';! for (var i = 0; i < messages.length; i++) {! html += '<li>' + messages[i].text + '</li>';! }! html += '</ul>';! $('#container').html(html);! or…
  • 119. 119" http://jsperf.com/renderinghtml 48x Faster 44x faster 15x faster Less than 200 operations per second!
  • 121. DOM operations Iteration / function calls 121"
  • 124. var cache = {! ! get: function (key) {! return localStorage.getItem(key);! },! ! set: function (key, value) {! localStorage.setItem(key, value);! }! ! };" 124"
  • 125. var cache = {! ! get: function (key) {! return localStorage.getItem(key);! },! ! set: function (key, value) {! localStorage.setItem(key, value);! }! ! };" 125" Disc IO
  • 126. var cache = {! ! data_: {},! ! get: function (key) {! ! if (this.data_.hasOwnProperty(key)) {! return this.data_[key];! }! ! var value = localStorage.getItem(key);! ! if (value !== null) {! this.data_[key] = value;! return value;! }! ! return null;! },! set: function (key, value) {! this.data_[key] = value;! localStorage.setItem(key, value);! }! };" 126"
  • 127. var cache = {! ! data_: {},! ! get: function (key) {! ! if (this.data_.hasOwnProperty(key)) {! return this.data_[key];! }! ! var value = localStorage.getItem(key);! ! if (value !== null) {! this.data_[key] = value;! return value;! }! ! return null;! },! set: function (key, value) {! this.data_[key] = value;! localStorage.setItem(key, value);! }! };" 127" Memory
  • 128. var cache = {! ! data_: {},! ! get: function (key) {! ! if (this.data_.hasOwnProperty(key)) {! return this.data_[key];! }! ! var value = localStorage.getItem(key);! ! if (value !== null) {! this.data_[key] = value;! return value;! }! ! return null;! },! set: function (key, value) {! this.data_[key] = value;! localStorage.setItem(key, value);! }! };" 128" Quicker reading
  • 129. var cache = {! ! data_: {},! ! get: function (key) {! ! if (this.data_.hasOwnProperty(key)) {! return this.data_[key];! }! ! var value = localStorage.getItem(key);! ! if (value !== null) {! this.data_[key] = value;! return value;! }! ! return null;! },! set: function (key, value) {! this.data_[key] = value;! localStorage.setItem(key, value);! }! };" 129" Saving for later
  • 133. 133" Makes future maintenance easier Prevent unexpected breakdowns
  • 136. 136" It's about making our lives easier
  • 137. 137" It's about making our work pass the test of time
  • 138. Thank you! 138" Yet Another Conference 2013 @jonbretman jonbretman.co.uk Mobile Web Developer @ Badoo http://techblog.badoo.com @BadooTech