Design is about communication.
There are tons of ways of telling the same thing.
But some ways say better than others.
What do you prefer?
glBegin (GL_TRIANGLES);
glVertex (0,0,0);
glVertex (1,1,0);
glVertex (2,0,0);
glEnd ();
v = &buffer.vertexes[0];
v->x = 0; v->y = 0; v->z = 0;
v++;
v->x = 1; v->y = 1; v->z = 0;
v++;
v->x = 2; v->y = 0; v->z = 0;
c = &buffer.commands;
c->operation = DRAW_TRIANGLE;
c->vertexes[0] = 0;
c->vertexes[1] = 1;
c->vertexes[2] = 2;
IssueExecuteBuffer (buffer);
It’s not uncommon for designers to confuse a beautiful looking product with one that works beautifully.
Braden Kowitz
A Behaviour-Driven Development framework
Includes test management, an expectation library and function spies.
Check it! http://pivotal.github.io/jasmine/
Offers a micro internal DSL
describe("A suite", function() {
it("contains spec with an expectation", function() {
expect(true).toBe(true);
});
});
Note this metaphore:
xdescribe("A spec", function() {
var foo;
xit("is just a function, so it can contain any code", function() {
expect(foo).toEqual(1);
});
})
The x
prefix crosses out and disables the test
"not" tests are naturally derived from positive ones:
expect(this).not.toBe(true);
expect(this).not.toMatch(/^https?/);
expect(this).not.toContain('www');
There is no toBeGreaterOrEqualThan()
.
But there is a toBeLessThan()
.
So we can write not.toBeLessThan()
.
A library to build meaningful regular expressions.
Translate the obscure regexp syntax to a human-friendly format.
Check it! https://github.com/VerbalExpressions/JSVerbalExpressions
Consider this pattern ^http(s)?://(www.)?[^ ]+$
var tester = VerEx()
.startOfLine()
.then( "http" )
.maybe( "s" )
.then( "://" )
.maybe( "www." )
.anythingBut( " " )
.endOfLine();
Unfortunately, a discontinued library for handling dates.
Extend JS native objects to improve readability.
Check what remains. https://code.google.com/p/datejs/
A fluent API
Date.today().first().thursday() // Returns the first Thursday of the current month.
Date.today().second().thursday()// Returns the second Thursday of the current month.
Date.march().third().thursday() // Returns the third Thursday in March of the current year.
Date.october().fourth().sunday()// Returns the fourth Sunday in October.
Date.today().fifth().sunday() // Returns the fifth Sunday in the current month, or throws a RangeError exception if there are not 5 Sundays in the current month.
Date.october().final().sunday() // Returns the final Sunday in October.
Extensions in other types
(1).day().fromNow() // One (1) day from now.
(3).months().ago() // Three (3) months ago.
Algebraical date expressions
Date.parse('t + 5d') // Adds 5 days to today.
Date.parse('today - 1 month') // Subtracts 1 month from today.
Date.parse('+') // Add 1 day to today = tomorrow.
Date.parse('- 3months') // Subtract 3 months.
A pattern to control asynchronous flows.
The promise is the unit of asynchronous flow.
Check the polyfill! https://github.com/slightlyoff/Promises
A promise retains a future value.
function getAnswerToEverything() {
return new Promise(function (resolver) {
doHeavyCalculations();
function doHeavyCalculations() {
setTimeout(function () {
// fulfill once we get the answer
resolver.fulfill(42);
}, 2000);
}
});
}
.then()
allows to chain execution.
getAnswerToEverything().then(guessTheQuestion);
.then()
returns a promise. So more chaining is possible.
getAnswerToEverything()
.then(guessTheQuestion).
.then(reachOmnisciency);
A light-weight implementation of jQuery.
Let's focus on the query engine and chainability only.
Check it! http://zeptojs.com/
Reusing CSS knowledge...
$('article aside.comments');
$('span[data-tooltip]');
$('#navigation ul > li');
...the developer becomes more productive.
Improved chainability...
$('#navigation ul')
.find('li:nth-of-type(1)')
.css('background-color', 'red')
.end()
.find('li:nth-of-type(2)')
.toogle('background-color', 'green')
.end();
...allowing independant chains of operations
by maintaining a stack of states.
I think not all design principles can be applied
directly to the API design.
But with some adaptation...
(roughly based on Secrets of Awesome JavaScript API design)
In design, the concept behind the work.
In software design, the goal of the library.
The coexistence of non-conflictive elements in a work.
In software design, regularity and predictability of the API.
In design, the distribution of the work elements
according to their visual weight.
In software design, the completeness of the API methods.
addYears()
, addMonths()
, addDays()
... allowing total control of the date parameters.any()
, all()
and some()
covering most of the common asynchronous situations.In design, the order of significance.
In software design, modularity and organisation.
VerEx
object.Zepto
namespace) and DOM manipulation (called from Zepto collections).In design, the relative size of elements againts each other.
In software design, the scope of each component.
In design, the focal point of the work outstanding by the use of contrast.
In software design, the major structures around which the library structures itself.
.then()
and Promise
chainability.fn
in Zepto.APIs simulating natural language.
They have contextual meaning.
By method chaining.
By micro embedded DSLs.
The good ,)
The bad :(
An example of fluent API
A colour manipulating library.
Start by creating user stories.
You will realize you are speaking a specific language.
Adapt this language to an API.
In color·k
// I want to create colors using CSS constructors.
k.color('red');
k.color('#F00');
k.color('#FA0000');
k.color('rgba(255, 0, 0, 0.5)');
// I want to make a color lighter or darker
// by a fixed amount.
k.color('red').lighter();
k.color('green').darker();
// I want to use the color entities in CSS contexts.
k.color('red').toString() // returns 'hsla(0, 50%, 50%, 1.0)'
The façade pattern: simplify complex APIs.
The proxy pattern: dynamic access to properties.
The interpreter pattern: execution of DSLs.
In color·k
// A prefix-based DSL to build colors
k.color('light-red');
k.color('web-violet');
k.color('dull-transparent-orange');
k.color('dark-#0F0');
Allows methods to form natural language sentences.
You must violate the Command / Query principle.
Main limitation: one unique context to modify.
In color·k
k.color('red')
.lighter()
.more.red()
.less.blue()
.brighter();
Used in jQuery / Zepto: .find()
and .end()
.
Implemented by maintaining a stack of contexts.
Some methods save the current context, .end()
restores the last context.
In color·k (experimental feature)
var variations = k.color('red')
.change().lighter()._
.change().darker()._
.change().alpha(0).$
By using special methods and descriptors:
change()
_
is a descriptor that saves the current state into the result stack and restore the context state.$
do the same but returning the result stack.In color·k
Check the ongoing specs!
Check Semanting Versioning. In semver you use three numbers M.m.p
standing for Major version, minor version and patch version.
p
number.m
number.M
number.