SlideShare a Scribd company logo
Composition
Something something Mozart
I'm Josh Mock.
I'm @joshmock on all of the things.
Except email, that's josh@joshmock.com.
So original, right?
Composition in JavaScript
Composition in JavaScript
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 example
var 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 example
var 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 reuse
function getCount (value) {
return value.count;
}
function noOdds (value) {
return value % 2 === 0;
}
function add (value1, value2) {
return value1 + value2;
}
Function reuse
var myList = [
{ count: 17 },
{ count: 22 },
{ count: 3 },
{ count: 18 }
];
var sum = _.chain(myList)
.map(getCount)
.filter(noOdds)
.reduce(add)
.value();
each / map / filter / reduce
function 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 / reduce
function 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 streams
gulp.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."
Composition in JavaScript
@joshmock
josh@joshmock.com

More Related Content

Composition in JavaScript

  • 2. I'm Josh Mock. I'm @joshmock on all of the things. Except email, that's josh@joshmock.com. So original, right?
  • 5. What is composition? Combining simple objects in code to make more complex ones.
  • 6. How do I compose things? Find repeated patterns or duplications in your code and refactor them into reusable parts.
  • 7. A simple example var 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!'
  • 8. A simple example var 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!'
  • 9. ● Maximize code reuse ● Use objects without classes ● Avoid traps of single-parent inheritance Mixins
  • 10. Mixins in the wild ● Marionette Behaviors ● Bootstrap CSS classes ● Hapi plugins
  • 11. 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
  • 12. Underscore.js _.chain(myArray) .map(/* reformat items */) .filter(/* pull out items you don't need */) .reduce(/* crunch down to a single value */) .value();
  • 13. 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
  • 14. mapped = map(..., my_array) filtered = filter(..., mapped) final_val = reduce(..., filtered) And in Python
  • 16. 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
  • 17. Function reuse function getCount (value) { return value.count; } function noOdds (value) { return value % 2 === 0; } function add (value1, value2) { return value1 + value2; }
  • 18. Function reuse var myList = [ { count: 17 }, { count: 22 }, { count: 3 }, { count: 18 } ]; var sum = _.chain(myList) .map(getCount) .filter(noOdds) .reduce(add) .value();
  • 19. each / map / filter / reduce function 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; }
  • 20. each / map / filter / reduce function 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 || []; }
  • 21. each / map / filter / reduce ● Small, single-purpose functions ● Maintainable ● Reusable ● Easy to test ● Universally understandable
  • 22. Web components ● HTML is perfectly composable: <form> <input type="text"> <button>click me</button> </form> ● Custom elements = infinite composition possibilities!
  • 23. $ cat index.js | grep 'var' | wc -l 5 Unix piping
  • 24. "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
  • 25. A Node.js API to read in data, act on it in chunks, then then write out to a new stream. Node streams
  • 26. Node streams gulp.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')); });
  • 27. Functional reactive programming Act on DOM events as though they were streams or arrays.
  • 28. Microservices "...an approach to developing a single application as a suite of small services, each running in its own process."
  • 32. ● Stop building behemoths ● Build single-purpose tools ● Chain them together to do big things TL;DR