How to Write Big Apps (Richard Rodger NodeDublin 2012)

Preview:

Citation preview

HOW TO WRITE BIG APPS.Richard Rodger@rjrodger

Friday 26 October 2012

Node.js apps are getting bigger.

Friday 26 October 2012

So, how do you scale?‣be stateless, ‣lots of little processes,‣funky V8 options,‣...

Friday 26 October 2012

NO

Friday 26 October 2012

How do you scale this?

Friday 26 October 2012

Let's write a class for Cars.

Friday 26 October 2012

Classicalfunction Car( params ) { this.color = params.color || "red" this.marque = params.marque || "Ferrari" this.model = params.model || "Testarossa" this.cylinders = params.cylinders || 12 this.timeto60 = params.timeto60 || 5.2 // seconds }

Car.prototype.drive = function() { console.log( "vrooom!" )}

var car = new Car({color:"yellow"})car.drive()

Friday 26 October 2012

Classicalfunction Car( params ) { this.color = params.color || "red" this.marque = params.marque || "Ferrari" this.model = params.model || "Testarossa" this.cylinders = params.cylinders || 12 this.timeto60 = params.timeto60 || 5.2 // seconds }

Car.prototype.drive = function() { console.log( "vrooom!" )}

var car = new Car({color:"yellow"})car.drive()

VOTENOW

Friday 26 October 2012

Prototypicalvar Car = { color: "red", marque: "Ferrari", model: "Testarossa", cylinders: 12, timeto60: 5.2, drive: function() { console.log( "vrooom!", this ) }}

var car = Object.create(Car)car.color = "yellow"car.drive()

Friday 26 October 2012

Prototypicalvar Car = { color: "red", marque: "Ferrari", model: "Testarossa", cylinders: 12, timeto60: 5.2, drive: function() { console.log( "vrooom!", this ) }}

var car = Object.create(Car)car.color = "yellow"car.drive()

VOTENOW

Friday 26 October 2012

Functionalfunction Car( params ) { var self = {}

var color = params.color || "red" var marque = params.marque || "Ferrari" var model = params.model || "Testarossa" var cylinders = params.cylinders || 12 var timeto60 = params.timeto60 || 5.2

self.drive = function() { console.log( "vrooom!", self ) } return self}var car = Car({color:"yellow"})car.drive()

Friday 26 October 2012

Functionalfunction Car( params ) { var self = {}

var color = params.color || "red" var marque = params.marque || "Ferrari" var model = params.model || "Testarossa" var cylinders = params.cylinders || 12 var timeto60 = params.timeto60 || 5.2

self.drive = function() { console.log( "vrooom!", self ) } return self}var car = Car({color:"yellow"})car.drive()

VOTENOW

Friday 26 October 2012

Which one should we use for Cars?

Friday 26 October 2012

Let's play a GAME.

Friday 26 October 2012

Stand up.

Friday 26 October 2012

Stand up.Everybody.

Friday 26 October 2012

Is this a car?

Friday 26 October 2012

YES NOStay standing. Sit down.

And stay down!

Friday 26 October 2012

Is this a car?

Friday 26 October 2012

Is this a car?

Friday 26 October 2012

Is this a car?

Friday 26 October 2012

Is this a car?

Friday 26 October 2012

Is this a car?

Friday 26 October 2012

Is this a car?

Friday 26 October 2012

Is this a car?It's a painting.

Friday 26 October 2012

Which one?‣Classical‣Prototypical‣Functional

Friday 26 October 2012

Which one?‣Classical‣Prototypical‣Functional

NONE!Friday 26 October 2012

‣Color - Lego?‣Marque - Batman brand?‣Model - Flintstones?‣Cylinders - Star Wars hover car?‣timeto60 - Model T max is 45mph

What's wrong with properties?

Friday 26 October 2012

Classes are ideal Platonic forms.

Friday 26 October 2012

‣Sides - 3!‣Points - 3!‣Total of Angles - 180°!

Think of the ideal triangle.

Friday 26 October 2012

‣Sides - 3!‣Points - 3!‣Total of Angles - 180°!

Think of the ideal triangle.

Now picture it in your mind.

Friday 26 October 2012

Plato was wrong.Ideal forms do not exist.

Friday 26 October 2012

George Berkeley

berkeley.edusame guy

also Irish!Friday 26 October 2012

Inventor of...

Friday 26 October 2012

Friday 26 October 2012

There is no mental image of a ideal triangle.

Friday 26 October 2012

Classes suck.Objects are ok.

Friday 26 October 2012

Classes suck.Objects are ok.inherit

ance

Friday 26 October 2012

Classes suck.Objects are ok.inherit

ancerefactoring

Friday 26 October 2012

Classes suck.Objects are ok.inherit

ancerefactoring

architecture

Friday 26 October 2012

Classes suck.Objects are ok.inherit

ance

enca

psul

atio

n

refactoring

architecture

Friday 26 October 2012

Classes suck.Objects are ok.inherit

ance

enca

psul

atio

n

refactoring

architecture

schemas

Friday 26 October 2012

Classes suck.Objects are ok.inherit

ance

enca

psul

atio

npo

lym

orph

ism

refactoring

architecture

schemas

Friday 26 October 2012

Classes suck.Objects are ok.inherit

ance

enca

psul

atio

npo

lym

orph

ism

unit testing

refactoring

architecture

schemas

Friday 26 October 2012

Classes suck.Objects are ok.inherit

ance

enca

psul

atio

npo

lym

orph

ism

unit testing

refactoring

architecture

schemas

dependencies

Friday 26 October 2012

Something is wrong with modeling a car.

Friday 26 October 2012

But you can still drive all those cars.

Friday 26 October 2012

It's not what you are.It's what you do.

Friday 26 October 2012

‣Register a new user,‣Place an order,‣Call an external service,‣Save and load data,‣...

What does your app want to do?

Friday 26 October 2012

This is JavaScriptJSON JSONfunction

A command for your app,

that "does stuff"

OUTPUT, asynchronously,

of courseINPUT(mostly in-

memory objects)

Friday 26 October 2012

How do you find the right "thing to do"?

Friday 26 October 2012

How do you find the right "thing to do"?PATTERN MATCHING!

Friday 26 October 2012

{ thing: "product", cmd: "save",

... other fields}

{ thing: "product", cmd: "load",

... other fields}

doSave()

doLoad()

Friday 26 October 2012

Define your "business logic" in terms of these commands.

Friday 26 October 2012

What do you get as the pay off?

Friday 26 October 2012

Really easy testing.Verify the returned JSON and you're done.

Friday 26 October 2012

A distributed system, if you need it.That gives you scale too.

Friday 26 October 2012

Completely decoupledcommands that never need to know about each other.

Friday 26 October 2012

Plugins for free - just bundle up a few related commands.Organize your code!

Friday 26 October 2012

middleware-style layering - e.g. add a caching layer by matching data storage commands.

Friday 26 October 2012

Stay in control - tracing, logging, throttling, permissions, special cases - all easy.

Friday 26 October 2012

Documentation - just list all the commands and the JSON they expect.

Friday 26 October 2012

Code!Open sourced at http://senecajs.orgnpm install seneca

Friday 26 October 2012

var seneca = require('seneca')()

// define a commandseneca.add({role:'math', cmd:'sum'}, function(args,callback) { var sum = args.left + args.right callback(null,{answer:sum}) })

// call the commandseneca.act({role:'math', cmd:'sum', left:1, right:2}, function(err,result) { if( err ) return console.error( err ) console.log(result) })

// prints: { answer: 3 }

Define and call a command.

Friday 26 October 2012

// define a commandseneca.add({role:'math', cmd:'sum'}, function(args,callback) { var sum = args.left + args.right callback(null,{answer:sum}) })

// pin the APIvar math = seneca.pin({role:'math',cmd:'*'})

// call the commandmath.sum({left:1,right:2}, function(err,result) { console.log(result) })

// prints: { answer: 3 }

Pinning an API for convenience

Friday 26 October 2012

seneca.use( function(seneca,options,callback) { seneca.add( {role:'math', cmd:'sum'}, function(args,callback) { var sum = args.left + args.right callback(null,{answer:sum}) })

seneca.add( {role:'math', cmd:'product'}, function(args,callback) { var product = args.left * args.right callback(null,{answer:product}) })

callback( null, seneca.http({ // just a connect middleware pin: {role:'math', cmd:'*'}, map: { sum: {}, product: {} }, // GET is the default HTTP method args: { left: parseFloat, right: parseFloat } }))})

var app = connect() .use(connect.query()) .use(seneca.service()) .listen(3000)// http://localhost:3000/api/sum?left=1&right=2

Plugins: commands + HTTP API.

Friday 26 October 2012

// client: // use transport plugin to calculate product remotelyseneca.use('transport',{ pins:[ {role:'math', cmd:'product'} ]})

// this will go out over networkseneca.act({role:'math', cmd:'product', left:3, right:4}, function(err,result) { if( err ) return console.error( err ) console.log(result) })

// server (as per previous slide):seneca.use('transport')...app.use( connect.json() )...

Build a distributed system

Friday 26 October 2012

var product = seneca.make('product')product.name = 'apple'product.price = 100

// ActiveRecord-styleproduct.save$(function( err, product ) { if( err ) return console.error( err ) console.log( 'saved: '+product )

// product.id was generated for you product.load$({id:product.id},function( err, product ) { if( err ) return console.error( err ) console.log( 'loaded: '+product ) })})

// output:// saved: //product:{id=286624;name=apple;price=100}// loaded: //product:{id=286624;name=apple;price=100}

// mix-and-match in-memory, MongoDB, MySQL, PostreSQL, etc.

Data storage (also plugin-based)

Friday 26 October 2012

Also, seneca...‣is about 18 months old‣has detailed tracing‣has nice error messages‣has a REPL! @dshaw happy?‣is used in production

Friday 26 October 2012

Why did we built it? builds Minimum Viable Products that become big apps.

Friday 26 October 2012

senecajs.org@nodeseneca

Thanks!

Friday 26 October 2012

Recommended