Secrets of Awesome JavaScript API Design

Secrets of Awesome JavaScript API Design

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.

2411e1b8fa28ddd0c8071dc4aec1c5a1?s=128

Brandon Satrom

May 23, 2013
Tweet

Transcript

  1. 6.
  2. 7.

    Three ideas... 1.APIs are “Developer UX” 2.API Design is a

    universal practice 3.API Design is a “principle-driven” art form Friday, May 24, 13
  3. 9.

    What is design? “form[ing] a plan or scheme of [some

    thing]… for later execution” - Oxford English Dictionary Friday, May 24, 13
  4. 11.

    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/ Friday, May 24, 13
  5. 12.

    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/ Friday, May 24, 13
  6. 13.

    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/ Friday, May 24, 13
  7. 14.

    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/ Friday, May 24, 13
  8. 15.

    “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 Friday, May 24, 13
  9. 17.

    We call this practice, User Experience (UX) design... Images from:

    http://pinterest.com/fromupnorth/gui/ Friday, May 24, 13
  10. 35.

    In Industrial Design, this is NOT an acceptable answer... Image

    from: http://idratherbewriting.com/wp-content/uploads/2012/08/rtfmtractor.jpg Friday, May 24, 13
  11. 44.

    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; } Friday, May 24, 13
  12. 45.

    Goals of API Design Be Self-Describing Prevent Errors Make Users

    Fast Image from: http://elliottbrown.files.wordpress.com/2012/04/sandcastles.png Friday, May 24, 13
  13. 51.

    Principles, not Rules Rules are rote, often applied without context

    Principles encourage application of context Friday, May 24, 13
  14. 53.

    Principles on display in popular libraries... Backbone jQuery Kendo UI

    Modernizr Moment.js Underscore Friday, May 24, 13
  15. 56.

    Unity and Harmony Image “Portrait of the children of Charles

    I” by Anthony Van Dyck from: http://char.txa.cornell.edu/language/principl/principl.htm Friday, May 24, 13
  16. 57.

    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 Friday, May 24, 13
  17. 58.

    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 Friday, May 24, 13
  18. 59.

    Example: Create Kendo UI Widgets from jQuery-selected DOM Elements $("ul.tree").kendoTreeView();

    $("ul.panel").kendoPanelBar(); $("div").kendoGrid(); Friday, May 24, 13
  19. 60.

    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(); Friday, May 24, 13
  20. 61.

    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()  {  ...  } }); Friday, May 24, 13
  21. 62.

    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()  {  ...  } }); Friday, May 24, 13
  22. 63.

    Balance Image “Portrait of the children of Charles I” by

    Anthony Van Dyck from: http://char.txa.cornell.edu/language/principl/principl.htm Friday, May 24, 13
  23. 64.

    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 Friday, May 24, 13
  24. 65.

    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. Friday, May 24, 13
  25. 67.

    Example: Modernizr.geolocation Modernizr.localstorage Modernizr.webworkers Modernizr.canvas Modernizr.borderradius Test Browser Capabilities using

    Modernizr Each property matches an HTML5/CSS-related API and returns a boolean Friday, May 24, 13
  26. 68.

    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 Friday, May 24, 13
  27. 69.

    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 Friday, May 24, 13
  28. 71.

    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 Friday, May 24, 13
  29. 72.

    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. Friday, May 24, 13
  30. 73.

    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 2013 moment().startOf('day').fromNow(); Friday, May 24, 13
  31. 74.

    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 2013 moment().startOf('day').fromNow(); Friday, May 24, 13
  32. 75.

    _.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 Friday, May 24, 13
  33. 76.

    _.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. Friday, May 24, 13
  34. 78.

    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 Friday, May 24, 13
  35. 79.

    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 Friday, May 24, 13
  36. 80.

    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’); Friday, May 24, 13
  37. 81.

    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’); Friday, May 24, 13
  38. 82.

    (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... Friday, May 24, 13
  39. 83.

    (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 Friday, May 24, 13
  40. 84.

    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 Friday, May 24, 13
  41. 85.

    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 Friday, May 24, 13
  42. 92.

    Inconsistency... var  letters  =  [“a”,  “b”,  “c”,  “d”,  “e”]; $.each(letters,

     function(index,  val)  {    console.log(index  +  “:  “  +  val.toUpperCase()); Callback signatures on $.map, $.each & $(el).map Friday, May 24, 13
  43. 93.

    Inconsistency... var  letters  =  [“a”,  “b”,  “c”,  “d”,  “e”]; $.each(letters,

     function(index,  val)  {    console.log(index  +  “:  “  +  val.toUpperCase()); });   Callback signatures on $.map, $.each & $(el).map Friday, May 24, 13
  44. 94.

    Inconsistency... var  letters  =  [“a”,  “b”,  “c”,  “d”,  “e”]; $.each(letters,

     function(index,  val)  {    console.log(index  +  “:  “  +  val.toUpperCase()); });   Callback signatures on $.map, $.each & $(el).map Friday, May 24, 13
  45. 95.

    Inconsistency... 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 Friday, May 24, 13
  46. 96.

    Inconsistency... 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 Friday, May 24, 13
  47. 97.

    Inconsistency... 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 Friday, May 24, 13
  48. 98.

    Inconsistency... 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 Friday, May 24, 13
  49. 99.

    Inconsistency... 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. Friday, May 24, 13
  50. 107.

    jQuery(  selector  [,  context]  )  //  Select jQuery(  element  )

     //  Wrap Overloads on the jQuery() method... Friday, May 24, 13
  51. 108.

    jQuery(  selector  [,  context]  )  //  Select jQuery(  element  )

     //  Wrap jQuery(  object  )  //  Wrap Overloads on the jQuery() method... Friday, May 24, 13
  52. 109.

    jQuery(  selector  [,  context]  )  //  Select jQuery(  element  )

     //  Wrap jQuery(  object  )  //  Wrap jQuery()  //  Empty  $  Object Overloads on the jQuery() method... Friday, May 24, 13
  53. 110.

    jQuery(  selector  [,  context]  )  //  Select jQuery(  element  )

     //  Wrap jQuery(  object  )  //  Wrap jQuery()  //  Empty  $  Object jQuery(  elementArray  )  //  Wrap Overloads on the jQuery() method... Friday, May 24, 13
  54. 111.

    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... Friday, May 24, 13
  55. 112.

    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... Friday, May 24, 13
  56. 113.

    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... Friday, May 24, 13
  57. 114.

    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... Friday, May 24, 13
  58. 115.

    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! Friday, May 24, 13
  59. 116.

    Building and evolving a useful API is hard... Image from:

    http://www.ibiblio.org/xml/slides/xmlone/london2002/schemas/83.html Friday, May 24, 13
  60. 119.

    ... so you don’t have to be either. But hey,

    jQuery’s not perfect... Friday, May 24, 13
  61. 120.

    What are we building anyway? Image of Fred Brooks from:

    http://www-set.win.tue.nl/UnsungHeroes/files/PTERA-Kosten-Poel.jpg Friday, May 24, 13
  62. 123.

    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...” Friday, May 24, 13
  63. 125.

    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 Friday, May 24, 13