81
Your JS Library Dan Webb AKA @danwrong Tuesday, May 3, 2011

Building Non-shit APIs with JavaScript

  • Upload
    danwrong

  • View
    12.560

  • Download
    1

Embed Size (px)

DESCRIPTION

As given at JSConf 2011.

Citation preview

Page 1: Building Non-shit APIs with JavaScript

Your JS LibraryDan Webb AKA @danwrong

Tuesday, May 3, 2011

Page 2: Building Non-shit APIs with JavaScript

Tuesday, May 3, 2011

Page 3: Building Non-shit APIs with JavaScript

In the beginning...

Tuesday, May 3, 2011

Page 4: Building Non-shit APIs with JavaScript

In the beginning...

Tuesday, May 3, 2011

Page 5: Building Non-shit APIs with JavaScript

$("p.surprise").addClass("ohmy").show("slow");

Tuesday, May 3, 2011

Page 6: Building Non-shit APIs with JavaScript

We all know what happened next...

jQuery

The Rest

Tuesday, May 3, 2011

Page 7: Building Non-shit APIs with JavaScript

Why?

Tuesday, May 3, 2011

Page 8: Building Non-shit APIs with JavaScript

Internals were not important...

Tuesday, May 3, 2011

Page 9: Building Non-shit APIs with JavaScript

...what had John created was a great interface

Tuesday, May 3, 2011

Page 10: Building Non-shit APIs with JavaScript

"All programmers are API designers"Joshua Bloch (http://lcsd05.cs.tamu.edu/slides/keynote.pdf)

Tuesday, May 3, 2011

Page 11: Building Non-shit APIs with JavaScript

The API is priority #1

Tuesday, May 3, 2011

Page 12: Building Non-shit APIs with JavaScript

❖ Predictability❖ Simplicity❖ Flexibility

Tuesday, May 3, 2011

Page 13: Building Non-shit APIs with JavaScript

Predictability

Tuesday, May 3, 2011

Page 14: Building Non-shit APIs with JavaScript

RTFMTuesday, May 3, 2011

Page 15: Building Non-shit APIs with JavaScript

Short attention spanTuesday, May 3, 2011

Page 16: Building Non-shit APIs with JavaScript

Think about your audience...

Tuesday, May 3, 2011

Page 17: Building Non-shit APIs with JavaScript

...use conventions people already know

Tuesday, May 3, 2011

Page 18: Building Non-shit APIs with JavaScript

Language conventions and standard library

Tuesday, May 3, 2011

Page 19: Building Non-shit APIs with JavaScript

THIS IS JAVASCRIPT

Tuesday, May 3, 2011

Page 20: Building Non-shit APIs with JavaScript

useCamelCase, yesReally.

Tuesday, May 3, 2011

Page 21: Building Non-shit APIs with JavaScript

Be careful with polyfills

Tuesday, May 3, 2011

Page 22: Building Non-shit APIs with JavaScript

Popular JS libraries

Tuesday, May 3, 2011

Page 23: Building Non-shit APIs with JavaScript

var paper = Raphael(10, 50, 320, 200);

var c = paper.circle(50, 40, 10);

c.attr("fill", "#f00");

c.show();

Tuesday, May 3, 2011

Page 24: Building Non-shit APIs with JavaScript

The problem domain

Tuesday, May 3, 2011

Page 25: Building Non-shit APIs with JavaScript

a.internal { color: #44e534; text-decoration: none;}

$('a.external').css({ color: '#44e534', textDecoration: 'none'});

Tuesday, May 3, 2011

Page 26: Building Non-shit APIs with JavaScript

Example: creating a DOM Builder

Tuesday, May 3, 2011

Page 27: Building Non-shit APIs with JavaScript

node.innerHTML = '<form method="post" action="/action">' + '<p>' + '<label>' + 'Username: <input type="text" name="username">' + '</label>' + '<label>' + 'Password: <input type="password" name="password">' + '</label>' + '</p>' + '</form>';

var form = document.createElement('form');var p = document.createElement('p');form.setAttribute('action', '/login');form.setAttribute('method', 'post');var usernameLabel = document.createElement('label');var usernameText = document.createTextElement('Username: ');var usernameInput = document.createElement('input');usernameInput.setAttribute('type', 'text');usernameInput.setAttribute('name', 'username');form.appendChild(p);p.appendChild(usernameLabel);// ... at this point I decided to give // all this up and become a farmer

Tuesday, May 3, 2011

Page 28: Building Non-shit APIs with JavaScript

var html = { element: function(name, attributes, children) { var node = document.createElement(name); for (var attr in attributes) { node.setAttribute(attr, attributes[attr]); } for (var i=0, len=children.length; i < len; i++) { node.appendChild(children[i]); } return node; }}

Tuesday, May 3, 2011

Page 29: Building Non-shit APIs with JavaScript

var form = html.element( 'form', { action: '/login', method: 'post' } [ html.element('p', {}, [ html.element('label', {}, [ document.createTextElement('Username: '), html.element('input', { type: 'text', name: 'username' }, []), // ... you get the idea ]) ]) ]);

Tuesday, May 3, 2011

Page 30: Building Non-shit APIs with JavaScript

var form = html.form({ action: '/login', method: 'post' }, [ html.p({}, [ html.label({}, [ document.createTextElement('Username: '), html.input({ type: 'text', name: 'username' }, []), // ... you still get the idea, right? ]) ]) ]);

Tuesday, May 3, 2011

Page 31: Building Non-shit APIs with JavaScript

function elementBuilder(name) { return function(attributes, children) { return html.element(name, attributes, children); }}

function generateBuilderFunctions(elements) { for (var i=0, len=elements.length; i < len; i++) { html[elements[i]] = createElementBuilder(elements[i]); }}

generateBuilderFunctions("p|div|span|strong|em|img|table|tr|td|th|thead|tbody|tfoot|pre|code|h1|h2|h3|h4|h5|h6|ul|ol|li|form|input|textarea|legend|fieldset|select|option|blockquote|cite|br|hr|dd|dl|dt|address|a|button|abbr|acronym|script|link|style|bdo|ins|del|object|param|col|colgroup|optgroup|caption|label|dfn|kbd|samp|var".split("|"));

Tuesday, May 3, 2011

Page 32: Building Non-shit APIs with JavaScript

Simplicity

Tuesday, May 3, 2011

Page 33: Building Non-shit APIs with JavaScript

Tuesday, May 3, 2011

Page 34: Building Non-shit APIs with JavaScript

Don’t make me RTFM again...

Tuesday, May 3, 2011

Page 35: Building Non-shit APIs with JavaScript

Sensible defaults

Tuesday, May 3, 2011

Page 36: Building Non-shit APIs with JavaScript

Tuesday, May 3, 2011

Page 37: Building Non-shit APIs with JavaScript

Tuesday, May 3, 2011

Page 38: Building Non-shit APIs with JavaScript

var evt = document.createEvent("MouseEvents");

evt.initMouseEvent("click", true, true, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null);

Tuesday, May 3, 2011

Page 39: Building Non-shit APIs with JavaScript

element.addEventListener('input', function() { // do some front-end magic}, false);

Tuesday, May 3, 2011

Page 40: Building Non-shit APIs with JavaScript

var evt = document.createEvent("MouseEvents");

evt.initMouseEvent("click", true, true, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null);

Tuesday, May 3, 2011

Page 41: Building Non-shit APIs with JavaScript

Use options hashes for optional arguments

Tuesday, May 3, 2011

Page 42: Building Non-shit APIs with JavaScript

evt.initMouseEvent("click", { bubble: false, relatedTarget: thing});

Tuesday, May 3, 2011

Page 44: Building Non-shit APIs with JavaScript

Function calls should read well

Tuesday, May 3, 2011

Page 45: Building Non-shit APIs with JavaScript

// replace oldNode with newNode - DOM API oldNode.parentNode.replaceChild(newNode, oldNode);

// Dojo dojo.place(newNode, oldNode, "replace");

// jQuery$(oldNode).replaceWith(newNode);

Tuesday, May 3, 2011

Page 46: Building Non-shit APIs with JavaScript

Mask complexity if possible

Tuesday, May 3, 2011

Page 47: Building Non-shit APIs with JavaScript

var con = xd.connect({ src: 'http://danwebb.net/receiver' });

con.bind('ready', function() { rpc(con).call('getData', function(result) { alert(result); });});

Tuesday, May 3, 2011

Page 48: Building Non-shit APIs with JavaScript

xd.connect({ src: 'http://danwebb.net/receiver' }, function(con) { rpc(con).call('getData', function(result) { alert(result); });});

Tuesday, May 3, 2011

Page 49: Building Non-shit APIs with JavaScript

var con = xd.connect({ src: 'http://danwebb.net/receiver' });

rpc(con).call('getData', function(result) { alert(result);});

Tuesday, May 3, 2011

Page 50: Building Non-shit APIs with JavaScript

Back to the DOM Builder

Tuesday, May 3, 2011

Page 51: Building Non-shit APIs with JavaScript

var form = html.form({ action: '/login', method: 'post' }, [ html.p({}, [ html.label({}, [ document.createTextElement('Username: '), html.input({ type: 'text', name: 'username' }, []), // ... you still get the idea, right? ]) ]) ]);

Tuesday, May 3, 2011

Page 52: Building Non-shit APIs with JavaScript

var form = html.form({ method: 'post', action: '/login' }, html.p( html.label( 'Username: ', html.input({ type: 'text', name: 'username' }) ), html.label( 'Password: ', html.input({ type: 'password', name: 'pass' }) ), html.input({ type: 'submit', value: 'Login'}) ));

Tuesday, May 3, 2011

Page 53: Building Non-shit APIs with JavaScript

function elementBuilder(name) { return function() { var attributes = {}, children = [], args = Array.prototype.slice.call(arguments);

// if the first arg is not a element or a string then its an attributes hash if (!args[0].nodeType && typeof args[0] != 'string') { attributes = args.unshift(); } // children can be an array or remaining args if (Array.isArray(args[0])) { args = args[0]; }

// add rest of args as children converting any strings to text nodes for (var i=0, len=args.length; i < len; i++) { if (typeof args[i] == 'string') { children.push(document.createTextNode(args[i])); } else { children.push(args[i]); } }

return html.element(name, attributes, children); }}

Tuesday, May 3, 2011

Page 54: Building Non-shit APIs with JavaScript

Flexibility

Tuesday, May 3, 2011

Page 55: Building Non-shit APIs with JavaScript

Tuesday, May 3, 2011

Page 56: Building Non-shit APIs with JavaScript

Tuesday, May 3, 2011

Page 57: Building Non-shit APIs with JavaScript

Tuesday, May 3, 2011

Page 58: Building Non-shit APIs with JavaScript

Remember: you can't please everyone

Tuesday, May 3, 2011

Page 59: Building Non-shit APIs with JavaScript

Don’t try to second guess every use case

Tuesday, May 3, 2011

Page 60: Building Non-shit APIs with JavaScript

Options hashes != flexibility

Tuesday, May 3, 2011

Page 61: Building Non-shit APIs with JavaScript

28 options!Tuesday, May 3, 2011

Page 62: Building Non-shit APIs with JavaScript

Add hackability

Tuesday, May 3, 2011

Page 63: Building Non-shit APIs with JavaScript

public, internal, protected

Tuesday, May 3, 2011

Page 64: Building Non-shit APIs with JavaScript

var lib = (function() { var private = function() { // you can't mess with me };

return { _internal: function() { // you probably shouldn't mess with me }, public: function() { // I'm part of the API - call me sometime } }}());

Tuesday, May 3, 2011

Page 65: Building Non-shit APIs with JavaScript

...using functions

Tuesday, May 3, 2011

Page 66: Building Non-shit APIs with JavaScript

// https://github.com/ender-js/Ender

$._select = function(selector, root) { return Sizzle(selector, root);}

$._select = function (selector, root) { return (root || document).querySelectorAll(selector);});

Tuesday, May 3, 2011

Page 67: Building Non-shit APIs with JavaScript

..inheritance

Tuesday, May 3, 2011

Page 68: Building Non-shit APIs with JavaScript

// github.com/danwrong/loadrunner

function Mustache(path) { this.path = path;}Mustache.prototype = new loadrunner.Dependency;Mustache.prototype.start = function() { var me = this; $.get(this.path, function(result) { var template = Mustache.parse(result); me.complete(template); });}

using(new Mustache('thing.mustache'), function(template) { template.evaluate({ a: 'yep', b: 'nope' });});

Tuesday, May 3, 2011

Page 69: Building Non-shit APIs with JavaScript

..duck typing

Tuesday, May 3, 2011

Page 70: Building Non-shit APIs with JavaScript

Meanwhile, back in DOM Builder land...

Tuesday, May 3, 2011

Page 71: Building Non-shit APIs with JavaScript

function elementBuilder(name) { return function() { // code collapsed for clarity

// add rest of args as children // converting any strings to text nodes for (var i=0, len=args.length; i < len; i++) { if (typeof args[i] == 'string') { node = document.createTextNode(args[i]); } else { if (typeof args[i].toDOM == 'function') { node = args[i].toDOM(); } else { node = args[i]; } }

children.push(node); }

return html.element(name, attributes, children); }}

Tuesday, May 3, 2011

Page 72: Building Non-shit APIs with JavaScript

function Tweet(text, author, timestamp) { this.text = text; this.author = author; this.timestamp = timestamp;}Tweet.prototype.toDOM = function() { return html.p( { 'class': 'tweet' }, html.strong(this.author.name), this.text, html.span({ 'class': 'time' }, this.timestamp) );}

var timeline = // an array of Tweet objects

document.appendChild(html.div({ id: 'timeline' }, timeline));

Tuesday, May 3, 2011

Page 73: Building Non-shit APIs with JavaScript

Create a framework for solving your problem...

Tuesday, May 3, 2011

Page 74: Building Non-shit APIs with JavaScript

...then build your library on top of that

Tuesday, May 3, 2011

Page 75: Building Non-shit APIs with JavaScript

You got yourself a plugin system

Tuesday, May 3, 2011

Page 76: Building Non-shit APIs with JavaScript

Build tools to solve the problem

Tuesday, May 3, 2011

Page 77: Building Non-shit APIs with JavaScript

❖ Design up front❖ Make use of conventions❖ Don’t make me think❖ Build in hackability

Tuesday, May 3, 2011

Page 78: Building Non-shit APIs with JavaScript

Questions?@danwrong

Tuesday, May 3, 2011

Page 79: Building Non-shit APIs with JavaScript

@jointheflocktwitter.com/[email protected]

Tuesday, May 3, 2011

Page 80: Building Non-shit APIs with JavaScript

Eye of the BeholderTuesday, May 3, 2011

Page 81: Building Non-shit APIs with JavaScript

ChainingTuesday, May 3, 2011