UX Camp

Web Frontend Dev

Part 3 of 4: From the Trenches


Presented on 15 March 2013.


Press down for video or right for slides.

Presented by

John-Philip Johansson at Avanade

Tip: Watch in fullscreen. It's in HD.

Download: MP4 720p, MP4 480p, OGG 720p, or OGG 480p.

Agenda


Rounding up the basics


Design patterns in JavaScript


Somethings from a project


Tips & tricks

Rounding up the basics


Some extra stuff we didn't cover so far

JavaScript functions


IIFE


Function.bind()


Curry functions


Safer constructors


Even safer constructors

IIFE

Immediately Invoked Function Expressions


(function() {
  // do secret stuff
})();

Function.bind()


var buffer = {
  entries: [],
  add: function(s) {
    this.entries.push(s);
  }
};

var source = ["867", "-", "5309"];
source.forEach(buffer.add); // error: entries is undefined

source.forEach(buffer.add.bind(buffer)); // ok!

Curry functions


var simpleUrl = function(protocol, domain, path) {
  return protocol + "://" + domain + "/" + path;
}

var myPageUrl = simpleUrl.bind(null, 'http', 'spelkalendern.se');
myPageUrl('about') === 'http://spelkalendern.se/about';

Safer constructors


function User(name, passwordHash) {
  if (!(this instanceof User))
    return new User(name, passwordHash);

  this.name = name;
  this.passwordHash = passwordHash;
}

var user1 = new User('abc', '123'); // as expected
var user2 = User('def', '456'); // now also works!

Even safer constructor


function User(name, passwordHash) {
  var self = this instanceof User ? this : Object.create(User.prototype);

  self.name = name;
  self.passwordHash = passwordHash;

  return self;
}

var user1 = new User('abc', '123'); // as expected
var user2 = User('def', '456'); // now also works!

JavaScript arguments


Undefined arguments


Array


Arguments object


Options

Undefined arguments


var sum = sum(1, 2, 3, 4, 5);

Array


send(url, [1, 2, 3, 4, 5]);

Arguments object


send( { url: url, data: [1, 2, 3, 4, 5] } );

Options


// Seen something like this?
var alert = new Alert("Error", message, "blue",
                      "white", "black", "error", true);
// Prefer this instead
var options = { titleColor: "blue", bgColor: "white",
                textColor: "black", icon: "error", modal: true }
var alert = new Alert("Error", message, options);
// How to do it
function Alert(title, message, opts) {
  // ...
  var defaultOpts = { ... };
  opts = $.extend(defaultOpts, opts || {});
  this = $.extend(this, opts);
}

HTML semantics


<article>For what you would syndicate</article>
<section>For things that belong together</section>
<div>Otherwise</div>

<aside>For related side content</aside>
<nav>For pure navigation links</nav>

<header>At the start of areas</header>
<footer>At the end</footer>

Doesn't work in IE8 and below, but you can use html5shiv.

CSS Architecture


SMACSS

OOCSS

BEM

SMACSS

Scalable and Modular Architecture for CSS


h1             /* Base   */

.l-line        /* Layout */

.mod-tooltip   /* Module */

.is-hidden     /* State  */

.highlight     /* Theme  */

OOCSS

Object-Oriented CSS


The Media object
screenshot of the media object
.media { margin: 10px; }
.media, .bd { overflow: hidden; _overflow: visible; zoom: 1; }
.media .img { float: left; margin-right: 10px; }
.media .img img { display: block; }
.media .imgExt{ float: right; margin-left: 10px; }

BEM

Blocks, Elements, and Modifiers

Blocks and Elements
Illustration of blocks and elements

Modifier
Illustration of modifier

CSS Specificity

Use classes, avoid elements, don't use ID's

Right to left!

inline style > external

Don't be overly specific
.intro
.main .intro  /* later */
.main p.intro  /* even later */
section.main p.intro  /* uhoh... */
article section.main p.intro  /* I GIVE UP! */
p.intro /* bad */
.intro  /* good */
.main .intro /* ok */
.main-intro  /* better */
.intro { border: none !important; } /* probably wrong! */

Design Patterns

in JavaScript

Patterns


  • Solves a particular problem
  • Does not have an obvious solution
  • Describes a proven concept
  • Describes a relationship

The Module Pattern


Enables private and public

Basic module


Not visible outside of scope function

(function () {

  var $title = $('article h1');
  var originalTitle = $title.text();

  var reverseString = function(s) {
    return s.split("").reverse().join("");
  }

  $title.text( reverseString(originalTitle) );

}());

Module-based class


var testModule = (function () {
  var privateVariable = 0;

  var privateFunction = function() { ... };

  return {
    publicFunction: function () { ... };
  };
})();

Revealing Module Pattern


var testModule = (function () {
  var privateVariable = 0;

  var privateFunction = function() { ... };

  var publicFunction = function() { ... };

  return {
    theFunction: publicFunction
  };
})();

Import modules


var testModule = (function ($, w, undefined) {
  // ...
})(jQuery, window);

Extend module


var testModule = (function ($) {

  $.newMethod = function() { ... };

})(jQuery = jQuery || {});

AMD, CommonJS, RequireJS, and ES Harmony


define(
  module_id /*optional*/, 
  [dependencies] /*optional*/, 
  definition function /*function for instantiating the module or object*/
);
define('myModule', // optional
  ['math', 'graph'], // optional
  function ( math, graph ) {
    var isReady = false, foobar;

    // note the inline require within our module definition
    require(['foo', 'bar'], function (foo, bar) {
        isReady = true;
        foobar = foo() + bar();
    });

    // Note that this is a slightly different pattern
    // With AMD, it's possible to define modules in a few
    // different ways due as it's relatively flexible with
    // certain aspects of the syntax
    return {
      plot: function(x, y){
        return graph.drawPie(math.randomGrid(x,y));
      }
    }
  };
});

Observer vs. Pub/Sub


Observer pattern


Publisher / Subscriber pattern

Observer pattern


Requires knowledge of the object that notifies


// observe
$('.myModule').bind('eventName', myCallback);

// notify
$('.myModule').trigger('eventName');

Publisher / Subscriber pattern


Uses 'channels' so no knowledge of origin is needed


// subscribe
$(document).on('namespace/eventName', myCallback); // put it on the root

// publish
$(document).trigger('eventName'); // doesn't matter much what element

Facade pattern


Limited abstractions of methods

Seen a lot in jQuery

$('.myClass').click(myCallback);
// same as
$('.myClass').on('click', myCallback);

Factory pattern


Generic interface for creating objects

Great when serializing

function Car() { ... };
function Truck() { ... };

function VehicleFactory() {};
VehicleFactory.prototype.createVehicle = function ( options ) {
  if( options.vehicleType === "car" )
    this.vehicleClass = Car;
  else
    this.vehicleClass = Truck;

  return new this.vehicleClass( options );
};

Somethings from a project

Some useful jQuery methods


github.com/seriema/jp.js

Missing and Exists


if ($('.aClass').exists())
  // do something
if ($('.someClass').missing())
  return;

Serialize form to object


var formData = $('form').serializeObject();
$.post(url, formData);

Manipulate URL parameters


// read
var sort = $.urlParam('sort');

// write
$.urlParam('sort', 'ascending');

Combine objects


var diff = $.difference(obj1, obj2);

var intersection = $.intersect(obj1, obj2);

var union = $.union(obj1, obj2);

var symDiff = $.symmetric(obj1, obj2);

Debug flag


Enable debug methods in your code

http://theproject:123/?debug=true
// page init, not included in production code
if ( urlParam('debug') === 'true' )
  MyLib.debug = true;

// then in your code
if ( MyLib.debug )
  // do stuff

Time functions

Expose debug functions

Check AJAX results

Enable offline-mode

Styling flags


http://theproject:123/?theme=summer

Switch CSS files with a flag

Highlight specific elements

Enable live edit

Components

Basic idea


Reusability

Encapsulated

No knowledge of outside components

Little knowledge of inside components

Basic "inheritance"

Example

Ajax action - tooltip input


<common:ajaxTooltipInput
  actionText="Create New group"
  inputName="userGroupName"
  inputText="New group name"
  postUrl="/api/groups/" />

Component example 1 Component example 2 Component example 3

Structure


One HTML file

One or zero CSS files

One or zero JS files


Follow a strict naming convention

Self-checking


The JS warns if needed elements are missing

The JS warns if the AJAX isn't as expected


Components - example of self check

Tips & tricks

Performance


Perceived performance

Optimize caching

Minimize round-trip times

Minimize request overhead

Minimize payload size

Optimize browser rendering

Performance tools


Test your page with:

Google Page Speed

Yahoo! YSlow

Webtestpage


Compress (lossless!) your images with Smush.it


Use the Network console and Profiler in Chrome dev tools

Pretend privacy

var myObj = {};
myObj._private = 'ssssh';

Cascade / Chaining


Return 'this' instead of 'undefined'

Chaining in jQuery


Typical (don't do this)

$('div.main-content').addClass('highlight');
$('div.main-content').click(onMainContentClick);

At least do this

var $mainContent = $('div.main-content');

$mainContent.addClass('highlight');
$mainContent.click(onMainContentClick);

Preferably use chaining

var $mainContent = $('div.main-content');

$mainContent.addClass('highlight').click(onMainContentClick);

How to do chaining


// taken from the actual jQuery source
jQuery.fn.extend({
  addClass: function( value ) {
    // ...

    return this;
  }
});

Promises

AKA deferred or future


Classical

$.getJSON(url, data, onDone);

Using promises

$.getJSON(url, data).done(onDone);

Do your own by calling jQuery.Deferred()

Do's and don'ts


No inline JavaScript

No inlince CSS

CSS on top, JS on bottom of the page

Consider font-icons

Consider image sprites

Use a reset.css or normalize.css

Optimize your images

Pick a coding style and stick with it

Keep URL's out of JS, use data-attributes in HTML if needed

A tip on responsive web design


Illustration of responsive web design

Design a handful of reflows, and stick to them.

Dev flow


The browser console


Fast feedback


Easy online checks

The browser console


<3 it


Not just console.log, use .dir and .error too


Quickly test your scripts


Verify JS behaviour

Fast feedback


Your changes should be instantly visible


Tools:

Easy online checks


Simple hosting - Dropbox with bit.ly

Online editors - CodePen or jsFiddle

Resources


Some videos,

a few frameworks,

and a bunch of books

JavaScript, wat?

Hilarious 4min presentation of JS uirkiness!


View it here.

50 performance tricks

to make your HTML5 apps and sites faster

Original

DOM, HTML5, & CSS3 Performance

Web Application Development Workflow

How Web Browsers Work

Original

Frameworks


Twitter Bootstrap


Zurb Foundation


HTML5 Boilerplate


Initializr

Books

book cover book cover book cover book cover book cover

the End?


Questions?


I got one: do you want a talk on functional programming?