composition in javascript

35
Composition Something something Mozart

Upload: josh-mock

Post on 16-Jul-2015

248 views

Category:

Software


0 download

TRANSCRIPT

CompositionSomething something Mozart

I'm Josh Mock.

I'm @joshmock on all of the things.

Except email, that's [email protected].

So original, right?

What is composition?

Combining simple objects in code to make more complex ones.

How do I compose things?

Find repeated patterns or duplications in your code and refactor them into reusable parts.

A simple examplevar obj1 = {

message: 'hello world!',

sayHi: function () {

alert(this.message);

}

};

var obj2 = {

message: 'hey!',

sayHi: function () {

alert(this.message);

}

};

obj1.sayHi(); // 'hello world!'

obj2.sayHi(); // 'hey!'

A simple examplevar obj1 = { message: 'hello world!' };var obj2 = { message: 'hey!' };

var alerter = { sayHi: function () { alert(this.message); }};

obj1 = _.extend(obj1, alerter);obj2 = _.extend(obj2, alerter);

obj1.sayHi(); // 'hello world!'obj2.sayHi(); // 'hey!'

● Maximize code reuse

● Use objects without classes

● Avoid traps of single-parent inheritance

Mixins

Mixins in the wild

● Marionette Behaviors

● Bootstrap CSS classes

● Hapi plugins

Underscore.js_.each(array, function) : Loop over each item in an array

_.map(array, function) : Reformat each item in an array

_.filter(array, function) : Make a new array containing only items that pass a test

_.reduce(array, function, start) : Calculate a single value from an array of items

Underscore.js_.chain(myArray)

.map(/* reformat items */)

.filter(/* pull out items you don't need */)

.reduce(/* crunch down to a single value */)

.value();

myArray

.map(/* reformat items */)

.filter(/* pull out items you don't need */)

.reduce(/* crunch down to a single value */)

You can do this in plain JS too

mapped = map(..., my_array)

filtered = filter(..., mapped)

final_val = reduce(..., filtered)

And in Python

my_array.map(...).reduce(...).reduce(...)

...and Ruby

var myList = [

{ count: 17 },

{ count: 22 },

{ count: 3 },

{ count: 18 }

];

var sum = 0;

for (var i = 0; i < myList.length; i++) {

sum += myList[i].count;

}

Function reuse

Function reusefunction getCount (value) {

return value.count;

}

function noOdds (value) {

return value % 2 === 0;

}

function add (value1, value2) {

return value1 + value2;

}

Function reusevar myList = [

{ count: 17 },

{ count: 22 },

{ count: 3 },

{ count: 18 }

];

var sum = _.chain(myList)

.map(getCount)

.filter(noOdds)

.reduce(add)

.value();

each / map / filter / reducefunction getForms (data) {

var forms = data.aggregate.all[window.location.protocol + '//' + window.location.host];

var formsOut = [];

var url = window.location.toString();

var formsToExclude = [];

for (var key in data.aggregate.exclude) {

if (new RegExp('^' + key + '$').test(url)) {

formsToExclude = formsToExclude.concat(data.aggregate.exclude[key]);

}

}

var filteredForms = [];

for (value in forms) {

if (formsToExclude.indexOf(value) === -1) {

filteredForms.push(value);

}

}

for (key in data.aggregate.include) {

if (new RegExp('^' + key + '$').test(url)) {

forms = forms.concat(data.aggregate.include[key]);

}

}

return formsOut;

}

each / map / filter / reducefunction getForms (data) {

var forms = data.aggregate.all[window.location.protocol + '//' + window.location.host];

var url = window.location.toString();

var formsToExclude = [];

_.each(data.aggregate.exclude, function (val, key) {

if (new RegExp('^' + key + '$').test(url)) {

formsToExclude = formsToExclude.concat(val);

}

});

forms = _.filter(forms, function (val) {

return formsToExclude.indexOf(val) === -1;

});

_.each(data.aggregate.include, function (val, key) {

if (new RegExp('^' + key + '$').test(url)) {

forms = forms.concat(val);

}

});

return forms || [];

}

each / map / filter / reduce

● Small, single-purpose functions

● Maintainable

● Reusable

● Easy to test

● Universally understandable

Web components● HTML is perfectly composable:

<form> <input type="text"> <button>click me</button></form>

● Custom elements = infinite composition possibilities!

$ cat index.js | grep 'var' | wc -l

5

Unix piping

"This is the Unix philosophy: Write programs that do one thing and do it well. Write programs to work together. Write programs to handle text streams, because that is a universal interface."

- Doug McIlroy

The Unix Philosophy

A Node.js API to read in data, act on it in chunks, then then write out to a new stream.

Node streams

Node streamsgulp.task('scripts', function() { return gulp.src('js/*.js') .pipe(concat('all.js')) .pipe(gulp.dest('dist')) .pipe(rename('all.min.js')) .pipe(uglify()) .pipe(gulp.dest('dist'));});

Functional reactive programming

Act on DOM events as though they were streams or arrays.

Microservices

"...an approach to developing a single application as a suite of small services, each running in its own process."

Emma, 5 years ago

Emma, 2.5 years ago

Emma, now-ish

● Stop building behemoths

● Build single-purpose tools

● Chain them together to do big things

TL;DR

"One thing well."