写290模块我学到的东西

(What I've learnt after writing 290 modules)


Some things I've written since node@0.2.1


testing stuff

meta-test       asynct               synct
testbed         test-report-test     test-child
test-runner     test-cmd             it-is
assertions      asynct_tests         macgyver

stream modules

event-stream    JSONStream           through
fsm-stream      map-stream           rpc-stream
git-stream      message-stream       push-stream
header-stream   msgpack-stream       recurse-stream
sort-stream     regular-stream       relational-join-stream
pause-stream    tab-stream           repl-stream
duplex          stream-combiner      redis-protocol-stream
mux-demux       stream-serializer    stream-to-pull-stream
reconnect       stream-spec          pull-stream-to-stream
stream-tester   post-message-stream

connect producers and consumers of data together.

input.pipe(transform).pipe(output)

light-weight data replication

snob           crdt                  scuttlebutt
scuttlebucket  r-edit                level-scuttlebutt
r-value        scuttlebutt-remote    localstorage-scuttlebutt
repred         schema-scuttlebutt    r-array

these all follow the duplex pattern

stream.pipe(replicator.createStream).pipe(stream)

replicator.set('foo', 'bar')

var bar = replicator.get('foo')

replicator.on('change', function (key, value) {
  console.log('change', key, value)
})

minimal streams

strm

pull-stream       pull-glob      pull-sorted-merge
pull-through      reg-spec       pull-traverse
pull-cat          pull-http      pull-split
pull-core         pull-level     pull-async-batch
pull-window       pull-zip       regular-stream
pull-crypto       pull-markable  pull-stream-range
pull-decode       pull-merge     pull-stream-to-stream
pull-flow         pull-paramap   pull-switch
pull-fs           pull-pushable  pull-tee

function as a stream

function values (array) {
  var i = 0
  return function (abort, cb) {
    if(i > array.length) cb(true)
    else                 cb(null, array[i++])
  })
}

reader instead of a writable

function sink (read) {
  read(null, function next (end, data) {
    if(!end) {
      console.log(data)
      read(null, next)
    }
  })

.pipe() is reader(readable)

//pass the source to the sink
sink(values([1, 2, 3]))

//OR
var pull = require('pull-stream')
pull(values([1, 2, 3]), sink)

leveldb

level-sublevel    level-queue        level-live-stream
level-manifest    level-replicate    level-test
level-trigger     level-scuttlebutt  level-update
level-couch-sync  level-repred       level-master
level-fix-range   level-merkle       level-view-stream
level-heavy       level-merkle-tree  level-search
level-window      level-hooks        level-in-flight
level-peek        level-static       level-index
level-post        level-store        level-inverted-index

leveldb


what I've learnt

Some aspects of that...


To collaborate...

We need to agree on some things, and modules can help us find agreement...

By Limiting the scope of that agreement


modules are more fun!


The ideal situation:

when A published module that B uses, and B published module that A uses.

Now we are actively collaborating.


it's easier to agree a little than a lot

Modules make it easier to collaborate in a loose way, because we can use the same modules for different things.

We can collabotate, even though we have different goals.


Modules are not magic.


modules are solutions.

but what problems make for good modules?


Pick the right problem




Heaven and Earth must be in harmony.


Every language is imperfect

so any implementation is also imperfect.

By necessity, opinions and messiness are always present.


Don't try to be too clever.

If making something a little cruder is easier, do it.

The easiest way to put your module closer to heaven is to make less of it.


Observable - 2 way bindings

var o = require('observable')
var v = o()

v(10) // set value
console.log(v()) // get value
v(console.log) // track value
v(12) // trigger change

inside observable

function value () {
  var _val, change
  return function (val) {
    return (
      'undefined' === typeof val ? _val
    : 'function'  !== typeof val ? change && change(_val = val)
    : ((change = val), val(_val), function () {
      if(change === val) change = null
    })
  )}}

A Modular Ecosystem


The first modular ecosystem: UNIX


the ecosystem pattern


connect/express


streams


leveldb


node.js


Other Potential Modular Ecosystems

These don't really exist yet, but they could.


Graphs - see graphlib

dagre        - graph layout
graphlib-dot - parse dot files
dagre-d3     - render with d3
graphlib-git - generate graph of git commits
graphlib-adjacency
             - graph from adjacency list

Lots of potential graph algorithms.


Tabular Data & Statistics

Steal ideas from matlab, or panda (python)

Table#get(row, col)
Table#set(row, col, value)
Table#addRow (afterRow, values)
Table#select(startRow, EndRow) //returns a view on this table.

https://github.com/maxogden/dat/issues/16

Basically, everything you'd need to implement a spreadsheet.


Vec2 - 2D Vectors

use Vec2 to bring Geometry to the DOM.

var v = new Vec2().set(x, y)
//many methods working with vectors.

get the dimensions of an element, natively...

function positon(element) {
  var rect = element.getBoundingClientRect()

  //if this object has margins, add them to the calculation.
  //otherwise your numbers will be wrong!
  var style = getComputedStyle(element)

  return {
    x: rec.left + parseFloat(style['margin-left']),
    y: rec.top + parseFloat(style['margin-top'])
  }
}

Suppose, you wanted to set the position, to an exact pixel? (remember, position: absolute means absolute position within parent)

function subtract(a, b) {
  return { x: a.x - b.x, y: a.y - b.y }
}
function place (element, x, y) {
  var pos = position(foo)
  var parentPos = position(foo.parentElement)
  var _pos = subtract(parentPos, pos)
  foo.style.left = (x - _pos.y) + 'px'
  foo.style.top = (y - _pos.y) + 'px'
}

TOO HARD!


center a element

var vdom = require('vec2-dom')
var r1 = vdom.element(e1)
var r2 = vdom.absolute(e2, true)

r2.set(r1.size.divide(2, true).subtract(r2.size.divide(2, true))

DRAG & DROP EXAMPLE


Window Manager as Front End Framework?


Window Manager!


maps


Thank you jing.js