unassertEncourage Design by Contract (DbC) by writing assertions in production code, and compiling them away from release
Takuto Wada Nov 7, 2015 @nodefest Tokyo 2015
Takuto Wada Twitter: @t_wada github: @twada
Do you write tests?
assert(typeof item.id === 'strong') | | | | | | | false | | "foo" | Item{id:"foo",name:"bar"} "string"
--- [string] 'strong' +++ [string] typeof item.id @@ -1,6 +1,6 @@ str -o +i ng
I’m the author of power-assert-js!
power-assert
Wrestling with Babel6 recently…
unassertEncourage Design by Contract (DbC) by writing assertions in production code, and compiling them away from release
•unassert •unassertify •babel-plugin-unassert •webpack-unassert-loader
unassert family
'use strict';
var assert = require('assert');
function add (a, b) { console.assert(typeof a === 'number'); assert(!isNaN(a)); assert.equal(typeof b, 'number'); assert.ok(!isNaN(b)); return a + b; }
before
src.js
babel --plugins babel-plugin-unassert src.js > dest.js
browserify -t unassertify src.js > dest.js
'use strict';
var assert = require('assert');
function add (a, b) { console.assert(typeof a === 'number'); assert(!isNaN(a)); assert.equal(typeof b, 'number'); assert.ok(!isNaN(b)); return a + b; }
after
dest.js
User’s voice
https://www.mapbox.com/
“In internal / private methods, we check preconditions with assert, helping us catch mistakes within the library.
For performance, these checks are removed from the production build with unassertify.”
CONTRIBUTING.md
where / when unassert
“I don't think we should use this primarily for type checking, but for preconditions -- parts of API contracts that cannot be statically checked.”
@jfirebaugh
why unassert
“Flow & TypeScript are compile-time, and preconditions could be runtime.”
“Mapbox GL JS is pretty minimal in terms of transforms - envify, brfs, glify - such that all JS is vanilla.”
@tmcw
why not flow / typescript
preconditions?
postconditions?
invariants?
{P} A {Q}
Design by Contract by Bertrand Meyer
If you promise to call routine with precondition satisfied then I, in return, promise to deliver a final state in which postcondition is satisfied.
Design by Contract (DbC)
• redundant checks can and indeed will hurt • simplicity becomes a crucial criterion • complexity is the major enemy of quality •whose responsibility it is to enforce it: the client's, or the supplier's.
Design by Contract (DbC)
switch (name) { case 'foo': doSomething(); break; case 'bar': doAnother(); break; default: assert(false, 'Cannot be here'); }
Not only preconditions
add(path) { assert(path instanceof PathElement, `path should be PathElement but was: ${ typeName(path) }`); this.paths.push(path); assert.deepEqual(this.paths, sortedPathElements(this.paths), 'this.paths should always be sorted'); }
Not only preconditions
Not only preconditions
What if…we use power-assert instead of assert?
import assert from 'power-assert';
class Calc { add (a, b) { assert(!(isNaN(a) || isNaN(b))); assert(typeof a === 'number'); assert(typeof b === 'number'); return a + b; } }
const calc = new Calc(); console.log(calc.add(3, NaN));
calc.js
write assertions with power-assert
{ "env": { "development": { "plugins": [ "babel-plugin-espower" ], }, "production": { "plugins": [ "babel-plugin-unassert" ] } } } .babelrc
unassert in prod, power-assert in dev
$ $(npm bin)/babel-node calc.js
AssertionError: # calc.js:5
assert(!(isNaN(a) || isNaN(b))) | | | | | | | | | | true NaN | false 3 true false
power-assert output appears!
user’s voice
One more thing…
unassert is now babel6 ready!
power-assert is not babel6 ready yet
update: 2015/11/13 power-assert now supports babel6!!
power-assert now works with async/await
# test/some_test.js:6
assert((await bigOrSmall(input)) === big) | | | | | | | "big" "small" 3 false
--- [string] big +++ [string] await bigOrSmall(input) @@ -1,3 +1,5 @@ -big +small
power-assert now works with async/await
by @jamestalmage
Encourage reliable programming by writing assertions in production code,
and compiling them away from release (if you want).
to recap
power-asserthttps://github.com/power-assert-js/power-assert
unasserthttps://github.com/twada/unassert
Thank you!