72
P ROXIES BEFORE PROXIES: THE HIDDEN GEMS OF JAVASCRIPT AOP

Fullstack Conference - Proxies before proxies: The hidden gems of Javascript AOP

Embed Size (px)

DESCRIPTION

Tired of console.logging your way through applications? Want a way to slice through your application without adding complexity? AOP has been the answer to these questions for object oriented languages, such as Java and C#, but is not available in Javascript. ScarletJS(https://github.com/scarletjs/scarlet) is a project that tackles AOP using a clean, fluent, performant interface. The ScarletJS project provides Javascript developers a different way of thinking about traditional javascript problems. The project is still growing and looking into the future of what ES6 proxies will open up to the Javascript community. The talk will highlight the problems that javascript developers face with logging application behavior, security, and more. It will discuss the benefits of identifying a cross cutting concern, and programming using aspects. The talk will highlight how thinking about a project and cross cutting concerns can lead to cleaner more SOLID code. It will also discuss the future of ES6 proxies and the benefits that they will bring.

Citation preview

Page 1: Fullstack Conference -  Proxies before proxies: The hidden gems of Javascript AOP

PROXIES BEFORE

PROXIES: THE HIDDEN

GEMS OF JAVASCRIPT AOP

Page 2: Fullstack Conference -  Proxies before proxies: The hidden gems of Javascript AOP

1 - SHOES

Page 3: Fullstack Conference -  Proxies before proxies: The hidden gems of Javascript AOP

2 - GLOVES

Page 4: Fullstack Conference -  Proxies before proxies: The hidden gems of Javascript AOP

3 - JUMPER

Page 5: Fullstack Conference -  Proxies before proxies: The hidden gems of Javascript AOP

4 – COAT TAILS

Page 6: Fullstack Conference -  Proxies before proxies: The hidden gems of Javascript AOP

SCARLETJS

The simple fast JavaScript interceptor.

Page 7: Fullstack Conference -  Proxies before proxies: The hidden gems of Javascript AOP

SCARLETJS

• API fluent interface

• Readability

• Performance

• Use of Core features

• Lack of ability to use common proxies

• Challenge

• And to have a little fun

Page 8: Fullstack Conference -  Proxies before proxies: The hidden gems of Javascript AOP

WHAT IS A PROXY?

Page 9: Fullstack Conference -  Proxies before proxies: The hidden gems of Javascript AOP

var awesmeoThing = function(){

}

Page 10: Fullstack Conference -  Proxies before proxies: The hidden gems of Javascript AOP

called awesomeoThing <Any Date> with [X,Y, Z] params executed in .00000001 ms

called awesomeoThing <Any Date> with [X,Y, Z] params executed in .00000001 ms

called awesomeoThing <Any Date> with [X,Y, Z] params executed in .00000001 ms

called awesomeoThing <Any Date> with [X,Y, Z] params executed in .00000001 ms

called awesomeoThing <Any Date> with [X,Y, Z] params executed in .00000001 ms

called awesomeoThing <Any Date> with [X,Y, Z] params executed in .00000001 ms

called awesomeoThing <Any Date> with [X,Y, Z] params executed in .00000001 ms

called awesomeoThing <Any Date> with [X,Y, Z] params executed in .00000001 ms

called awesomeoThing <Any Date> with [X,Y, Z] params executed in .00000001 ms

called awesomeoThing <Any Date> with [X,Y, Z] params executed in .00000001 ms

called awesomeoThing <Any Date> with [X,Y, Z] params executed in .00000001 ms

called awesomeoThing <Any Date> with [X,Y, Z] params executed in .00000001 ms

called awesomeoThing <Any Date> with [X,Y, Z] params executed in .00000001 ms

called awesomeoThing <Any Date> with [X,Y, Z] params executed in .00000001 ms

called awesomeoThing <Any Date> with [X,Y, Z] params executed in .00000001 ms

called awesomeoThing <Any Date> with [X,Y, Z] params executed in .00000001 ms

called awesomeoThing <Any Date> with [X,Y, Z] params executed in .00000001 ms

called awesomeoThing <Any Date> with [X,Y, Z] params executed in .00000001 ms

called awesomeoThing <Any Date> with [X,Y, Z] params executed in .00000001 ms

Page 11: Fullstack Conference -  Proxies before proxies: The hidden gems of Javascript AOP

var awesomeoThing = function(x,y,z){

var startTime = new Date();

var endTime = new Date();

console.log(‘called awesomeoThing‘ + new Date()

+ ’ with params:’

+ [x,y,z]

+ ’ executed in:’

+ endTime-startTime);

}

Page 12: Fullstack Conference -  Proxies before proxies: The hidden gems of Javascript AOP
Page 13: Fullstack Conference -  Proxies before proxies: The hidden gems of Javascript AOP

Public class AnyClass{

Public void awesmeoThing(int x,int y,int z){

}

}

Page 14: Fullstack Conference -  Proxies before proxies: The hidden gems of Javascript AOP

@Component

@Aspect

public class MyLogger{

@Around("execution(* com.my.messaging..*.*(..))")

public Object logAfterMethod(ProceedingJoinPoint joinPoint) throws Throwable {

Logger log = Logger.getLogger(joinPoint.getTarget().getClass());

StopWatch stopWatch = new StopWatch();

stopWatch.start();

Object retVal = joinPoint.proceed();

stopWatch.stop();

….

System.out.println(“called: “

+ joinPoint.getTarget().getClass().getName()

+ “ with args: “

+ args

+ “executed in: “

+ stopWatch.getTotalTimeMillis());

}

}

Page 15: Fullstack Conference -  Proxies before proxies: The hidden gems of Javascript AOP

OK…SO WHAT ARE

PROXIES?

And what happened to the JavaScript?

Page 16: Fullstack Conference -  Proxies before proxies: The hidden gems of Javascript AOP

Var wrapper = function(){

var startTime = new Date();

var result = awesmeoThing();

var endTime = new Date();

console.log(‘called awesomeoThing‘

+ new Date()

+ ’ with params:’

+ [x,y,z]

+ ’ executed in:’

+ endTime-startTime);

return result;

}

Page 17: Fullstack Conference -  Proxies before proxies: The hidden gems of Javascript AOP

var wrapper = function(){

var startTime = new Date();

var result = awesmeoThing();

var endTime = new Date();

console.log(‘called awesomeoThing‘

+ new Date()

+ ’ with params:’

+ x+y+z

+ ’ executed in:’

+ endTime-startTime);

return result;

}

var awesomeoThing = function(x,y,z){

var startTime = new Date();

var endTime = new Date();

console.log(‘called awesomeoThing‘

+ new Date()

+ ’ with params:’

+ x+y+z

+ ’ executed in:’

+ endTime-startTime);

}

Page 18: Fullstack Conference -  Proxies before proxies: The hidden gems of Javascript AOP
Page 19: Fullstack Conference -  Proxies before proxies: The hidden gems of Javascript AOP

WHAT’S OUT THERE

TODAY?

• Hooker by Ben Alman (Cowboy) (Author and

main contributor of grunt)

• “Monkey-Patch(hook) functions for debugging

and stuff” – Github Readme

• Hooks by Brian Noguchi(bnoguchi)

• “Add pre and post middleware hooks to your

JavaScript methods.”

Page 20: Fullstack Conference -  Proxies before proxies: The hidden gems of Javascript AOP

HOOKER

hooker.hook(Math, "max", function() {

console.log(arguments.length + " arguments passed");

});

// logs: "3 arguments passed"

Math.max(5, 6, 7)

Page 21: Fullstack Conference -  Proxies before proxies: The hidden gems of Javascript AOP

HOOKJS

• create an instance of the thing

var instance = new awesemoThing();

• assign each member of the hooks implementation into the object

for(var k in hooks){

Instance[k] = hooks[k];

}

• Implement a method to implement before underlying method is called:

instance.pre(‘method’,function(next){

})

• Implement a post method to get called after the underlying method is called:

Instance.post(‘method’,function(next){

})

Page 22: Fullstack Conference -  Proxies before proxies: The hidden gems of Javascript AOP

EXISTING

IMPLEMENTATIONS

• Imbedded in popular projects

• We want to do it

• API and Module design

Page 23: Fullstack Conference -  Proxies before proxies: The hidden gems of Javascript AOP
Page 24: Fullstack Conference -  Proxies before proxies: The hidden gems of Javascript AOP

API FLUENT

INTERFACE

myFunction.do(<SOMETHING>)

.do(<SOMETHING_ELSE>)

.andDoMore();

Page 25: Fullstack Conference -  Proxies before proxies: The hidden gems of Javascript AOP

READABILITY

Page 26: Fullstack Conference -  Proxies before proxies: The hidden gems of Javascript AOP

PERFORMANCE

• Lo-Dash - John-David Dalton

• Best of breed - https://github.com/beastiejs

Page 27: Fullstack Conference -  Proxies before proxies: The hidden gems of Javascript AOP

USE OF CORE

FEATURES

• No pre and post methods. Use real events

Page 28: Fullstack Conference -  Proxies before proxies: The hidden gems of Javascript AOP

LACK OF ABILITY TO USE

COMMON PROXIES

• Easily be able to pull down and

use a logger, security module, etc

Page 29: Fullstack Conference -  Proxies before proxies: The hidden gems of Javascript AOP

CHALLENGE

Page 30: Fullstack Conference -  Proxies before proxies: The hidden gems of Javascript AOP

AND TO HAVE A LITTLE

FUN…TO MAKE MY CODE

PURR

Page 31: Fullstack Conference -  Proxies before proxies: The hidden gems of Javascript AOP

var purr = scarlet.plugins.purr;

purr.when(Math,'min').play();

Math.min(1,2,3);

Page 32: Fullstack Conference -  Proxies before proxies: The hidden gems of Javascript AOP

SCARLETJS -

THE PROJECT

Page 33: Fullstack Conference -  Proxies before proxies: The hidden gems of Javascript AOP
Page 34: Fullstack Conference -  Proxies before proxies: The hidden gems of Javascript AOP
Page 35: Fullstack Conference -  Proxies before proxies: The hidden gems of Javascript AOP

TESTING

• Tools Used

• Mocha

• Builders

ScarletBuilder.forInstance(<AnyInstance>)

ScarletBuilder.forProperty(<AnyProperty>)

.withInterceptors(<ArrayOfInterceptors>);

ScarletBuilder.forMethod(<AnyMethod>)

.withParameters(<AnyParams>)

.withEvents(<AnyEvents>)

.Assert();

Page 36: Fullstack Conference -  Proxies before proxies: The hidden gems of Javascript AOP
Page 37: Fullstack Conference -  Proxies before proxies: The hidden gems of Javascript AOP

MAKING IT EASY

• Intercept a function, object, or property

• Define event listeners for before and after the intercepted function had been called

• Define multiple functions to do the interception

• Being able to chain method calls together and have a fluent interface

Page 38: Fullstack Conference -  Proxies before proxies: The hidden gems of Javascript AOP

Scarlet.intercept(<ANYTHING>)

Page 39: Fullstack Conference -  Proxies before proxies: The hidden gems of Javascript AOP

Scarlet.intercept(<ANYTHING>)

.on(‘before’,<BEFORE_FUNC>)

.on(‘after’,<AFTER_FUNC>)

.on(‘done’,<DONE_FUNC>)

.on(‘error’,<ERROR_FUNC>);

Page 40: Fullstack Conference -  Proxies before proxies: The hidden gems of Javascript AOP

Scarlet.intercept(<ANYFUNCTION>)

.using(<INTERCEPTOR_FUNC)

Page 41: Fullstack Conference -  Proxies before proxies: The hidden gems of Javascript AOP

Scarlet.intercept(<ANYFUNCTION>)

.using(function(proceed){

//…BEFORE

proceed();

//…AFTER

});

Page 42: Fullstack Conference -  Proxies before proxies: The hidden gems of Javascript AOP

Scarlet.intercept(<ANYFUNCTION>)

.using(function(info, proceed){

//…BEFORE

proceed();

//…AFTER

});

Page 43: Fullstack Conference -  Proxies before proxies: The hidden gems of Javascript AOP

var someProxy = Scarlet.intercept(<ANYFUNCTION>)

.using(<INTERCEPTOR_FUNCTION>)

.proxy();

Page 44: Fullstack Conference -  Proxies before proxies: The hidden gems of Javascript AOP

Var awesemeoThing = function(){}

var someProxy = Scarlet.intercept(awesemeoThing)

.using(function(info, proceed){

var startTime = new Date();

var result = proceed();

var endTime = new Date();

console.log(‘called ‘ +info.methodName

+ new Date()

+ ’ with params:’

+ [x,y,z]

+ ’ executed in:’

+ endTime-startTime);

})

.proxy();

Page 45: Fullstack Conference -  Proxies before proxies: The hidden gems of Javascript AOP

PERFORMANCE

Page 46: Fullstack Conference -  Proxies before proxies: The hidden gems of Javascript AOP

PLUGINS

• Scarlet Passport

• Scarlet-winston

• Scarlet-ioc

• Scarlet-init

Page 47: Fullstack Conference -  Proxies before proxies: The hidden gems of Javascript AOP

var requestListener = scarletPassport

.scarletPassport

.authenticate('local',

{},

requestListener)

Page 48: Fullstack Conference -  Proxies before proxies: The hidden gems of Javascript AOP

scarletWinston.bindTo(Math,'min');

Math.min(1,2,3);

//->info: [Mon Sep 02 2013 00:49:58 GMT+0100 (BST)] calling -

Object::min(1,2,3)

//->info: [Mon Sep 02 2013 00:49:58 GMT+0100 (BST)]

Object::min(1,2,3) - returned:1 - execution time(0:0:0.0)

Page 49: Fullstack Conference -  Proxies before proxies: The hidden gems of Javascript AOP

function MyObjectB(myObjectA){

};

scarlet.plugins.ioc

.register("myObjectA", MyObjectA)

.register("myObjectB", MyObjectB);

var myObjectB = scarlet

.plugins

.ioc

.resolve("myObjectB");

myObjectB.anyMethod();

Page 50: Fullstack Conference -  Proxies before proxies: The hidden gems of Javascript AOP
Page 51: Fullstack Conference -  Proxies before proxies: The hidden gems of Javascript AOP

ES6 - PROXIES

”A proxy object is an exotic object whose essential

internal methods are partially implemented using ECMAScript

code” – ES6 Draft October 2014

Page 52: Fullstack Conference -  Proxies before proxies: The hidden gems of Javascript AOP

var awesemeoFunction = function(){…};

var proxiedObject = new Proxy(awesemeoFunction,{

apply: function(target, receiver, args){

var startTime = new Date();

var result = target(args);

var endTime = new Date();

console.log(‘called awesomeThing‘ + new Date()

+ ’ with params:’

+ args

+ ’ executed in:’

+ endTime-startTime);

return result;

}

});

Page 53: Fullstack Conference -  Proxies before proxies: The hidden gems of Javascript AOP

var awesemeoThing= {};

var proxiedThing = new Proxy(awesemeoThing,{

get: function(target, name){

console.log("In Get Proxy");

return target[name];

}

});

var x = proxiedThing.any;

Page 54: Fullstack Conference -  Proxies before proxies: The hidden gems of Javascript AOP

var awesemeoThing= {};

var proxiedThing = new Proxy(awesemeoThing,{

set: function(target, name, value){

console.log("In Set Proxy");

target[name] = value;

}

});

proxiedThing.any = 'thing';

Page 55: Fullstack Conference -  Proxies before proxies: The hidden gems of Javascript AOP

NODE.JS PROXIES

• Proxies can be enabled using the following commands:

• $ node –harmony-proxies

• $ node --harmony

Page 56: Fullstack Conference -  Proxies before proxies: The hidden gems of Javascript AOP
Page 57: Fullstack Conference -  Proxies before proxies: The hidden gems of Javascript AOP

HARMONY-REFLECT

• Shim so that the current draft implementation of proxies can be used https://github.com/tvcutsem/harmony-reflect

1. Install the module:

• npm install harmony-reflect

2. Require at the top of your js file:

• require(‘harmony-reflect);

3. Run node in harmony mode:

• $ node --harmony

Page 58: Fullstack Conference -  Proxies before proxies: The hidden gems of Javascript AOP

FIREFOX

• Available in versions 18+

Page 59: Fullstack Conference -  Proxies before proxies: The hidden gems of Javascript AOP

PROXIES IN USE –

NEGATIVE ARRAY

Page 60: Fullstack Conference -  Proxies before proxies: The hidden gems of Javascript AOP

var negativeArray = require('negative-array');

var unicorn = negativeArray(['pony',

'cake',

'rainbow']);

console.log(unicorn[-1]);

Page 61: Fullstack Conference -  Proxies before proxies: The hidden gems of Javascript AOP

module.exports = function (arr) {

return new Proxy(arr, {

get: function (target, name) {

var i = +name;

return target[i < 0 ?

target.length + i :

i];

},

}

Page 62: Fullstack Conference -  Proxies before proxies: The hidden gems of Javascript AOP

ANNOTATIONS

• Traceur – Converts ES6 to ES5 runnable code

• https://github.com/google/traceur-compiler

• Install through npm

• Npm install traceur

• Allows for annotations to be used with the following flags:

• traceur <ANY_FILE> --annotations true

Page 63: Fullstack Conference -  Proxies before proxies: The hidden gems of Javascript AOP

@AnyAnnotation

function simpleFunction () {

return 'any';

}

Page 64: Fullstack Conference -  Proxies before proxies: The hidden gems of Javascript AOP

var AnyAnnotation = function() {};

function simpleFunction() {

return 'any';

}

Object.defineProperty(simpleFunction,

"annotations",

{

get: function() {

return [new AnyAnnotation];

}

});

Page 65: Fullstack Conference -  Proxies before proxies: The hidden gems of Javascript AOP

Console.log(simpleFunction.annotations)

//-> [function AnyAnnotation(){}]

Page 66: Fullstack Conference -  Proxies before proxies: The hidden gems of Javascript AOP

LOGGER

ANNOTATIONS

@Logger

function simpleFunction () {

return 'any';

}

Page 67: Fullstack Conference -  Proxies before proxies: The hidden gems of Javascript AOP

var Logger = function(){

return function( target, receiver, args) {

var startTime = new Date();

var result = target(args);

var endTime = new Date();

console.log(‘called ‘ + target.name + new Date()

+ ’ with params:’

+ args

+ ’ executed in:’

+ endTime-startTime);

return result;

};

};

Page 68: Fullstack Conference -  Proxies before proxies: The hidden gems of Javascript AOP

var createProxy = function(anyFunction){

return new Proxy(anyFunction,

{

apply : anyFunction. annotations[0]

});

};

simpleFunction = createProxy(simpleFunction);

simpleFunction();

Page 69: Fullstack Conference -  Proxies before proxies: The hidden gems of Javascript AOP

called simpleFunction Thu Oct 23 2014

23:33:02 GMT+0100 (GMT Daylight Time)

with params: executed in:0

Page 70: Fullstack Conference -  Proxies before proxies: The hidden gems of Javascript AOP

THE FUTURE FOR

SCARLETJS

Page 71: Fullstack Conference -  Proxies before proxies: The hidden gems of Javascript AOP

THANK YOU

• @timchaplin

• https://github.com/tjchaplin

Page 72: Fullstack Conference -  Proxies before proxies: The hidden gems of Javascript AOP

REFERENCES

• http://soft.vub.ac.be/~tvcutsem/invokedynamic/proxies_tutorial

• https://brendaneich.com/2012/10/harmony-of-dreams-come-true/

• http://wiki.ecmascript.org/doku.php?id=harmony:specification_drafts

• http://dailyjs.com/2013/11/15/negative-array/

• https://github.com/sindresorhus/negative-array/blob/master/package.json

• https://github.com/tvcutsem/proxy-handlers

• https://github.com/JustinDrake/node-es6-examples#proxies