git ssb

0+

dinoworm 🐛 / campjs-viii-ludditejs



Branch:
Michael Williams committed okayLatest: 4db53a5 on 8/6/2017, 12:21:47 AM
📄.gitignore
📄LICENSE
📄NOTES.md
📄README.md
📄avatar.png
📄catstack.jpg
📄dogstack.jpg
📄engelbart.jpg
📄enspiral.png
📄example.js
📄follow_your_dreams.png
📄git-ssb-screenshot.png
📄index.css
📄index.html
📄index.js
📄luddite.jpg
📄morpheus-cat.png
📄package-lock.json
📄package.json
📄patchwork-screenshot.jpg
📄patchwork.png
📄rabbit-hole.jpg
📄root-systems.jpg
📁stuff
📁test
📄training-wheels.jpg
📄white-rabbit.jpg
README.md

layout: true

<footer>dinosaur.is</footer>


class: center

luddite.js

<img src="./white-rabbit.jpg" />

<!-- image credit to http://www.rabbitholekc.org/ -->

???


class: center

hey CampJS

i'm Mikey from Enspiral & Root Systems

<div class="row">
<a href="http://dinosaur.is.com">
<img alt="Mikey's avatar" src="./avatar.png" width="200" />
</a>
<a href="http://enspiral.com">
<img alt="Enspiral logo" src="./enspiral.png" width="200" />
</a>
<a href="http://dinosaur.is">
<img alt="Root Systems logo" src="./root-systems.jpg" width="200" />
</a>
</div>

slides are available at:

http://dinosaur.is/campjs-viii-ludditejs

???


class: center, info

shout-out

???


class: info

Douglas Engelbart

augment human intellect

<img src="./engelbart.jpg" height="350" class="center" />

???

references:


class: center

let's adventure

to the silly wonderland of luddite.js

<img src="./rabbit-hole.jpg" height='380' class="center" />

<!-- image credit to Mary Blair at Disney -->

???

an ambiguous utopia


class: info

Luddite?

the Luddites was a political movement against centralized automated technology.

<img src="./luddite.jpg" height='300' class="center" />

???


class: info

luddite.js?

luddite.js is a (made-up) meme for decentralized simple JavaScript.

???


class: center, info

decentralized userland ecosystems


class: info

what if i told you...

<img src="./morpheus-cat.png" height="400" />

that anyone can create a standard?

???


class: info

what is a standard?

a standard is an opinion about a pattern

example: "standard style"

npm install --global standard

???


class: info

what if i told you...

<img src="./morpheus-cat.png" height="400" />

that you only needed functions and objects?

???


class: info

what is a luddite.js standard?

a standard based on a function signature

example: Redux reducers

const reducer = (state, action) => nextState

???


class: info

why is this important?

???


class: center, info

simple patterns based on function signatures


class: success

just a function

function fn (options) { return value }
const fn = (...args) => ({ [key]: value })

class: info

sync function signals

with a sync function, there are two possible signals:

  1. value: return value
  2. error: throw error

???

function fn (...args) { throw error }
try {
  fn(...args)
} catch (const err) {
  // handle error
}

class: center, info

modules


class: danger

es modules

import thing from 'module'

export default thing
import { thing as thingy } from 'module'

export const thing = thingy

???


class: success

node modules

also known as "CommonJS"

const thing = require('module')

module.exports = thing
const { thing: thingy } = require('module')

module.exports = { thing: thingy }

???


class: success

depject

const module = {
  needs: {
    message: {
      layout: 'first',
      render: 'map',
      decorate: 'reduce'
    }
  },
  gives: {
    message: {
      view: true
    }
  },
  create: ({ message: { layout, render, decorate }) => {
    return { message: { view } }

    function view () {}
  }
}

combine([modules...])

???

https://github.com/depject/depject


class: center, info

dom elements


class: danger

jsx

import React from 'react'
import classNames from 'classnames'

export default Todos

const Todos = ({ items }) => (
  <List>{items.map(item => (
    <Item item={item} />
  ))}</List>
)

const List = ({ children }) => (
  <div className='list'>{children}</div>
)

const Item = ({ item: { isActive, text } }) => {
  const className = classNames({
    item: true,
    active: isActive
  })
  return <div className={className}>{text}</div>
}

???


class: success

hyperscript

const h = require('react-hyperscript')
const classNames = require('classnames')

module.exports = Todos

const Todos = ({ items }) => (
  h(List, items.map(item =>
    h(Item, { item })
  ))
)

const List = ({ children }) => (
  h('div', { className: 'list' }, children)
)

const Item = ({ item: { isActive, text } }) => {
  const className = classNames({
    item: true,
    active: isActive
  })
  return h('div', { className }, text)
)

???

see also:


class: success

React.createElement

const h = require('react').createElement
const classNames = require('classnames')

module.exports = Todos

const Todos = ({ items }) => (
  h(List, null, items.map(item =>
    h(Item, { item })
  ))
)

const List = ({ children }) => (
  h('div', { className: 'list' }, children)
)

const Item = ({ item: { isActive, text } }) => {
  const className = classNames({
    item: true,
    active: isActive
  })
  return h('div', { className }, text)
)

???


class: center, info

eventual value


class: danger

promise spec

const promise = new Promise((resolve, reject) => {
  // do stuff...
  resolve(value)
  // oh no!
  reject(error)
}
promise
  .then(value => console.log(value))
  .catch(err => console.error(value))

???

https://tc39.github.io/ecma262/#sec-promise-objects

TODO waterfall

parallel

module.exports = fetchCats

function fetchCats ({ cats }) {
  return Promise.all(cats.map(cat => {
    return fetch(cat)
  }))
})

class: success

continuable

a "continuable" is a function that takes a single argument, a node-style error-first callback

const continuable = (callback) => {
  // do stuff...
  callback(null, value)
  // oh no!
  callback(error)
}
continuable((err, value) => {
  if (err) console.error(err)
  else console.log(value)
})

???

a continuable is the callback version of a promise

can be passed around as an "eventual value", same as promises. but without the resolved, pending, rejected state machine complexity.

TODO waterfall

parallel

const request = require('request')
const parallel = require('run-parallel')

module.exports = fetchCats

function fetchCats ({ cats }) {
  return callback => parallel(cats.map(cat => {
    return callback => request(cat, callback)
  }), callback)
})

class: info

async errors

with a node-style error-first callback, there are three possible signals:

  1. value: callback(null, value)
  2. user error: callback(error)
  3. programmer error: throw error

???

i could talk about how to do pipe continuable as a waterfall, in parallel, etc, but...

both continuables and promises have their own place in hell, we need better abstractions.


class: center, info

reactive values


class: danger

es observables

https://tc39.github.io/proposal-observable/

???

too much detail to explain here


class: success

observ-ables

reactive values using only functions!

???


class: success

const { h, Struct, Value, when } = require('mutant')

const toggle = (state) => {
  state.set(!state())
}

const Activity = ({ activity: { isActive, text }) => (
  h('div', {
    style: {
      color: when(isActive, 'green', 'red')
    },
    events: {
      click: () => toggle(isActive)
    }
  }, text)
)

var activity = Struct({
  text: Value('give a talk'),
  isActive: Value(true)
})
var element = Activity({ activity })

document.body.appendChild(element)

???


class: center, info

values over time


class: danger

node streams

https://nodejs.org/api/stream.html

???


class: danger

whatwg streams

https://streams.spec.whatwg.org/

???


class: success

pull streams

async streams using only functions!

pull(source, through, sink)

???

pull streams could be its own talk, going to be a quick intro


class: success

source

function createSource (...args) {
  // a source function accepts
  //   - abort: a boolean whether to signal end
  //   - callback: where to send next signal
  return (abort, callback) => {
    if (abort || done) callback(true)
    else callback(null, value)
  }
}

???

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

class: success

source usage

const values = require('pull-stream/sources/values')

const source = values([0, 1, 2, 3])

source(null, (err, value) {
  console.log('first value:', value)
})
// first value: 0

class: info

pull stream errors

with a pull stream source callback, there are four possible signals:

  1. value: callback(null, value)
  2. user error: callback(error)
  3. programmer error: throw error
  4. complete: callback(true)

???


class: success

sink spec

function createSink (...args) {
  // a sink function accepts a source
  return (source) => {
    // reads a value from the source
    source(null, function next (err, value) {
      // handle the result
      if (err) return handleError(err)
      handleValue(value)

      // recursively call source again!
      source(null, next)
    })
  }
}

???

function log (source) {
  source(null, function next (err, data) {
    if (err) return console.log(err)
    console.log(data)
    // recursively call source again!
    source(null, next)
  })
}

with continuables:

function log (source) {
  return (callback) => {
    source(null, function next (err, data) {
      if (err) return callback(err)
      console.log(data)
      // recursively call source again!
      source(null, next)
    })
  }
}

class: success

sink usage

const values = require('pull-stream/sources/values')
const drain = require('pull-stream/sinks/drain')

const source = values([0, 1, 2, 3])
const log = drain(console.log)

log(source)
// 0
// 1
// 2
// 3

class: success

through spec

function createThrough (...args) {
  // a sink function: accept a source
  return (source) => {
    // but return another source!
    return (abort, callback) {
      // ...
    }
  }
}

???

function map (mapper) {
  // a sink function: accept a source
  return function (source) {
    // but return another source!
    return function (abort, callback) {
      source(abort, function (err, data) {
        // if the stream has ended, pass that on.
        if (err) callback(err)
        // apply a mapping to that data
        else callback(null, mapper(data))
      })
    }
  }
}

class: success

through usage

const values = require('pull-stream/sources/values')
const drain = require('pull-stream/sinks/drain')
const map = require('pull-stream/throughs/map')

const source = values([0, 1, 2, 3])
const log = drain(console.log)
const double = map(x => x * 2)

log(double(source))
// 0
// 2
// 4
// 6

class: success

compose pull streams

pull(source, through, sink) === sink(through(source))

pull(source, through) // returns source

pull(through, sink) // returns sink

pull(source, sink) // runs to end

class: success

wild pull streams

ecosystem of modules: pull-stream.github.io

// parse a csv file
pull(
  File(filename),
  CSV(),
  pull.drain(console.log)
)

function CSV () {
  return pull(
    Split(), // defaults to '\n'
    pull.map(function (line) {
      return line.split(',')
    })
  )
}

???

obviously you don't want to re-implement simple streams from scratch all the time


class: center, info

why should you be a JavaScript luddite?


class: success

better performance

software performance is

less about gaining muscle

more about losing weight

???


class: success

easier to describe

specification is a function signature,

not a complex state machine

???


class: success

path to mastery

learnable tools focused on power users

<img src="./training-wheels.jpg" height="350" class="center" />

???


class: center, info

stories


class: warning

story: catstack

build a framework from scratch, alone

<img src="./catstack.jpg" height="350" class="center" />

???

reinvent every wheel possible! the entire web stack.

https://github.com/root-systems/catstack

i did it, but it was unsustainable, unable to transfer context to team


class: warning

learning:

yay, reinventing wheels for fun and learning

boo, the world on your shoulders

???

pros

cons


class: info

revised: dogstack

choose your battles

<img src="./dogstack.jpg" height="350" class="center" />

???

focus on what you do best

delegates parts where you are only marginally better

http://dogstack.js.org/


class: success

story: patch ecosystem

bring-your-own-JavaScript potluck

<img src="./patchwork.png" height="350" class="center" />

???

build an app with others, bring your own JavaScript opinions

references:


class: success, center

offline social media

patchwork.campjs.com
& scuttlebutt.nz

<img src="./patchwork-screenshot.jpg" height="400" class="center" />


class: success, center

git projects

npm install -g git-ssb

<img src="./git-ssb-screenshot.png" height="400" class="center" />


class: success

learning: mad science works!

follow your passion

find others who share your passion

???


class: center, info

conclusion


class: info

so what

everyone has opinions.

this one is mine. =^.^=

???

as my Mom always says:

it's not about being right, it's about being successful

takaways

aids

blocks


class: info

all the "standards"

make up your own opinions!

your opinion about JavaScript is valid.

???

at the end of the day, standards are just somebody's opinion.


class: info

questions?


class: success

thanks!

i appreciate the gift of your attention. ♥

<img src="./follow_your_dreams.png" height="300" class="center" />

<!-- image credit to @substack -->

???

references

luddite.js apps

Built with git-ssb-web