Introduction to Turtle

Construct, Connect, & Scale code

Erica Windisch

Docker alumni and "Clouderati", 15 years experience in pioneering cloud architecture.

Apache 2.0 licensed

NodeJS module

CLI tool

Social coding

Embeddable in Go (others coming)

Turtle is...

Construct

Developers write CommonJS modules and combine them to create applications.

 

We can automatically combine user modules to create new and complex application workflows.

Connect

Just as a lambda is a blackbox,

so are APIs. Chain web services as you do functions.

 

Combined with code-building, your application can easily speak to any web service.

Scale

Because modules implementing functions are stateless and self-contained, they're easily dispatched to remote workers.

 

IOpipe simplifies the use of multi-threaded, parallelized, and distributed computing.

Code written for IOpipe can scale automatically.

Built for devs.

The goal of IOpipe is to make it easier to develop, integrate, and scale applications.

Integrate IOpipe into your application and immediately see the benefits of scale. As the number of users of IOpipe increase, more kernels will be available, simplifying development and integration efforts.

Built for sharing.

Share your code and allow others to construct new workflows with the pieces. IOpipe is the ultimate "DRY" tool which advocates small, reusable functions that can be shared and automatically recomposed by your team.

Built for IoT

The ability to connect to anything and effortlessly scale compute is an IoT unicorn.


IOpipe runs natively on the Tessel platform, and SBCs with Linux or Windows such as the RaspberryPI.

 

IOpipe is designed to be embeddable in languages such as C for running on a range of devices.

Kernels

  • HTTP URLs (GET or POST)
  • Native Functions
  • CommonJS modules
module.exports = function(input, context) {
  context.done(i)
}
module.exports.iopipe_typedef = {
  "in": "*",
  "out": "*"
}

Smallest "useful" kernel

# Import a kernel and name it com.example.SomeScript
$ iopipe import --name com.example.SomeScript - <<EOF
module.exports = function(_, context) {
  context.done()
}
EOF
d9cb4fc46fd196806eab5906a5e125326ab59b1d096b189c485f298ef5093596

# List kernels
$ iopipe list
d9cb4fc46fd196806eab5906a5e125326ab59b1d096b189c485f298ef5093596
com.example.SomeScript

Management CLI


# Fetch response and process it with com.example.SomeScript
$ iopipe exec https://api.justyo.co/status/yoteam \
              com.example.SomeScript

# Fetch response and convert it with SomeScript, sending the result to otherhost
$ iopipe exec https://api.justyo.co/status/yoteam \
              com.example.SomeScript \
              http://otherhost.example.com/request

# Fetch response and convert it with SomeScript, send that result to otherhost,
# & converting the response with the script ResponseScript
$ iopipe exec http://localhost/some-request com.example.SomeScript \
              http://otherhost.example.com/request \
              some.example.ResponseScript

# Export an NPM module:
$ iopipe export --name my-module-name \
                http://localhost/some-request \
                com.example.SomeScript

Management CLI

// Get number of commits by the top 100 contributors to iopipe
var iopipe = require("iopipe")

iopipe.exec("http://requestb.in/api/v1/bins"
                           ,JSON.parse
                           ,iopipe.property("name")
                           ,
function(name) {
  var rbin = "http://requestb.in/"+name

  iopipe.exec(
    "https://api.github.com/repos/iopipe/iopipe/stats/contributors"
    ,iopipe.callback(JSON.parse)
    ,iopipe.map(iopipe.property("total"))
    ,iopipe.reduce(function(x, y) { return x + y })
    ,rbin
  )
  console.log('<a href="' + rbin + '?inspect">View at requestb.in</a>')
})

NodeJS SDK

// Get number of commits by the top 100 contributors to iopipe
var iopipe = require("iopipe")

iopipe.exec("http://requestb.in/api/v1/bins"
            ,iopipe.callback(JSON.parse)
            ,iopipe.property("name")
            ,iopipe.define(
               iopipe.tee(iopipe.define('<a href="'.concat
                                        ,iopipe.apply(
                                          "concat"
                                          ,'?inspect">'+
                                           'View at requestb.in</a>'))
                         ,iopipe.define(
                           "https://api.github.com/repos/iopipe/" +
                                      "iopipe/stats/contributors"
                           ,iopipe.callback(JSON.parse)
                           ,iopipe.map(iopipe.property("total"))
                           ,iopipe.reduce(function(x, y) {
                                          return x + y })
                         )
              )
            )
)

Functional syntax accepted

/* script1: Maps key-value pairs to an HTTP query string */
module.exports = function(input, context) {
  var query = ""
  for (var k in input) {
    if (query === "") {
      query += "?"
    } else {
      query += "&"
    }
    query = k + "=" + input[k]
  }
  context.done(query)
}
module.exports.iopipe_typedef = {
  "in": "dictionary"
  ,"out": "HTTPQuery"
}

/* script2: Fetches hacker news top stories, filtered by a FirebaseQuery */
module.exports = function(input, context) {
  var url = "https://hacker-news.firebaseio.com/v0/topstories.json"
  iopipe.define(iopipe.callback(url.concat),
               ,iopipe.fetch, iopipe.callback(JSON.parse)
               ,context.done)(query)
}
module.exports.iopipe_typedef = {
  "in": ["FirebaseQuery", "HTTPQuery"]
  ,"out": "[]HNitem.id"
}

HackerNews Top Stories

$ iopipe exec script1 script2 <<<'{ key: "value" }'

$ iopipe import --name searchHNUserNick <<EOF
module.exports = function(nick, context) {
  iopipe.define("https://hacker-news.firebaseio.com/v0/item/".concat
                ,iopipe.callback(JSON.parse), iopipe.property("by")
                ,iopipe.tee(echo, "hasUserLinkedIn", "hasUserGitHub",context.done))
               (nick)
}
function echo(i, cb) { cb(i) }
EOF
$ iopipe import --name hasUserLinkedIn <<EOF
module.exports = function(nick, context) {
  try { iopipe.fetch("https://www.linkedin.com/in/".concat, function(_, c) { c.done(true) }
                 , context.done) } catch(e) { context.fail() }
}
EOF
$ iopipe import --name hasUserGitHub <<EOF
module.exports = function(nick, context) {
  try { iopipe.fetch("https://www.github.com/".concat, function(_, c) { c.done(true) }
                 ,context.done) } catch(e) { context.fail() }
}
EOF
$ iopipe import --name mapSearchUserHNTopstories <<EOF
module.exports = function(_, context) {
  iopipe.exec("https://hacker-news.firebaseio.com/v0/topstories.json"
             ,iopipe.callback(JSON.parse)
             ,iopipe.map("searchHNUserNick"), context.done)
}
EOF

$ iopipe exec --dispatch=aws-lambda mapSearchUserHNTopstories
[ "ewindisch", true, true ]
...

Distributed compute

(work in progress)

https://hacker-news.firebaseio.com/v0/topstories.json

JSON.parse

map

searchHNUserNick

searchHNUserNick

searchHNUserNick

searchHNUserNick

"https://hacker-news.firebaseio.com/v0/item/".concat

iopipe.property("by")

tee

echo

hasUserLinkedIn

hasUserGithub

[ "someuser", true, false]

 [ [ "someuser", true, false], ["user2", false, false], ["user3", true, true] ]

Distributed compute

Thank you


Questions?


erica@iopipe.com

@ewindisch  

Join the IOpipe community at
https://github.com/iopipe/iopipe

Additional material

$ iopipe import --name getHNitemByID <<EOF
module.exports = function(HNitemID, context) {
  iopipe.define("https://hacker-news.firebaseio.com/v0/item/".concat
                ,iopipe.callback(JSON.parse), context.done)(HNitemID)
}
EOF
$ iopipe import --name getHNitemUsername <<EOF
module.exports = function(HNitem, context) { context.done(HNitem.by) }
EOF
$ iopipe import --name searchUserByNick <<EOF
module.exports = function(nick, context) {
  iopipe.tee(echo, "hasUserLinkedIn", "hasUserGitHub",context.done)
}
function echo(i, cb) { cb(i) }
EOF
$ iopipe import --name hasUserLinkedIn <<EOF
module.exports = function(nick, context) {
  try { iopipe.fetch("https://www.linkedin.com/in/".concat, function(_, c) { c.done(true) }
                 , context.done) } catch(e) { context.fail() }
}
EOF
$ iopipe import --name hasUserGitHub <<EOF
module.exports = function(nick, context) {
  try { iopipe.fetch("https://www.github.com/".concat, function(_, c) { c.done(true) }
                 ,context.done) } catch(e) { context.fail() }
}
EOF
$ iopipe import --name mapSearchUserHNTopstories <<EOF
module.exports = function(_, context) {
  iopipe.exec("https://hacker-news.firebaseio.com/v0/topstories.json"
             ,iopipe.callback(JSON.parse)
             ,iopipe.map("getHNitemByID", "getHNitemUsername", "searchUserByNick"), context.done)
}
EOF

$ iopipe exec --dispatch=aws-lambda mapSearchUserHNTopstories
[ "ewindisch", true, true ]
...

DRY distributed map

(work in progress)

Introduction to Turtle

By Erica Windisch

Introduction to Turtle

Writing code - with turtles all the way down

  • 1,863