JavaScript Abstraction in Implementation ! by Milan Adamovsky http://milan.adamovsky.com ◆ http://www.hardcorejs.com
Preface • Based on personal observations • Spanning over 15 companies • Small companies to mostly enterprise • Not based on comprehensive research • Full life cycle of web development
Quick Exercise
Analyze <html> <head> <title> This is the title of the page </title> </head> <body> <p id="main_content"> This is my content </p> <ul> <li class="first"> One <li> Two <ol> <li class="first"> A </ol> <li> </ul> </body> </html>
Analysis • A document • A tree of hierarchal nodes off of root node • Two children nodes off of root node • Second child node has two children nodes • Two children nodes are siblings
Overview • Ultimate goal is to write less code • Increase reusability • Change way of thinking • Change way of coding • Anticipate future code evolution
Quick Example
Before function resolveFirstName(person) { if (person.firstName) return person.firstName; else return "First name could not be found!"; } ! function findAge(person) { return person.age; } ! function printOutName(person) { if (cookie === "senior") { findAge() + 20; resolveAddress(); } return person.lastName || "No last name was found on record!"; }
After function errorMessage(descriptor) { return ({ age : "Age could not be determined", firstName : "First name could not be found!", lastName : "No last name was found on record!" })[descriptor]; } ! function resolveDescriptor(descriptor) { return typeof this[descriptor] !== "undefined" ? this[descriptor] : errorMessage(descriptor); } ! function resolveSeniority() { if (cookie === "senior") { findAge() + 20; resolveAddress(); } }
Paradigms
Overloading • One function serves multiple purposes • Argument signature determines function • Must differ by arity or data types • Same function name • JavaScript can only simulate overloading
Example function addMethod(object, name, fn){ // addMethod - By John Resig (MIT Licensed) var old = object[ name ]; object[ name ] = function(){ if ( fn.length == arguments.length ) return fn.apply( this, arguments ); else if ( typeof old == 'function' ) return old.apply( this, arguments ); }; } function Users(){ addMethod(this, "find", function(){ // Find all users... }); addMethod(this, "find", function(name){ // Find a user by name }); addMethod(this, "find", function(first, last){ // Find a user by first and last name }); }
Usage var users = new Users(); ! users.find(); // Finds all ! users.find("John"); // Finds users by name ! users.find("John", "Resig"); // Finds users by first and last name ! users.find("John", "E", "Resig"); // Does nothing
Events • Usually we couple an event to a function • Sometimes many functions to one event • We know what happens on an event • We should not care what happens • Decouple handlers from events
Coupled Binding Click function () {
 alert(‘hello world!’);
 }
Decoupled Binding Click Load Greet function () {
 alert(‘hello world!’);
 }
Decoupled Binding Greet function function function () {
 alert(‘hello world!’);
 }
OOP • Object oriented programming • Base classes are usually most abstract • Polymorphism • Duck typing • Composition
Procedural joe(); function joe() {
 sayHello();
 } jane(); function jane() {
 sayHello();
 } function sayHello() {
 alert(‘hello world!’);
 }
Object Oriented joe = new Person(); function Person() {
 this.hi = sayHello;
 } jane = new Person(); joe.hi();
 jane.hi(); function sayHello() {
 alert(‘hello world!’);
 }
Example function Person(name) { this.hi = sayHello; this.name = name; function sayHello() { console.log('hello world from ' + this.name); } } ! function init(names) { var people = []; for (var i = 0, count = names.length; i < count; i++) { people.push(new Person(names[i])); } return people; } function greet(people) { for (var i = 0, count = people.length; i < count; i++) { people[i].hi(); } } greet(init(["Joe", "Jane"]));
Example var Rifle = function () { this.reload = function () {}; this.fire = function () { /* ... */ }; }, ! Cannon = function () { this.reload = function () {}; this.fire = function () {}; }; ! var Soldier = function (gun) { this.currentGun = gun; this.inventory = { guns : [ gun ] }; this.attack = function () { this.currentGun.fire(); }; }; ! var Tank = function (gun) { this.currentGun = gun; this.inventory = { guns : [ gun ] }; this.attack = function () { this.currentGun.fire(); }; }; ! var soldier = new Soldier( new Rifle() ), tank = new Tank( new Cannon() );
Example var Rifle = function () { this.reload = function () {}; this.fire = function () { /* ... */ }; }, ! Cannon = function () { this.reload = function () {}; this.fire = function () {}; }; ! var Combatant = function (gun) { this.currentGun = gun; this.inventory = { guns : [ gun ] }; this.attack = function () { this.currentGun.fire(); }; }; ! var soldier = new Combatant( new Rifle() ), tank = new Combatant( new Cannon() );
MVC • Abstraction engrained in architecture • Separation of concerns (SoC) • Decouple model, view, controller • Each component replaceable • Any of these can be further abstracted
Traditional JS CSS HTML
MVC CSS Data HTML JS
Example function controller(model, view) { var items = “"; ! for (var i = 0, count = model.items.length; i < count; i++) { items += view.item.replace("{{item}}", model.items[i]); } } return view.list.replace("{{items}}", items); ! ! var view = { item : "<li>{{item}}</li>", list : "<ul>{{items}}</ul>" }; ! var model = { items : [1, 2, 3] }; ! console.log(controller(model, view));
RWD / AWD • Responsive responds to screen widths • Adaptive adapts to devices • Use mobile-first approach in all code • Segment code to accommodate growth • Use lazy loaders and module patterns
Coding
Thought Process • Do not care for specifics • Do not care who calls what • Assume anyone can call anything • Assume anything can contain anything • Think interfaces not internals
APIs • Make them intuitive • Do not rely on documentation • Provide switches for easy customization • Prioritize flexibility and agility of code • Design functions to handle one thing
Nomenclature • Generalize identifiers • Don’t over-generalize, stay within context • Reverse name groupings • Group related variables in objects
Before function buildPage() { var facebookIcon = "http://www.facebook.com/icon.png"; while (someConditionIsTrue()){ doSomeWork(); } var i = resolveTwitterIcon(); } ! var PinterestSmallLogo = pinterest(); ! buildPage();
Improving function buildPage() { var iconFacebook = "http://www.facebook.com/icon.png"; while (someConditionIsTrue()){ doSomeWork(); } var iconTwitter = resolveTwitterIcon(); } ! var iconPinterest = pinterest(); ! buildPage();
After function buildPage(icons) { icons.facebook = "http://www.facebook.com/icon.png"; while (someConditionIsTrue()){ doSomeWork(); } icons.twitter = resolveTwitterIcon(); } ! var }; ! icons = { facebook : "", pinterest : pinterest(), twitter : "" buildPage(icons);
Habit Forming • Adhere to strict coding style • Remove comments • Progressively generalize identifiers • Identify similar patterns to normalize • Code in anticipation for change
Generalize • This will do something • When something happens • It will take some parameters • Parameters will map to some object • The outcome will be specific to context
Example function initModules() { for (module in app.modules) { if (app.modules[module].init && app.modules[module].checked()) { if (app.modules[module].init.call(this, arguments)) { initialized++; } } } } function initModules() { var module; for (moduleName in app.modules) { module = app.modules[moduleName]; if (module.init && module.checked()) { if (module.init.call(this, arguments)) { initialized++; } } } }
Considerations • Balance performance • Balance maintainability • Strive for quality • Balance code base size • Balance complexity
Exercise 0 1 2 3 4 5 6 7 8 9 + 0 * Update on button click Gray background White border on click
Connect • Thank you for your time • Connect with me on LinkedIn • Join the Hardcore JavaScript community • Read my blog • Contact me via e-mail

JavaScript Abstraction

  • 1.
    JavaScript Abstraction in Implementation ! by Milan Adamovsky http://milan.adamovsky.com ◆ http://www.hardcorejs.com
  • 2.
    Preface • Based onpersonal observations • Spanning over 15 companies • Small companies to mostly enterprise • Not based on comprehensive research • Full life cycle of web development
  • 3.
  • 4.
    Analyze <html> <head> <title> This is thetitle of the page </title> </head> <body> <p id="main_content"> This is my content </p> <ul> <li class="first"> One <li> Two <ol> <li class="first"> A </ol> <li> </ul> </body> </html>
  • 5.
    Analysis • A document •A tree of hierarchal nodes off of root node • Two children nodes off of root node • Second child node has two children nodes • Two children nodes are siblings
  • 6.
    Overview • Ultimate goalis to write less code • Increase reusability • Change way of thinking • Change way of coding • Anticipate future code evolution
  • 7.
  • 8.
    Before function resolveFirstName(person) { if(person.firstName) return person.firstName; else return "First name could not be found!"; } ! function findAge(person) { return person.age; } ! function printOutName(person) { if (cookie === "senior") { findAge() + 20; resolveAddress(); } return person.lastName || "No last name was found on record!"; }
  • 9.
    After function errorMessage(descriptor) { return({ age : "Age could not be determined", firstName : "First name could not be found!", lastName : "No last name was found on record!" })[descriptor]; } ! function resolveDescriptor(descriptor) { return typeof this[descriptor] !== "undefined" ? this[descriptor] : errorMessage(descriptor); } ! function resolveSeniority() { if (cookie === "senior") { findAge() + 20; resolveAddress(); } }
  • 10.
  • 11.
    Overloading • One functionserves multiple purposes • Argument signature determines function • Must differ by arity or data types • Same function name • JavaScript can only simulate overloading
  • 12.
    Example function addMethod(object, name,fn){ // addMethod - By John Resig (MIT Licensed) var old = object[ name ]; object[ name ] = function(){ if ( fn.length == arguments.length ) return fn.apply( this, arguments ); else if ( typeof old == 'function' ) return old.apply( this, arguments ); }; } function Users(){ addMethod(this, "find", function(){ // Find all users... }); addMethod(this, "find", function(name){ // Find a user by name }); addMethod(this, "find", function(first, last){ // Find a user by first and last name }); }
  • 13.
    Usage var users =new Users(); ! users.find(); // Finds all ! users.find("John"); // Finds users by name ! users.find("John", "Resig"); // Finds users by first and last name ! users.find("John", "E", "Resig"); // Does nothing
  • 14.
    Events • Usually wecouple an event to a function • Sometimes many functions to one event • We know what happens on an event • We should not care what happens • Decouple handlers from events
  • 15.
    Coupled Binding Click function (){
 alert(‘hello world!’);
 }
  • 16.
    Decoupled Binding Click Load Greet function (){
 alert(‘hello world!’);
 }
  • 17.
    Decoupled Binding Greet function function function (){
 alert(‘hello world!’);
 }
  • 18.
    OOP • Object orientedprogramming • Base classes are usually most abstract • Polymorphism • Duck typing • Composition
  • 19.
    Procedural joe(); function joe() {
 sayHello();
 } jane(); functionjane() {
 sayHello();
 } function sayHello() {
 alert(‘hello world!’);
 }
  • 20.
    Object Oriented joe =new Person(); function Person() {
 this.hi = sayHello;
 } jane = new Person(); joe.hi();
 jane.hi(); function sayHello() {
 alert(‘hello world!’);
 }
  • 21.
    Example function Person(name) { this.hi= sayHello; this.name = name; function sayHello() { console.log('hello world from ' + this.name); } } ! function init(names) { var people = []; for (var i = 0, count = names.length; i < count; i++) { people.push(new Person(names[i])); } return people; } function greet(people) { for (var i = 0, count = people.length; i < count; i++) { people[i].hi(); } } greet(init(["Joe", "Jane"]));
  • 22.
    Example var Rifle =function () { this.reload = function () {}; this.fire = function () { /* ... */ }; }, ! Cannon = function () { this.reload = function () {}; this.fire = function () {}; }; ! var Soldier = function (gun) { this.currentGun = gun; this.inventory = { guns : [ gun ] }; this.attack = function () { this.currentGun.fire(); }; }; ! var Tank = function (gun) { this.currentGun = gun; this.inventory = { guns : [ gun ] }; this.attack = function () { this.currentGun.fire(); }; }; ! var soldier = new Soldier( new Rifle() ), tank = new Tank( new Cannon() );
  • 23.
    Example var Rifle =function () { this.reload = function () {}; this.fire = function () { /* ... */ }; }, ! Cannon = function () { this.reload = function () {}; this.fire = function () {}; }; ! var Combatant = function (gun) { this.currentGun = gun; this.inventory = { guns : [ gun ] }; this.attack = function () { this.currentGun.fire(); }; }; ! var soldier = new Combatant( new Rifle() ), tank = new Combatant( new Cannon() );
  • 24.
    MVC • Abstraction engrainedin architecture • Separation of concerns (SoC) • Decouple model, view, controller • Each component replaceable • Any of these can be further abstracted
  • 25.
  • 26.
  • 27.
    Example function controller(model, view){ var items = “"; ! for (var i = 0, count = model.items.length; i < count; i++) { items += view.item.replace("{{item}}", model.items[i]); } } return view.list.replace("{{items}}", items); ! ! var view = { item : "<li>{{item}}</li>", list : "<ul>{{items}}</ul>" }; ! var model = { items : [1, 2, 3] }; ! console.log(controller(model, view));
  • 28.
    RWD / AWD •Responsive responds to screen widths • Adaptive adapts to devices • Use mobile-first approach in all code • Segment code to accommodate growth • Use lazy loaders and module patterns
  • 29.
  • 30.
    Thought Process • Donot care for specifics • Do not care who calls what • Assume anyone can call anything • Assume anything can contain anything • Think interfaces not internals
  • 31.
    APIs • Make themintuitive • Do not rely on documentation • Provide switches for easy customization • Prioritize flexibility and agility of code • Design functions to handle one thing
  • 32.
    Nomenclature • Generalize identifiers •Don’t over-generalize, stay within context • Reverse name groupings • Group related variables in objects
  • 33.
    Before function buildPage() { varfacebookIcon = "http://www.facebook.com/icon.png"; while (someConditionIsTrue()){ doSomeWork(); } var i = resolveTwitterIcon(); } ! var PinterestSmallLogo = pinterest(); ! buildPage();
  • 34.
    Improving function buildPage() { variconFacebook = "http://www.facebook.com/icon.png"; while (someConditionIsTrue()){ doSomeWork(); } var iconTwitter = resolveTwitterIcon(); } ! var iconPinterest = pinterest(); ! buildPage();
  • 35.
    After function buildPage(icons) { icons.facebook= "http://www.facebook.com/icon.png"; while (someConditionIsTrue()){ doSomeWork(); } icons.twitter = resolveTwitterIcon(); } ! var }; ! icons = { facebook : "", pinterest : pinterest(), twitter : "" buildPage(icons);
  • 36.
    Habit Forming • Adhereto strict coding style • Remove comments • Progressively generalize identifiers • Identify similar patterns to normalize • Code in anticipation for change
  • 37.
    Generalize • This willdo something • When something happens • It will take some parameters • Parameters will map to some object • The outcome will be specific to context
  • 38.
    Example function initModules() { for(module in app.modules) { if (app.modules[module].init && app.modules[module].checked()) { if (app.modules[module].init.call(this, arguments)) { initialized++; } } } } function initModules() { var module; for (moduleName in app.modules) { module = app.modules[moduleName]; if (module.init && module.checked()) { if (module.init.call(this, arguments)) { initialized++; } } } }
  • 39.
    Considerations • Balance performance •Balance maintainability • Strive for quality • Balance code base size • Balance complexity
  • 40.
    Exercise 0 1 2 3 4 5 6 7 8 9 + 0 * Update on buttonclick Gray background White border on click
  • 41.
    Connect • Thank youfor your time • Connect with me on LinkedIn • Join the Hardcore JavaScript community • Read my blog • Contact me via e-mail