Secrets of Awesome JavaScript API Design

132
Secrets of Awesome JavaScript API Design Brandon Satrom @BrandonSatrom [email protected]

description

As developers, we know what good and bad JavaScript APIs "feel" like, and yet we struggle with designing the kind of APIs that we enjoy using. But principles of good JavaScript API design do exist, and it's possible to extract them from several key libraries in the the proliferating JavaScript landscape. In this session, Brandon Satrom will do exactly that, digging into the design aspects of popular libraries like jQuery, Backbone, Knockout, Modernizer, Kendo UI and others to enumerate the designed-in qualities of these libraries that make them not only popular, but a pleasure to use.

Transcript of Secrets of Awesome JavaScript API Design

Page 1: Secrets of Awesome JavaScript API Design

Secrets of Awesome JavaScript API Design

Brandon Satrom@BrandonSatrom

[email protected]

Page 2: Secrets of Awesome JavaScript API Design

Read it @ bit.ly/ZS5VYv

Page 3: Secrets of Awesome JavaScript API Design

3 Big Ideas

Page 4: Secrets of Awesome JavaScript API Design

Three ideas...

Page 5: Secrets of Awesome JavaScript API Design

Three ideas...

1.APIs are “Developer UX”

Page 6: Secrets of Awesome JavaScript API Design

Three ideas...

1.APIs are “Developer UX”

2.API Design is a universal practice

Page 7: Secrets of Awesome JavaScript API Design

Three ideas...

1.APIs are “Developer UX”

2.API Design is a universal practice

3.API Design is a “principle-driven” art form

Page 8: Secrets of Awesome JavaScript API Design

What is design?

Page 9: Secrets of Awesome JavaScript API Design

What is design?

“form[ing] a plan or scheme of [some thing]… for later execution”

- Oxford English Dictionary

Page 10: Secrets of Awesome JavaScript API Design

Design is universal

Page 11: Secrets of Awesome JavaScript API Design

We judge designs to be...

...elegant

...beautiful

...utilitarian

...simple

...or not...Images from: http://www.greatbuildings.com/ and http://list25.com/25-ugliest-buildings-in-the-world/

Page 12: Secrets of Awesome JavaScript API Design

We judge designs to be...

...elegant

...beautiful

...utilitarian

...simple

...or not...Images from: http://www.greatbuildings.com/ and http://list25.com/25-ugliest-buildings-in-the-world/

Page 13: Secrets of Awesome JavaScript API Design

We judge designs to be...

...elegant

...beautiful

...utilitarian

...simple

...or not...Images from: http://www.greatbuildings.com/ and http://list25.com/25-ugliest-buildings-in-the-world/

Page 14: Secrets of Awesome JavaScript API Design

We judge designs to be...

...elegant

...beautiful

...utilitarian

...simple

...or not...Images from: http://www.greatbuildings.com/ and http://list25.com/25-ugliest-buildings-in-the-world/

Page 15: Secrets of Awesome JavaScript API Design

“Mediocre design provably wastes the world’s resources, corrupts the environment, affects international

competitiveness. Design is important, teaching design is

important.”

- Fred Brooks

Image of Fred Brooks from: http://en.wikipedia.org/wiki/File:Fred_Brooks.jpg

Poor Design is Costly

Page 16: Secrets of Awesome JavaScript API Design

We apply design practices to User Interfaces...

Images from: http://pinterest.com/fromupnorth/gui/

Page 17: Secrets of Awesome JavaScript API Design

We call this practice, User Experience (UX)

design...Images from: http://pinterest.com/fromupnorth/gui/

Page 18: Secrets of Awesome JavaScript API Design

What about API Design?

Page 19: Secrets of Awesome JavaScript API Design

API Design is “Developer UX”

Page 20: Secrets of Awesome JavaScript API Design

API Design is not JUST For Library Authors...

Page 21: Secrets of Awesome JavaScript API Design

...modular JS is written to be consumed...

Page 23: Secrets of Awesome JavaScript API Design

In JavaScript, API design is critically important...

Page 24: Secrets of Awesome JavaScript API Design

Dynamic Language...

Page 25: Secrets of Awesome JavaScript API Design

Anonymity of consumers...

http://i.qkme.me/3qesq1.jpg

Page 26: Secrets of Awesome JavaScript API Design

Ambiguity of Requirements...

Page 27: Secrets of Awesome JavaScript API Design

Your users are smart...

Page 30: Secrets of Awesome JavaScript API Design

A Tale of Ice & Water

Page 31: Secrets of Awesome JavaScript API Design

A Tale of Ice & Water

Page 32: Secrets of Awesome JavaScript API Design

A Tale of Ice & Water

Page 33: Secrets of Awesome JavaScript API Design

A Tale of Ice & Water

Page 34: Secrets of Awesome JavaScript API Design

A Tale of Ice & Water

Page 38: Secrets of Awesome JavaScript API Design
Page 39: Secrets of Awesome JavaScript API Design

Your users are smart...

Page 43: Secrets of Awesome JavaScript API Design

Example:

$("article.blogPost").fadeIn();

Use jQuery to select all article tags with the class “blogPost”

Page 44: Secrets of Awesome JavaScript API Design

Example:

$("article.blogPost").fadeIn();

Use jQuery to select all article tags with the class “blogPost”

article.blogPost  {    border-­‐radius:  10px;    background-­‐color:  salmon;    box-­‐shadow:  0px  0px  10px  2px  #ccc;}

Page 46: Secrets of Awesome JavaScript API Design
Page 47: Secrets of Awesome JavaScript API Design

Goals are not enough...

Page 48: Secrets of Awesome JavaScript API Design
Page 49: Secrets of Awesome JavaScript API Design

...we need guiding principles...

Page 50: Secrets of Awesome JavaScript API Design

Principles, not Rules

Page 51: Secrets of Awesome JavaScript API Design

Principles, not Rules

Rules are rote, often applied without context

Principles encourage application of context

Page 53: Secrets of Awesome JavaScript API Design

Principles on display in popular libraries...

Backbone

jQuery

Kendo UI

Modernizr

Moment.js

Underscore

Page 54: Secrets of Awesome JavaScript API Design

The Four Principles

Unity & Harmony

Balance

Proportion

Emphasis

Page 55: Secrets of Awesome JavaScript API Design

WARNING! This is ART, not SCIENCE

Page 57: Secrets of Awesome JavaScript API Design

Unity and Harmony (art)

Unity: The concept behind a work, or how the composer brings everything together into a coherent whole.

Harmony: The placement of similar elements throughout a work, yielding an uncomplicated and simple feel.

Painting by Robert Delauny, from: http://char.txa.cornell.edu/language/principl/principl.htm

Page 58: Secrets of Awesome JavaScript API Design

Unity & Harmony (API Design):Familiarity & Comfort

Extended Object creation in Backbone

Widget Instantiation in Kendo UI

Use similar and/or unifying elements through your library to create familiarity and comfort

Page 59: Secrets of Awesome JavaScript API Design

Example: Create Kendo UI Widgets from jQuery-selected DOM Elements

$("ul.tree").kendoTreeView();

$("ul.panel").kendoPanelBar();

$("div").kendoGrid();

Page 60: Secrets of Awesome JavaScript API Design

Example: Create Kendo UI Widgets from jQuery-selected DOM Elements

Each Widget is prefixed with “kendo” and named in a consistent, camel-cased style

$("ul.tree").kendoTreeView();

$("ul.panel").kendoPanelBar();

$("div").kendoGrid();

Page 61: Secrets of Awesome JavaScript API Design

Example: Create Extended Objects with Backbone

var  Book  =  Backbone.Model.extend({    initialize:  function()  {  ...  },    author:  function()  {  ...  },    pubDate:  function()  {  ...  },});

var  DocumentRow  =  Backbone.View.extend({    tagName:  "li",    className:  "row",    events:  {        "click  .icon":  "open",        "click  .button.edit":  "openEditDialog"    },    render:  function()  {  ...  }});

Page 62: Secrets of Awesome JavaScript API Design

Example: Create Extended Objects with Backbone

[Object].extend is used to “inherit” the built-in functionality of Backbone Models, Views, Collections and Routers

var  Book  =  Backbone.Model.extend({    initialize:  function()  {  ...  },    author:  function()  {  ...  },    pubDate:  function()  {  ...  },});

var  DocumentRow  =  Backbone.View.extend({    tagName:  "li",    className:  "row",    events:  {        "click  .icon":  "open",        "click  .button.edit":  "openEditDialog"    },    render:  function()  {  ...  }});

Page 64: Secrets of Awesome JavaScript API Design

Balance (art)

The arrangement of elements to ensure that no one part of the work overpowers other parts, or causes it to feel unstable.

Image of Italian Textile, 18th Centuty from: http://char.txa.cornell.edu/language/principl/principl.htm

Page 65: Secrets of Awesome JavaScript API Design

Balance (API Design):Weight & Predictability

Browser Feature Tests in Modernizr

DOM Selection Syntax in jQuery

Ensure that each function of your library exhibits consistent behavior, or aids in meeting a complimentary goal.

Page 66: Secrets of Awesome JavaScript API Design

Example:

Modernizr.geolocationModernizr.localstorageModernizr.webworkersModernizr.canvasModernizr.borderradius

Test Browser Capabilities using Modernizr

Page 67: Secrets of Awesome JavaScript API Design

Example:

Modernizr.geolocationModernizr.localstorageModernizr.webworkersModernizr.canvasModernizr.borderradius

Test Browser Capabilities using Modernizr

Each property matches an HTML5/CSS-related API and returns a boolean

Page 68: Secrets of Awesome JavaScript API Design

Example:

$("#grid")  //  Selects  by  ID

$("ul.nav  >  li")  //  All  LIs  for  UL  w/class  "nav"

$("ul  li:nth-­‐child(2)")  //  2nd  item  in  each  list

Select DOM Elements using jQuery’s Selector Syntax

Page 69: Secrets of Awesome JavaScript API Design

Example:

$("#grid")  //  Selects  by  ID

$("ul.nav  >  li")  //  All  LIs  for  UL  w/class  "nav"

$("ul  li:nth-­‐child(2)")  //  2nd  item  in  each  list

Select DOM Elements using jQuery’s Selector Syntax

Many jQuery Selectors map directly to equivalent CSS selectors

Page 71: Secrets of Awesome JavaScript API Design

Proportion (art)

A measurement of the size and quantity of elements within a work, relative to the whole.

Image of Salisbury Cathedral from: http://char.txa.cornell.edu/language/principl/principl.htm

Page 72: Secrets of Awesome JavaScript API Design

Proportion (API Design):Scope that matches capability

Moment.js

Underscore

Make sure that every interface of the library matches its intended purpose & that no extraneous elements exist.

Page 73: Secrets of Awesome JavaScript API Design

Example: Moment.js is working working with dates... and that’s it

moment().format('dddd');moment().startOf('hour').fromNow();moment().format('[Hello from] YYYY'); // Hello from 2013moment().startOf('day').fromNow();

Page 74: Secrets of Awesome JavaScript API Design

Example: Moment.js is working working with dates... and that’s it

Moment is designed to make working with the JavaScript Date object tolerable, and it provides no functionality beyond that scope.

moment().format('dddd');moment().startOf('hour').fromNow();moment().format('[Hello from] YYYY'); // Hello from 2013moment().startOf('day').fromNow();

Page 75: Secrets of Awesome JavaScript API Design

_.each(["Todd",  "Burke",  "Derick"],  function(name){      alert(name);  });

_.map([1,  2,  3],  function(num){      return  num  *  3;  });

_.isNumber("ten");  //  False

Example: Underscore.js, designed to add functional programming support to JS

Page 76: Secrets of Awesome JavaScript API Design

_.each(["Todd",  "Burke",  "Derick"],  function(name){      alert(name);  });

_.map([1,  2,  3],  function(num){      return  num  *  3;  });

_.isNumber("ten");  //  False

Example: Underscore.js, designed to add functional programming support to JS

Underscore provides utility functions that help devs work with JS collections, arrays, functions and objects. Larger API surface, for a broader purpose.

Page 77: Secrets of Awesome JavaScript API Design

Emphasis

Image of the FlatIron Building from: http://www.greatbuildings.com/

Page 78: Secrets of Awesome JavaScript API Design

Emphasis (art)

The point of focus or interruption of a work. The use of contrast to cause an aspect of the work to stand out and capture the viewer’s

attention.

Image from: http://char.txa.cornell.edu/language/principl/principl.htm

Page 79: Secrets of Awesome JavaScript API Design

Emphasis (API Design):Creating a focal point

Plugin development using jQuery’s fn namespace

Method chaining in jQuery

Object extensibility in Backbone

Provide a gateway method that anchors your library, a chained or fluent API, or create extensibility hooks for consuming devs

Page 80: Secrets of Awesome JavaScript API Design

Example: jQuery enables a fluent programming style by returning a jQuery object from most functions.

$(‘ul.first’).find(‘.overdue’)    .css(‘background-­‐color’,‘red’)    .end()    .find(‘.due-­‐soon’)    .css(‘background-­‐color’,  ‘yellow’);

Page 81: Secrets of Awesome JavaScript API Design

Example: jQuery enables a fluent programming style by returning a jQuery object from most functions.

This style enables devs to accomplish a great deal of work in a terse, yet readable manner.

$(‘ul.first’).find(‘.overdue’)    .css(‘background-­‐color’,‘red’)    .end()    .find(‘.due-­‐soon’)    .css(‘background-­‐color’,  ‘yellow’);

Page 82: Secrets of Awesome JavaScript API Design

(function($)  {    $.fn.kittehfy  =  function()  {        return  this.each(function(idx,  el)  {                            var  width  =  el.width,                height  =  el.height;            var  src=  "http://placekitten.com/";            el.src=  src  +  width  +  "/"  +  height;        });    };})(jQuery);

$("img").kittehfy();

Example: jQuery plugins are connected to jQuery via the fn (“effin”) namespace...

Page 83: Secrets of Awesome JavaScript API Design

(function($)  {    $.fn.kittehfy  =  function()  {        return  this.each(function(idx,  el)  {                            var  width  =  el.width,                height  =  el.height;            var  src=  "http://placekitten.com/";            el.src=  src  +  width  +  "/"  +  height;        });    };})(jQuery);

$("img").kittehfy();

Example: jQuery plugins are connected to jQuery via the fn (“effin”) namespace...

jQuery Plugins “feel” like natural extensions to jQuery itself, and behave in similar ways

Page 84: Secrets of Awesome JavaScript API Design

Example:

   var  Book  =  Backbone.Model.extend({        initialize:  function()  {  ...  },    author:  function()  {  ...  },    pubDate:  function()  {  ...  },});

var  DocumentRow  =  Backbone.View.extend({    tagName:  "li",    className:  "row",    events:  {        "click  .icon":  "open",        "click  .button.edit":  "openEditDialog"    },    render:  function()  {  ...  }});

Create Extended Objects with Backbone

Page 85: Secrets of Awesome JavaScript API Design

Example:

   var  Book  =  Backbone.Model.extend({        initialize:  function()  {  ...  },    author:  function()  {  ...  },    pubDate:  function()  {  ...  },});

var  DocumentRow  =  Backbone.View.extend({    tagName:  "li",    className:  "row",    events:  {        "click  .icon":  "open",        "click  .button.edit":  "openEditDialog"    },    render:  function()  {  ...  }});

Create Extended Objects with Backbone

[Object].extend is used to “inherit” the built-in functionality of Backbone Models, Views, Collections and Routers

Page 86: Secrets of Awesome JavaScript API Design

The Four Principles

Unity & Harmony

Balance

Proportion

Emphasis

Page 87: Secrets of Awesome JavaScript API Design

The HORROR!aka What might go wrong...

Page 88: Secrets of Awesome JavaScript API Design

What might go wrong...

Inconsistency Disproportionality

Page 89: Secrets of Awesome JavaScript API Design

Imbalance...Callback signatures on $.map, $.each & $(el).map

Page 90: Secrets of Awesome JavaScript API Design

Imbalance...Callback signatures on $.map, $.each & $(el).map

Page 91: Secrets of Awesome JavaScript API Design

Imbalance...

var  letters  =  [“a”,  “b”,  “c”,  “d”,  “e”];

Callback signatures on $.map, $.each & $(el).map

Page 92: Secrets of Awesome JavaScript API Design

Imbalance...

var  letters  =  [“a”,  “b”,  “c”,  “d”,  “e”];$.each(letters,  function(index,  val)  {    console.log(index  +  “:  “  +  val.toUpperCase());

Callback signatures on $.map, $.each & $(el).map

Page 93: Secrets of Awesome JavaScript API Design

Imbalance...

var  letters  =  [“a”,  “b”,  “c”,  “d”,  “e”];$.each(letters,  function(index,  val)  {    console.log(index  +  “:  “  +  val.toUpperCase());});  

Callback signatures on $.map, $.each & $(el).map

Page 94: Secrets of Awesome JavaScript API Design

Imbalance...

var  letters  =  [“a”,  “b”,  “c”,  “d”,  “e”];$.each(letters,  function(index,  val)  {    console.log(index  +  “:  “  +  val.toUpperCase());});  

Callback signatures on $.map, $.each & $(el).map

Page 95: Secrets of Awesome JavaScript API Design

Imbalance...

var  letters  =  [“a”,  “b”,  “c”,  “d”,  “e”];$.each(letters,  function(index,  val)  {    console.log(index  +  “:  “  +  val.toUpperCase());});  

var  uppers  =  $.map(letters,  function(val,  index)  {    return  (val.toUpperCase());

Callback signatures on $.map, $.each & $(el).map

Page 96: Secrets of Awesome JavaScript API Design

Imbalance...

var  letters  =  [“a”,  “b”,  “c”,  “d”,  “e”];$.each(letters,  function(index,  val)  {    console.log(index  +  “:  “  +  val.toUpperCase());});  

var  uppers  =  $.map(letters,  function(val,  index)  {    return  (val.toUpperCase());});

Callback signatures on $.map, $.each & $(el).map

Page 97: Secrets of Awesome JavaScript API Design

Imbalance...

var  letters  =  [“a”,  “b”,  “c”,  “d”,  “e”];$.each(letters,  function(index,  val)  {    console.log(index  +  “:  “  +  val.toUpperCase());});  

var  uppers  =  $.map(letters,  function(val,  index)  {    return  (val.toUpperCase());});

Callback signatures on $.map, $.each & $(el).map

Page 98: Secrets of Awesome JavaScript API Design

Imbalance...

var  letters  =  [“a”,  “b”,  “c”,  “d”,  “e”];$.each(letters,  function(index,  val)  {    console.log(index  +  “:  “  +  val.toUpperCase());});  

var  uppers  =  $.map(letters,  function(val,  index)  {    return  (val.toUpperCase());});

$(‘li’).map(function(index,  val)  {  //WAT  });

Callback signatures on $.map, $.each & $(el).map

Page 99: Secrets of Awesome JavaScript API Design

Imbalance...

var  letters  =  [“a”,  “b”,  “c”,  “d”,  “e”];$.each(letters,  function(index,  val)  {    console.log(index  +  “:  “  +  val.toUpperCase());});  

var  uppers  =  $.map(letters,  function(val,  index)  {    return  (val.toUpperCase());});

$(‘li’).map(function(index,  val)  {  //WAT  });

Callback signatures on $.map, $.each & $(el).map

Not only do $.map and $.each diverge, but $.map and $(el).map order the callback params differently, depending on how the method is called.

Page 100: Secrets of Awesome JavaScript API Design

Proportion: Too Large or Too Small...

Page 103: Secrets of Awesome JavaScript API Design

Image of Fred Brooks from: http://www-set.win.tue.nl/UnsungHeroes/files/PTERA-Kosten-Poel.jpg

“... Every instruction carried out the same operation. He demonstrated the sufficiency of his operation—his machine could do anything any other computer could do...”

Page 105: Secrets of Awesome JavaScript API Design

Image of Fred Brooks from: http://www-set.win.tue.nl/UnsungHeroes/files/PTERA-Kosten-Poel.jpg

“...the delight that came from using it was similar to... working out a crossword puzzle—a construct of intentional complexity and no intended utility.”

- Fred Brooks

Page 106: Secrets of Awesome JavaScript API Design

AwesomeLib.do(prams);

Page 107: Secrets of Awesome JavaScript API Design

AwesomeLib.do(prams);

We can all agree that this is bad

Page 108: Secrets of Awesome JavaScript API Design

jQuery();

Page 109: Secrets of Awesome JavaScript API Design

jQuery();

Then, so is this...

Page 110: Secrets of Awesome JavaScript API Design

Overloads on the jQuery() method...

Page 111: Secrets of Awesome JavaScript API Design

jQuery(  selector  [,  context]  )  //  Select

Overloads on the jQuery() method...

Page 112: Secrets of Awesome JavaScript API Design

jQuery(  selector  [,  context]  )  //  Select

jQuery(  element  )  //  Wrap

Overloads on the jQuery() method...

Page 113: Secrets of Awesome JavaScript API Design

jQuery(  selector  [,  context]  )  //  Select

jQuery(  element  )  //  Wrap

jQuery(  object  )  //  Wrap

Overloads on the jQuery() method...

Page 114: Secrets of Awesome JavaScript API Design

jQuery(  selector  [,  context]  )  //  Select

jQuery(  element  )  //  Wrap

jQuery(  object  )  //  Wrap

jQuery()  //  Empty  $  Object

Overloads on the jQuery() method...

Page 115: Secrets of Awesome JavaScript API Design

jQuery(  selector  [,  context]  )  //  Select

jQuery(  element  )  //  Wrap

jQuery(  object  )  //  Wrap

jQuery()  //  Empty  $  Object

jQuery(  elementArray  )  //  Wrap

Overloads on the jQuery() method...

Page 116: Secrets of Awesome JavaScript API Design

jQuery(  selector  [,  context]  )  //  Select

jQuery(  element  )  //  Wrap

jQuery(  object  )  //  Wrap

jQuery()  //  Empty  $  Object

jQuery(  elementArray  )  //  Wrap

jQuery(    jQuery  object  )  //  Clone

Overloads on the jQuery() method...

Page 117: Secrets of Awesome JavaScript API Design

jQuery(  selector  [,  context]  )  //  Select

jQuery(  element  )  //  Wrap

jQuery(  object  )  //  Wrap

jQuery()  //  Empty  $  Object

jQuery(  elementArray  )  //  Wrap

jQuery(    jQuery  object  )  //  Clone

jQuery(  html  [,  ownerDocument  ]  )  //  Create  DOM  Elements

Overloads on the jQuery() method...

Page 118: Secrets of Awesome JavaScript API Design

jQuery(  selector  [,  context]  )  //  Select

jQuery(  element  )  //  Wrap

jQuery(  object  )  //  Wrap

jQuery()  //  Empty  $  Object

jQuery(  elementArray  )  //  Wrap

jQuery(    jQuery  object  )  //  Clone

jQuery(  html  [,  ownerDocument  ]  )  //  Create  DOM  Elements

jQuery  (  html,  props  )  //  Create  DOM  Elements

Overloads on the jQuery() method...

Page 119: Secrets of Awesome JavaScript API Design

jQuery(  selector  [,  context]  )  //  Select

jQuery(  element  )  //  Wrap

jQuery(  object  )  //  Wrap

jQuery()  //  Empty  $  Object

jQuery(  elementArray  )  //  Wrap

jQuery(    jQuery  object  )  //  Clone

jQuery(  html  [,  ownerDocument  ]  )  //  Create  DOM  Elements

jQuery  (  html,  props  )  //  Create  DOM  Elements

jQuery  (  callback  )  //  Bind  DOM  loaded  function  

Overloads on the jQuery() method...

Page 120: Secrets of Awesome JavaScript API Design

jQuery(  selector  [,  context]  )  //  Select

jQuery(  element  )  //  Wrap

jQuery(  object  )  //  Wrap

jQuery()  //  Empty  $  Object

jQuery(  elementArray  )  //  Wrap

jQuery(    jQuery  object  )  //  Clone

jQuery(  html  [,  ownerDocument  ]  )  //  Create  DOM  Elements

jQuery  (  html,  props  )  //  Create  DOM  Elements

jQuery  (  callback  )  //  Bind  DOM  loaded  function  

Overloads on the jQuery() method...

11 ways to call jQuery, with 6 different contexts!

Page 121: Secrets of Awesome JavaScript API Design

Now, for a question...

Page 125: Secrets of Awesome JavaScript API Design
Page 126: Secrets of Awesome JavaScript API Design

YES

Page 130: Secrets of Awesome JavaScript API Design

But hey, jQuery’s not perfect...

Page 131: Secrets of Awesome JavaScript API Design

... so you don’t have to be either.