63
Controlling Flow callbacks made are easy Thursday, October 28, 2010

Controlling Flo · Common Mistakes • Abandoning convention and consistency. • Putting all callbacks inline. • Using libraries without grokking them. • Trying to make async

  • Upload
    others

  • View
    2

  • Download
    0

Embed Size (px)

Citation preview

Page 1: Controlling Flo · Common Mistakes • Abandoning convention and consistency. • Putting all callbacks inline. • Using libraries without grokking them. • Trying to make async

Controlling Flowcallbacks made are easy

Thursday, October 28, 2010

Page 2: Controlling Flo · Common Mistakes • Abandoning convention and consistency. • Putting all callbacks inline. • Using libraries without grokking them. • Trying to make async

EventEmitters are Easy

• Responding to events is a solved problem(At least for JavaScripters)

• Very similar to DOM coding

• thing.on("event", doSomething)

• easy.

Thursday, October 28, 2010

Page 3: Controlling Flo · Common Mistakes • Abandoning convention and consistency. • Putting all callbacks inline. • Using libraries without grokking them. • Trying to make async

callbacks are hard• Most common complaint about nodejs:

Ew, callbacks? Ugly nasty nesting indented forever spaghetti code? Just to open a file?!

YOU’VE GOTTA BE FRICKIN KIDDING ME.

• Variant:

Why doesn’t this work?

<link to severely broken code>

Thursday, October 28, 2010

Page 4: Controlling Flo · Common Mistakes • Abandoning convention and consistency. • Putting all callbacks inline. • Using libraries without grokking them. • Trying to make async

It's worse than that

• Most *objects* in NodeJS are Event Emitters (http server/client, etc.)

• Most low level *functions* take callbacks. (posix API, DNS lookups, etc.)

• Beyond "hello, world" it gets tricky.

Thursday, October 28, 2010

Page 5: Controlling Flo · Common Mistakes • Abandoning convention and consistency. • Putting all callbacks inline. • Using libraries without grokking them. • Trying to make async

What's actually hard?

• Doing a bunch of things in a specific order.

• Knowing when stuff is done.

• Handling failures.

• Breaking up functionality into parts (infinitely nested inline callbacks)

Thursday, October 28, 2010

Page 6: Controlling Flo · Common Mistakes • Abandoning convention and consistency. • Putting all callbacks inline. • Using libraries without grokking them. • Trying to make async

Common Mistakes

• Abandoning convention and consistency.

• Putting all callbacks inline.

• Using libraries without grokking them.

• Trying to make async code look sync.*

*controversialIn my opinion, promises are a perfectly fine way to solve this problem. But they're complicated under the hood, and making async code look sync can cause weird expectations. Also, people like to talk about a "Promise" like it's one kind of thing, when it's actually a very general pattern.Thursday, October 28, 2010

Page 7: Controlling Flo · Common Mistakes • Abandoning convention and consistency. • Putting all callbacks inline. • Using libraries without grokking them. • Trying to make async

flow control libraries

• There are approximately 7 gillion flow control libraries in the node.js ecosystem.

• Everyone likes their own the best.

• Obvious solution: Write your own.

• Let's do that now.

Thursday, October 28, 2010

Page 8: Controlling Flo · Common Mistakes • Abandoning convention and consistency. • Putting all callbacks inline. • Using libraries without grokking them. • Trying to make async

This is a learning exercise

• The goal is not to write the ideal flow control library.

• The goal is simplicity and understanding, with very little magic.

• Please don’t hold questions for the end.

• Please do try this at home.

Thursday, October 28, 2010

Page 9: Controlling Flo · Common Mistakes • Abandoning convention and consistency. • Putting all callbacks inline. • Using libraries without grokking them. • Trying to make async

First Priority:A Really Cool Name

• Be descriptive, but not much to describe.

• So minimal, you can write it in a slide show.

• http://github.com/isaacs/slide-flow-control

• npm install slide

• Hellz. Yeah.

Thursday, October 28, 2010

Page 10: Controlling Flo · Common Mistakes • Abandoning convention and consistency. • Putting all callbacks inline. • Using libraries without grokking them. • Trying to make async

Define Conventions• Two kinds of functions:

Actors: Take action

Callbacks: Get results

• Essentially the continuation pattern. Resulting code *looks* similar to fibers, but is *much* simpler to implement.

• Bonus: node works this way in the lowlevel APIs already, and it's very flexible.

Thursday, October 28, 2010

Page 11: Controlling Flo · Common Mistakes • Abandoning convention and consistency. • Putting all callbacks inline. • Using libraries without grokking them. • Trying to make async

Callbacks

• Simple responders

• Must always be prepared to handle errors! (That's why it's the first argument.)

• Often inline anonymous, but not always.

• Can trap and call other callbacks with modified data, or to pass errors upwards.

Thursday, October 28, 2010

Page 12: Controlling Flo · Common Mistakes • Abandoning convention and consistency. • Putting all callbacks inline. • Using libraries without grokking them. • Trying to make async

Actors

• Last argument is a callback.

• If any error occurs, and can't be handled, pass it to the callback and return.

• Must not throw. Return value ignored.

• return x ==> return cb(null, x)

• throw er ==> return cb(er)

Thursday, October 28, 2010

Page 13: Controlling Flo · Common Mistakes • Abandoning convention and consistency. • Putting all callbacks inline. • Using libraries without grokking them. • Trying to make async

Actor Examplefunction actor (some, args, cb) { // last argument is callback // optional args: if (!cb && typeof(args) === "function") cb = args, args = []

// do something, and then: if (failed) cb(new Error( "failed!")) else cb(null, optionalData)}

Thursday, October 28, 2010

Page 14: Controlling Flo · Common Mistakes • Abandoning convention and consistency. • Putting all callbacks inline. • Using libraries without grokking them. • Trying to make async

Actor Example

// return true if a path is either// a symlink or a directory.function isLinkOrDir (path, cb) { fs.lstat(path, function (er, s) { if (er) return cb(er) return cb(null, s.isDirectory() || s.isSymbolicLink()) })}

Thursday, October 28, 2010

Page 15: Controlling Flo · Common Mistakes • Abandoning convention and consistency. • Putting all callbacks inline. • Using libraries without grokking them. • Trying to make async

Actor Example

// return true if a path is either// a symlink or a directory.function isLinkOrDir (path, cb) { fs.lstat(path, function (er, s) { if (er) return cb(er) return cb(null, s.isDirectory() || s.isSymbolicLink()) })}

Thursday, October 28, 2010

Page 16: Controlling Flo · Common Mistakes • Abandoning convention and consistency. • Putting all callbacks inline. • Using libraries without grokking them. • Trying to make async

Actor Example

// return true if a path is either// a symlink or a directory.function isLinkOrDir (path, cb) { fs.lstat(path, function (er, s) { if (er) return cb(er) return cb(null, s.isDirectory() || s.isSymbolicLink()) })}

Thursday, October 28, 2010

Page 17: Controlling Flo · Common Mistakes • Abandoning convention and consistency. • Putting all callbacks inline. • Using libraries without grokking them. • Trying to make async

Actor Example

// return true if a path is either// a symlink or a directory.function isLinkOrDir (path, cb) { fs.lstat(path, function (er, s) { if (er) return cb(er) return cb(null, s.isDirectory() || s.isSymbolicLink()) })}

Thursday, October 28, 2010

Page 18: Controlling Flo · Common Mistakes • Abandoning convention and consistency. • Putting all callbacks inline. • Using libraries without grokking them. • Trying to make async

Actor Composition

// return true if a path is either// a symlink or a directory, and also// ends in ".bak"function isLinkDirBak (path, cb) { return isLinkOrDir(path, function (er, ld) { return cb(er, ld && path.substr(-4) === ".bak") })}

Thursday, October 28, 2010

Page 19: Controlling Flo · Common Mistakes • Abandoning convention and consistency. • Putting all callbacks inline. • Using libraries without grokking them. • Trying to make async

Actor Composition

// return true if a path is either// a symlink or a directory, and also// ends in ".bak"function isLinkDirBak (path, cb) { return isLinkOrDir(path, function (er, ld) { return cb(er, ld && path.substr(-4) === ".bak") })}

Thursday, October 28, 2010

Page 20: Controlling Flo · Common Mistakes • Abandoning convention and consistency. • Putting all callbacks inline. • Using libraries without grokking them. • Trying to make async

Actor Composition

// return true if a path is either// a symlink or a directory, and also// ends in ".bak"function isLinkDirBak (path, cb) { return isLinkOrDir(path, function (er, ld) { return cb(er, ld && path.substr(-4) === ".bak") })}

Thursday, October 28, 2010

Page 21: Controlling Flo · Common Mistakes • Abandoning convention and consistency. • Putting all callbacks inline. • Using libraries without grokking them. • Trying to make async

usecase: asyncMap• I have a list of 10 files, and need to read all

of them, and then continue when they're all done.

• I have a dozen URLs, and need to fetch them all, and then continue when they're all done.

• I have 4 connected users, and need to send a message to all of them, and then continue when that's done.

Thursday, October 28, 2010

Page 22: Controlling Flo · Common Mistakes • Abandoning convention and consistency. • Putting all callbacks inline. • Using libraries without grokking them. • Trying to make async

usecase: asyncMap

• I have a list of n things, and I need to dosomething with all of them, in parallel, and get the results once they're all complete.

Thursday, October 28, 2010

Page 23: Controlling Flo · Common Mistakes • Abandoning convention and consistency. • Putting all callbacks inline. • Using libraries without grokking them. • Trying to make async

function asyncMap (list, fn, cb_) { var n = list.length , results = [] , errState = null function cb (er, data) { if (errState) return if (er) return cb(errState = er) results.push(data) if (-- n === 0) return cb_(null, results) } list.forEach(function (l) { fn(l, cb) })}

Thursday, October 28, 2010

Page 24: Controlling Flo · Common Mistakes • Abandoning convention and consistency. • Putting all callbacks inline. • Using libraries without grokking them. • Trying to make async

function asyncMap (list, fn, cb_) { var n = list.length , results = [] , errState = null function cb (er, data) { if (errState) return if (er) return cb(errState = er) results.push(data) if (-- n === 0) return cb_(null, results) } list.forEach(function (l) { fn(l, cb) })}

Thursday, October 28, 2010

Page 25: Controlling Flo · Common Mistakes • Abandoning convention and consistency. • Putting all callbacks inline. • Using libraries without grokking them. • Trying to make async

function asyncMap (list, fn, cb_) { var n = list.length , results = [] , errState = null function cb (er, data) { if (errState) return if (er) return cb(errState = er) results.push(data) if (-- n === 0) return cb_(null, results) } list.forEach(function (l) { fn(l, cb) })}

Thursday, October 28, 2010

Page 26: Controlling Flo · Common Mistakes • Abandoning convention and consistency. • Putting all callbacks inline. • Using libraries without grokking them. • Trying to make async

function asyncMap (list, fn, cb_) { var n = list.length , results = [] , errState = null function cb (er, data) { if (errState) return if (er) return cb(errState = er) results.push(data) if (-- n === 0) return cb_(null, results) } list.forEach(function (l) { fn(l, cb) })}

Thursday, October 28, 2010

Page 27: Controlling Flo · Common Mistakes • Abandoning convention and consistency. • Putting all callbacks inline. • Using libraries without grokking them. • Trying to make async

usecase: asyncMap

function writeFiles (files, what, cb) { asyncMap( files , function (f, cb) { fs.writeFile(f,what,cb) } , cb )}

writeFiles([my,file,list], "foo", cb)

Thursday, October 28, 2010

Page 28: Controlling Flo · Common Mistakes • Abandoning convention and consistency. • Putting all callbacks inline. • Using libraries without grokking them. • Trying to make async

asyncMap

• note that asyncMap itself is an Actor function, so you can asyncMap your asyncMaps, dawg.

• This implementation is fine if order doesn't matter, but what if it does?

Thursday, October 28, 2010

Page 29: Controlling Flo · Common Mistakes • Abandoning convention and consistency. • Putting all callbacks inline. • Using libraries without grokking them. • Trying to make async

asyncMap - ordered

• close over the array index in the generated cb function.

• match up results to their original index.

Thursday, October 28, 2010

Page 30: Controlling Flo · Common Mistakes • Abandoning convention and consistency. • Putting all callbacks inline. • Using libraries without grokking them. • Trying to make async

function asyncMap (list, fn, cb_) { var n = list.length , results = [] , errState = null function cbGen (i) { return function cb (er, data) { if (errState) return if (er) return cb(errState = er) results[i] = data if (-- n === 0) return cb_(null, results) }} list.forEach(function (l, i) { fn(l, cbGen(i)) })

Thursday, October 28, 2010

Page 31: Controlling Flo · Common Mistakes • Abandoning convention and consistency. • Putting all callbacks inline. • Using libraries without grokking them. • Trying to make async

function asyncMap (list, fn, cb_) { var n = list.length , results = [] , errState = null function cbGen (i) { return function cb (er, data) { if (errState) return if (er) return cb(errState = er) results[i] = data if (-- n === 0) return cb_(null, results) }} list.forEach(function (l, i) { fn(l, cbGen(i)) })

Thursday, October 28, 2010

Page 32: Controlling Flo · Common Mistakes • Abandoning convention and consistency. • Putting all callbacks inline. • Using libraries without grokking them. • Trying to make async

usecase: chain

• I have to do a bunch of things, in order. Get db credentials out of a file, read the data from the db, write that data to another file.

• If anything fails, do not continue.

Thursday, October 28, 2010

Page 33: Controlling Flo · Common Mistakes • Abandoning convention and consistency. • Putting all callbacks inline. • Using libraries without grokking them. • Trying to make async

function chain (things, cb) { ;(function LOOP (i, len) { if (i >= len) return cb() things[i](function (er) { if (er) return cb(er) LOOP(i + 1, len) }) })(0, things.length)}

Thursday, October 28, 2010

Page 34: Controlling Flo · Common Mistakes • Abandoning convention and consistency. • Putting all callbacks inline. • Using libraries without grokking them. • Trying to make async

function chain (things, cb) { ;(function LOOP (i, len) { if (i >= len) return cb() things[i](function (er) { if (er) return cb(er) LOOP(i + 1, len) }) })(0, things.length)}

Thursday, October 28, 2010

Page 35: Controlling Flo · Common Mistakes • Abandoning convention and consistency. • Putting all callbacks inline. • Using libraries without grokking them. • Trying to make async

function chain (things, cb) { ;(function LOOP (i, len) { if (i >= len) return cb() things[i](function (er) { if (er) return cb(er) LOOP(i + 1, len) }) })(0, things.length)}

Thursday, October 28, 2010

Page 36: Controlling Flo · Common Mistakes • Abandoning convention and consistency. • Putting all callbacks inline. • Using libraries without grokking them. • Trying to make async

function chain (things, cb) { ;(function LOOP (i, len) { if (i >= len) return cb() things[i](function (er) { if (er) return cb(er) LOOP(i + 1, len) }) })(0, things.length)}

Thursday, October 28, 2010

Page 37: Controlling Flo · Common Mistakes • Abandoning convention and consistency. • Putting all callbacks inline. • Using libraries without grokking them. • Trying to make async

usecase: chain

• Still have to provide an array of functions, which is a lot of boilerplate, and a pita if your functions take args "function (cb){blah(a,b,c,cb)}"

• Results are discarded, which is a bit lame.

• No way to branch.

Thursday, October 28, 2010

Page 38: Controlling Flo · Common Mistakes • Abandoning convention and consistency. • Putting all callbacks inline. • Using libraries without grokking them. • Trying to make async

reducing boilerplate

• convert an array of [fn, args] to an actor that takes no arguments (except cb)

• A bit like Function#bind, but tailored for our use-case.

• bindActor(obj, "method", a, b, c) bindActor(fn, a, b, c) bindActor(obj, fn, a, b, c)

Thursday, October 28, 2010

Page 39: Controlling Flo · Common Mistakes • Abandoning convention and consistency. • Putting all callbacks inline. • Using libraries without grokking them. • Trying to make async

function bindActor () { var args = Array.prototype.slice.call (arguments) // jswtf. , obj = null , fn if (typeof args[0] === "object") { obj = args.shift() fn = args.shift() if (typeof fn === "string") fn = obj[ fn ] } else fn = args.shift() return function (cb) { fn.apply(obj, args.concat(cb)) }}

Thursday, October 28, 2010

Page 40: Controlling Flo · Common Mistakes • Abandoning convention and consistency. • Putting all callbacks inline. • Using libraries without grokking them. • Trying to make async

function bindActor () { var args = Array.prototype.slice.call (arguments) // jswtf. , obj = null , fn if (typeof args[0] === "object") { obj = args.shift() fn = args.shift() if (typeof fn === "string") fn = obj[ fn ] } else fn = args.shift() return function (cb) { fn.apply(obj, args.concat(cb)) }}

Thursday, October 28, 2010

Page 41: Controlling Flo · Common Mistakes • Abandoning convention and consistency. • Putting all callbacks inline. • Using libraries without grokking them. • Trying to make async

function bindActor () { var args = Array.prototype.slice.call (arguments) // jswtf. , obj = null , fn if (typeof args[0] === "object") { obj = args.shift() fn = args.shift() if (typeof fn === "string") fn = obj[ fn ] } else fn = args.shift() return function (cb) { fn.apply(obj, args.concat(cb)) }}

Thursday, October 28, 2010

Page 42: Controlling Flo · Common Mistakes • Abandoning convention and consistency. • Putting all callbacks inline. • Using libraries without grokking them. • Trying to make async

function bindActor () { var args = Array.prototype.slice.call (arguments) // jswtf. , obj = null , fn if (typeof args[0] === "object") { obj = args.shift() fn = args.shift() if (typeof fn === "string") fn = obj[ fn ] } else fn = args.shift() return function (cb) { fn.apply(obj, args.concat(cb)) }}

Thursday, October 28, 2010

Page 43: Controlling Flo · Common Mistakes • Abandoning convention and consistency. • Putting all callbacks inline. • Using libraries without grokking them. • Trying to make async

bindActor

• Some obvious areas for improvement.

• They wouldn't fit on a slide.

• Left as an exercise for the reader.

Thursday, October 28, 2010

Page 44: Controlling Flo · Common Mistakes • Abandoning convention and consistency. • Putting all callbacks inline. • Using libraries without grokking them. • Trying to make async

function chain (things, cb) { ;(function LOOP (i, len) { if (i >= len) return cb() if (Array.isArray(things[i])) things[i] = bindActor.apply (null, things[i]) things[i](function (er) { if (er) return cb(er) LOOP(i + 1, len) }) })(0, things.length)}

Thursday, October 28, 2010

Page 45: Controlling Flo · Common Mistakes • Abandoning convention and consistency. • Putting all callbacks inline. • Using libraries without grokking them. • Trying to make async

function chain (things, cb) { ;(function LOOP (i, len) { if (i >= len) return cb() if (Array.isArray(things[i])) things[i] = bindActor.apply (null, things[i]) things[i](function (er) { if (er) return cb(er) LOOP(i + 1, len) }) })(0, things.length)}

Thursday, October 28, 2010

Page 46: Controlling Flo · Common Mistakes • Abandoning convention and consistency. • Putting all callbacks inline. • Using libraries without grokking them. • Trying to make async

chain: branching

• Skip over falsey arguments

• chain([ doThing && [thing,a,b,c] , isFoo && [doFoo, "foo"] , subChain && [chain, [one, two]] ], cb)

Thursday, October 28, 2010

Page 47: Controlling Flo · Common Mistakes • Abandoning convention and consistency. • Putting all callbacks inline. • Using libraries without grokking them. • Trying to make async

function chain (things, cb) { ;(function LOOP (i, len) { if (i >= len) return cb() if (Array.isArray(things[i])) things[i] = bindActor.apply (null, things[i]) if (!things[i]) return LOOP(i + 1, len) things[i](function (er) { if (er) return cb(er) LOOP(i + 1, len) }) })(0, things.length)}

Thursday, October 28, 2010

Page 48: Controlling Flo · Common Mistakes • Abandoning convention and consistency. • Putting all callbacks inline. • Using libraries without grokking them. • Trying to make async

chain: tracking results

• Supply an array to keep the results in.

• If you don't care, don't worry about it.

• Last result is always inresults[results.length - 1]

• Just for kicks, let's also treat chain.first and chain.last as placeholders for the first/last result up until that point.

Thursday, October 28, 2010

Page 49: Controlling Flo · Common Mistakes • Abandoning convention and consistency. • Putting all callbacks inline. • Using libraries without grokking them. • Trying to make async

chain.first = {} ; chain.last = {}function chain (things, res, cb) { if (!cb) cb = res , res = [] ;(function LOOP (i, len) { if (i >= len) return cb(null,res) if (Array.isArray(things[i])) things[i] = bindActor.apply(null, things[i].map(function(i){ return (i===chain.first) ? res[0] : (i===chain.last) ? res[res.length - 1] : i })) if (!things[i]) return LOOP(i + 1, len) things[i](function (er, data) { res.push(er || data) if (er) return cb(er, res) LOOP(i + 1, len) })

})(0, things.length) }Thursday, October 28, 2010

Page 50: Controlling Flo · Common Mistakes • Abandoning convention and consistency. • Putting all callbacks inline. • Using libraries without grokking them. • Trying to make async

chain.first = {} ; chain.last = {}function chain (things, res, cb) { if (!cb) cb = res , res = [] ;(function LOOP (i, len) { if (i >= len) return cb(null,res) if (Array.isArray(things[i])) things[i] = bindActor.apply(null, things[i].map(function(i){ return (i===chain.first) ? res[0] : (i===chain.last) ? res[res.length - 1] : i })) if (!things[i]) return LOOP(i + 1, len) things[i](function (er, data) { res.push(er || data) if (er) return cb(er, res) LOOP(i + 1, len) })

})(0, things.length) }Thursday, October 28, 2010

Page 51: Controlling Flo · Common Mistakes • Abandoning convention and consistency. • Putting all callbacks inline. • Using libraries without grokking them. • Trying to make async

chain.first = {} ; chain.last = {}function chain (things, res, cb) { if (!cb) cb = res , res = [] ;(function LOOP (i, len) { if (i >= len) return cb(null,res) if (Array.isArray(things[i])) things[i] = bindActor.apply(null, things[i].map(function(i){ return (i===chain.first) ? res[0] : (i===chain.last) ? res[res.length - 1] : i })) if (!things[i]) return LOOP(i + 1, len) things[i](function (er, data) { res.push(er || data) if (er) return cb(er, res) LOOP(i + 1, len) })

})(0, things.length) }Thursday, October 28, 2010

Page 52: Controlling Flo · Common Mistakes • Abandoning convention and consistency. • Putting all callbacks inline. • Using libraries without grokking them. • Trying to make async

chain.first = {} ; chain.last = {}function chain (things, res, cb) { if (!cb) cb = res , res = [] ;(function LOOP (i, len) { if (i >= len) return cb(null,res) if (Array.isArray(things[i])) things[i] = bindActor.apply(null, things[i].map(function(i){ return (i===chain.first) ? res[0] : (i===chain.last) ? res[res.length - 1] : i })) if (!things[i]) return LOOP(i + 1, len) things[i](function (er, data) { res.push(er || data) if (er) return cb(er, res) LOOP(i + 1, len) })

})(0, things.length) }Thursday, October 28, 2010

Page 53: Controlling Flo · Common Mistakes • Abandoning convention and consistency. • Putting all callbacks inline. • Using libraries without grokking them. • Trying to make async

chain.first = {} ; chain.last = {}function chain (things, res, cb) { if (!cb) cb = res , res = [] ;(function LOOP (i, len) { if (i >= len) return cb(null,res) if (Array.isArray(things[i])) things[i] = bindActor.apply(null, things[i].map(function(i){ return (i===chain.first) ? res[0] : (i===chain.last) ? res[res.length - 1] : i })) if (!things[i]) return LOOP(i + 1, len) things[i](function (er, data) { res.push(er || data) if (er) return cb(er, res) LOOP(i + 1, len) })

})(0, things.length) }Thursday, October 28, 2010

Page 54: Controlling Flo · Common Mistakes • Abandoning convention and consistency. • Putting all callbacks inline. • Using libraries without grokking them. • Trying to make async

chain.first = {} ; chain.last = {}function chain (things, res, cb) { if (!cb) cb = res , res = [] ;(function LOOP (i, len) { if (i >= len) return cb(null,res) if (Array.isArray(things[i])) things[i] = bindActor.apply(null, things[i].map(function(i){ return (i===chain.first) ? res[0] : (i===chain.last) ? res[res.length - 1] : i })) if (!things[i]) return LOOP(i + 1, len) things[i](function (er, data) { res.push(er || data) if (er) return cb(er, res) LOOP(i + 1, len) })

})(0, things.length) }Ok, this can't get anybigger or it won't fit.

Thursday, October 28, 2010

Page 55: Controlling Flo · Common Mistakes • Abandoning convention and consistency. • Putting all callbacks inline. • Using libraries without grokking them. • Trying to make async

Non-trivial Use Case

• Read number files in a directory

• Add the results together

• Ping a web service with the result

• Write the response to a file

• Delete the number files

Thursday, October 28, 2010

Page 56: Controlling Flo · Common Mistakes • Abandoning convention and consistency. • Putting all callbacks inline. • Using libraries without grokking them. • Trying to make async

var chain = require("./chain.js") , asyncMap = require("./async-map.js")function myProgram (cb) { var res = [], last = chain.last , first = chain.first chain ( [ [fs, "readdir", "the-directory"] , [readFiles, "the-directory", last] , [sum, last] , [ping, "POST", "example.com", 80 , "/foo", last] , [fs, "writeFile", "result.txt", last] , [rmFiles, "./the-directory", first] ] , res , cb ))

Thursday, October 28, 2010

Page 57: Controlling Flo · Common Mistakes • Abandoning convention and consistency. • Putting all callbacks inline. • Using libraries without grokking them. • Trying to make async

var chain = require("./chain.js") , asyncMap = require("./async-map.js")function myProgram (cb) { var res = [], last = chain.last , first = chain.first chain ( [ [fs, "readdir", "the-directory"] , [readFiles, "the-directory", last] , [sum, last] , [ping, "POST", "example.com", 80 , "/foo", last] , [fs, "writeFile", "result.txt", last] , [rmFiles, "./the-directory", first] ] , res , cb ))

Thursday, October 28, 2010

Page 58: Controlling Flo · Common Mistakes • Abandoning convention and consistency. • Putting all callbacks inline. • Using libraries without grokking them. • Trying to make async

var chain = require("./chain.js") , asyncMap = require("./async-map.js")function myProgram (cb) { var res = [], last = chain.last , first = chain.first chain ( [ [fs, "readdir", "the-directory"] , [readFiles, "the-directory", last] , [sum, last] , [ping, "POST", "example.com", 80 , "/foo", last] , [fs, "writeFile", "result.txt", last] , [rmFiles, "./the-directory", first] ] , res , cb ))

Thursday, October 28, 2010

Page 59: Controlling Flo · Common Mistakes • Abandoning convention and consistency. • Putting all callbacks inline. • Using libraries without grokking them. • Trying to make async

var chain = require("./chain.js") , asyncMap = require("./async-map.js")function myProgram (cb) { var res = [], last = chain.last , first = chain.first chain ( [ [fs, "readdir", "the-directory"] , [readFiles, "the-directory", last] , [sum, last] , [ping, "POST", "example.com", 80 , "/foo", last] , [fs, "writeFile", "result.txt", last] , [rmFiles, "./the-directory", first] ] , res , cb ))

Thursday, October 28, 2010

Page 60: Controlling Flo · Common Mistakes • Abandoning convention and consistency. • Putting all callbacks inline. • Using libraries without grokking them. • Trying to make async

var chain = require("./chain.js") , asyncMap = require("./async-map.js")function myProgram (cb) { var res = [], last = chain.last , first = chain.first chain ( [ [fs, "readdir", "the-directory"] , [readFiles, "the-directory", last] , [sum, last] , [ping, "POST", "example.com", 80 , "/foo", last] , [fs, "writeFile", "result.txt", last] , [rmFiles, "./the-directory", first] ] , res , cb ))

Thursday, October 28, 2010

Page 61: Controlling Flo · Common Mistakes • Abandoning convention and consistency. • Putting all callbacks inline. • Using libraries without grokking them. • Trying to make async

var chain = require("./chain.js") , asyncMap = require("./async-map.js")function myProgram (cb) { var res = [], last = chain.last , first = chain.first chain ( [ [fs, "readdir", "the-directory"] , [readFiles, "the-directory", last] , [sum, last] , [ping, "POST", "example.com", 80 , "/foo", last] , [fs, "writeFile", "result.txt", last] , [rmFiles, "./the-directory", first] ] , res , cb ))

Thursday, October 28, 2010

Page 62: Controlling Flo · Common Mistakes • Abandoning convention and consistency. • Putting all callbacks inline. • Using libraries without grokking them. • Trying to make async

var chain = require("./chain.js") , asyncMap = require("./async-map.js")function myProgram (cb) { var res = [], last = chain.last , first = chain.first chain ( [ [fs, "readdir", "the-directory"] , [readFiles, "the-directory", last] , [sum, last] , [ping, "POST", "example.com", 80 , "/foo", last] , [fs, "writeFile", "result.txt", last] , [rmFiles, "./the-directory", first] ] , res , cb ))

Thursday, October 28, 2010

Page 63: Controlling Flo · Common Mistakes • Abandoning convention and consistency. • Putting all callbacks inline. • Using libraries without grokking them. • Trying to make async

Convention Profits

• Consistent API from top to bottom.

• Sneak in at any point to inject functionality. (testable, reusable, etc.)

• When ruby and python users whine, you can smile condescendingly.

Thursday, October 28, 2010