javascript abstraction
Post on 05-Dec-2014
480 Views
Preview:
DESCRIPTION
TRANSCRIPT
JavaScriptAbstraction 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
Beforefunction 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!";}
Afterfunction 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
Examplefunction 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 });}
Usagevar 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
Click
function () { alert(‘hello world!’); }
Coupled Binding
Decoupled Binding
Click
function () { alert(‘hello world!’); }
Greet
Load
Decoupled Binding
function () { alert(‘hello world!’); }
Greet
function
function
OOP
• Object oriented programming
• Base classes are usually most abstract
• Polymorphism
• Duck typing
• Composition
function sayHello() { alert(‘hello world!’); }
Procedural
function joe() { sayHello(); }
joe(); jane();function jane() { sayHello(); }
function sayHello() { alert(‘hello world!’); }
Object Oriented
joe.hi(); jane.hi();
joe = new Person();
jane = new Person();
function Person() { this.hi = sayHello; }
Examplefunction 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"]));
Examplevar 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() );
Examplevar 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
HTML
CSS
JS
MVC
HTML
JS
CSS
Data
Examplefunction 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
Beforefunction buildPage() { var facebookIcon = "http://www.facebook.com/icon.png"; while (someConditionIsTrue()){ doSomeWork(); } var i = resolveTwitterIcon(); }!var PinterestSmallLogo = pinterest();!buildPage();
Improvingfunction buildPage() { var iconFacebook = "http://www.facebook.com/icon.png"; while (someConditionIsTrue()){ doSomeWork(); } var iconTwitter = resolveTwitterIcon(); }!var iconPinterest = pinterest();!buildPage();
Afterfunction 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
Examplefunction 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
White border on click
Gray background
Connect
• Thank you for your time
• Connect with me on LinkedIn
• Join the Hardcore JavaScript community
• Read my blog
• Contact me via e-mail
top related