KEMBAR78
Introducing the Seneca MVP framework for Node.js
seneca
 nodejsdublin
16 August 2012

Richard Rodger
   @rjrodger
hello
nodejsdublin
 • let's start a community project
 • how Node.js modules work
 • introducing the seneca module
getting
    started
• how do you learn Node.js?
• how do you contribute to Node.js?
• how do you get a job doing Node.js?
your
community
• nodejsdublin is for you
• here to help you learn
• here to build a great community
let's start
 a project
• less talking, more coding!
• community project with many coders
• something with lots of small pieces
seneca
• A Minimal Viable Product toolkit
• let's you build a startup in a weekend :)
• for more about MVPs: http://bit.ly/N25FlZ
• Lucius Annaeus Seneca, 4 BC – AD 65
• You have to be stoic to do a startup
• "increases are of sluggish growth, but the way to
  ruin is rapid"
                             * http://cassandralegacy.blogspot.ie/2011/08/seneca-effect-origins-of-collapse.html
sign up
• Tweet @nodejsdublin with #seneca
• Mail me: richard.rodger@nearform.com
• Code: github.com/nodejsdublin/seneca
node.js
   modules
• basic building blocks of Node.js apps
• no special syntax; plain old JavaScript
• no version conflicts!
using modules

var _ = require("underscore");

var threes = _.map([1, 2, 3], function(n){ return n*3 });
console.log( threes );
// prints [3, 6, 9]



var mongo = require('mongodb');

var host = 'localhost';
var port = 27017;

var db   = new mongo.Db( 'mydatabase',
  new mongo.Server(host, port, {}), {});

db.open(function(err, db) { ... }
cool
        modules
• express - JSP/ASP style dynamic server-side pages
• socket.io - HTML5 real-time web sockets that "just work"
• request - easy outbound calls to web services
using npm
• npmjs.org - module repository of record
• usage: npm install modulename
• modules live in local node_modules folder
how to pick
 a module
•   serious modules are on https://github.com/joyent/node/wiki/modules
•   popularity! check watchers/issues on github
•   documentation, including third party blogs
•   ask the community: http://nodejs.org/community/
why npm
  rocks
• modules are installed separately for each project
• dependencies are also installed separately
• no global conflicts, no cross-dependency
  conflicts
package.json
 • defines a module; lists dependencies
 • always create one for each project
 • npm install will set up dependencies for you!
package.json
{
  "name"         : "optimist",
  "version"      : "0.3.4",
  "description" : "Light-weight option parsing.",
  "main"         : "./index.js",
 
  "dependencies" : {
     "wordwrap" : ">=0.0.2"
  },

  "repository"   : {
    "type" : "git",
    "url" : "http://github.com/substack/node-optimist.git"
  },

  "keywords"    : [ "argument", "args", "option", "parser" ]
  "author"      : { "name" : "James Halliday" },
  "engine"      : { "node" : ">=0.4 }
}
write a
    module
• create a project on github
• npm init - creates package.json for you
• start with lib/modulename.js
modulename.js
"use strict";

function ModuleName() {
  var self = {};

    var private = "hidden";

    self.member = "data";

    self.method = function() { ... };

    return self;
}

exports.ModuleName = ModuleName


                     callingcode.js
    var modulename = require('modulename')

    var instance = new modulename.ModuleName()
parambulator
•   written just for this meetup! - sanity checks JSON data structures
•   https://github.com/rjrodger/parambulator
•   you also need a README.md and LICENSE.txt
•   you really should have unit tests; try the vows module
file structure
parambulator /

      package.json

      README.md

      LICENSE.txt

      lib /

         parambulator.js
publishing a
  module
• the package.json files property is your friend
• register for an account on npmjs.org
• npm publish
• sit back and bask in the glory...
seneca
• nearForm builds web/mobile services
• shared set of features every startup needs
• ... must resist ... let's build a framework!
shared
     features
•   user accounts: login/logout, profile pages, social media, ...
•   email: transactional, promotional, ...
•   e-commerce: gateways, app stores, ...
•   admin: data editors, analytics, audit logs, ..
seneca is in
  production

businesspost.ie   chartaca.com   stanzr.com
command
 pattern
•   actions are represented by a set of properties
•   seneca "executes" them by invoking plugins
•   everything that happens is traceable
•   business logic is insulated from service providers
seneca commands
// register a new user
seneca.act({
   on:       'user',
   cmd:      'register',
   email:    'alice@example.com',
   name:     'Alice',
   password: '1234',
   active:   true
},
function(err, result) { ... })


// send an email
seneca.act({
   on:       'email',
   cmd:      'send',
   to:       'alice@example.com',
   code:     'thanks-for-registering',
   fields:   {name:'Alice'}
},
function(err, result) { ... })
plugins
• everything is a plugin
• plugins provide actions
• plugins are just modules!
seneca plugin
function EchoPlugin() {
  var self = {};
  self.name = 'echo';

    self.init = function(seneca,opts,cb) {

        seneca.add({on:'echo'}, function(args,seneca,cb){
           var out = args
           cb(null,out)
        })

        cb()
    }

    self.service = function() {
      return function(req,res,next){
        if( '/echo' == req.url ) {
          res.writeHead(200);
          res.end(req.url);
        }
        else next();
      }
    }
}

exports.plugin = function() {
  return new EchoPlugin()
}
shared
data model
• Built-in ODM - Object Document Mapper
• You need this to stay sane
• ActiveRecord-ish API with MongoDB-ish queries
seneca data model
var product = seneca.make('product');

product.name = 'Apple';
product.price = 1.99;

product.save$(function(err,savedproduct){
   console.log('generated id: '+savedproduct.id);
})

product.load$('1234',function(err,foundproduct){
   console.log('found product '+foundproduct);
})

product.list$( {price:1.99}, function(err,list){
   for( var i = 0; i < list.length; i++ ) {
     console.log( list[i] );
   }
})
what we
•
 have now
  messy code that kinda sorta works
• a few hackety hack plugins
• no documentation!
what we
     need
• plugins! plugins! plugins!
• documentation ( ... just kidding! I'll do that)
• some nodeknockout.com entries -
   November 10-12th! Fame & Glory Await!
let's code!
• Tweet @nodejsdublin with #seneca
• Mail me: richard.rodger@nearform.com
• Code: github.com/nodejsdublin/seneca

Introducing the Seneca MVP framework for Node.js

  • 1.
    seneca nodejsdublin 16 August2012 Richard Rodger @rjrodger
  • 2.
    hello nodejsdublin • let'sstart a community project • how Node.js modules work • introducing the seneca module
  • 3.
    getting started • how do you learn Node.js? • how do you contribute to Node.js? • how do you get a job doing Node.js?
  • 4.
    your community • nodejsdublin isfor you • here to help you learn • here to build a great community
  • 5.
    let's start aproject • less talking, more coding! • community project with many coders • something with lots of small pieces
  • 6.
    seneca • A MinimalViable Product toolkit • let's you build a startup in a weekend :) • for more about MVPs: http://bit.ly/N25FlZ
  • 7.
    • Lucius AnnaeusSeneca, 4 BC – AD 65 • You have to be stoic to do a startup • "increases are of sluggish growth, but the way to ruin is rapid" * http://cassandralegacy.blogspot.ie/2011/08/seneca-effect-origins-of-collapse.html
  • 8.
    sign up • Tweet@nodejsdublin with #seneca • Mail me: richard.rodger@nearform.com • Code: github.com/nodejsdublin/seneca
  • 9.
    node.js modules • basic building blocks of Node.js apps • no special syntax; plain old JavaScript • no version conflicts!
  • 10.
    using modules var _= require("underscore"); var threes = _.map([1, 2, 3], function(n){ return n*3 }); console.log( threes ); // prints [3, 6, 9] var mongo = require('mongodb'); var host = 'localhost'; var port = 27017; var db = new mongo.Db( 'mydatabase', new mongo.Server(host, port, {}), {}); db.open(function(err, db) { ... }
  • 11.
    cool modules • express - JSP/ASP style dynamic server-side pages • socket.io - HTML5 real-time web sockets that "just work" • request - easy outbound calls to web services
  • 12.
    using npm • npmjs.org- module repository of record • usage: npm install modulename • modules live in local node_modules folder
  • 13.
    how to pick a module • serious modules are on https://github.com/joyent/node/wiki/modules • popularity! check watchers/issues on github • documentation, including third party blogs • ask the community: http://nodejs.org/community/
  • 14.
    why npm rocks • modules are installed separately for each project • dependencies are also installed separately • no global conflicts, no cross-dependency conflicts
  • 15.
    package.json • definesa module; lists dependencies • always create one for each project • npm install will set up dependencies for you!
  • 16.
    package.json {   "name" : "optimist",   "version" : "0.3.4",   "description" : "Light-weight option parsing.", "main" : "./index.js",     "dependencies" : {      "wordwrap" : ">=0.0.2"   },   "repository" : {     "type" : "git",     "url" : "http://github.com/substack/node-optimist.git"   },   "keywords" : [ "argument", "args", "option", "parser" ]   "author" : { "name" : "James Halliday" }, "engine" : { "node" : ">=0.4 } }
  • 17.
    write a module • create a project on github • npm init - creates package.json for you • start with lib/modulename.js
  • 18.
    modulename.js "use strict"; function ModuleName(){ var self = {}; var private = "hidden"; self.member = "data"; self.method = function() { ... }; return self; } exports.ModuleName = ModuleName callingcode.js var modulename = require('modulename') var instance = new modulename.ModuleName()
  • 19.
    parambulator • written just for this meetup! - sanity checks JSON data structures • https://github.com/rjrodger/parambulator • you also need a README.md and LICENSE.txt • you really should have unit tests; try the vows module
  • 20.
    file structure parambulator / package.json README.md LICENSE.txt lib / parambulator.js
  • 21.
    publishing a module • the package.json files property is your friend • register for an account on npmjs.org • npm publish • sit back and bask in the glory...
  • 22.
    seneca • nearForm buildsweb/mobile services • shared set of features every startup needs • ... must resist ... let's build a framework!
  • 23.
    shared features • user accounts: login/logout, profile pages, social media, ... • email: transactional, promotional, ... • e-commerce: gateways, app stores, ... • admin: data editors, analytics, audit logs, ..
  • 24.
    seneca is in production businesspost.ie chartaca.com stanzr.com
  • 25.
    command pattern • actions are represented by a set of properties • seneca "executes" them by invoking plugins • everything that happens is traceable • business logic is insulated from service providers
  • 26.
    seneca commands // registera new user seneca.act({ on: 'user', cmd: 'register', email: 'alice@example.com', name: 'Alice', password: '1234', active: true }, function(err, result) { ... }) // send an email seneca.act({ on: 'email', cmd: 'send', to: 'alice@example.com', code: 'thanks-for-registering', fields: {name:'Alice'} }, function(err, result) { ... })
  • 27.
    plugins • everything isa plugin • plugins provide actions • plugins are just modules!
  • 28.
    seneca plugin function EchoPlugin(){ var self = {}; self.name = 'echo'; self.init = function(seneca,opts,cb) { seneca.add({on:'echo'}, function(args,seneca,cb){ var out = args cb(null,out) }) cb() } self.service = function() { return function(req,res,next){ if( '/echo' == req.url ) { res.writeHead(200); res.end(req.url); } else next(); } } } exports.plugin = function() { return new EchoPlugin() }
  • 29.
    shared data model • Built-inODM - Object Document Mapper • You need this to stay sane • ActiveRecord-ish API with MongoDB-ish queries
  • 30.
    seneca data model varproduct = seneca.make('product'); product.name = 'Apple'; product.price = 1.99; product.save$(function(err,savedproduct){ console.log('generated id: '+savedproduct.id); }) product.load$('1234',function(err,foundproduct){ console.log('found product '+foundproduct); }) product.list$( {price:1.99}, function(err,list){ for( var i = 0; i < list.length; i++ ) { console.log( list[i] ); } })
  • 31.
    what we • havenow messy code that kinda sorta works • a few hackety hack plugins • no documentation!
  • 32.
    what we need • plugins! plugins! plugins! • documentation ( ... just kidding! I'll do that) • some nodeknockout.com entries - November 10-12th! Fame & Glory Await!
  • 33.
    let's code! • Tweet@nodejsdublin with #seneca • Mail me: richard.rodger@nearform.com • Code: github.com/nodejsdublin/seneca

Editor's Notes