Slide 1

Slide 1 text

JavaScript, Spaghetti (or why modularity matters) and Meatballs @fnando http://nandovieira.com

Slide 2

Slide 2 text

No content

Slide 3

Slide 3 text

THE FIRST REVOLUTION 2004

Slide 4

Slide 4 text

ASYNCRONOUS JAVASCRIPT AND XML AJAX

Slide 5

Slide 5 text

THE SECOND REVOLUTION 2006

Slide 6

Slide 6 text

No content

Slide 7

Slide 7 text

THE THIRD REVOLUTION 2009

Slide 8

Slide 8 text

No content

Slide 9

Slide 9 text

29 out of 50* most popular Github repositories are JavaScript-related. *bootstrap, node, jquery, html5-boilerplate, impress.js, d3, backbone, chosen, three.js, jQuery-File-Upload, brackets, express, angular.js, Modernizr, meteor, less.js, socket.io, jquery-mobile, underscore, reveal.js, co ee-script, jquery-ui, moment, ember.js, select2, todomvc, backbone-fundamentals, jquery-pjax, pdf.js.

Slide 10

Slide 10 text

JavaScript is the most important language nowadays.

Slide 11

Slide 11 text

And JavaScript is almost 20 years old.

Slide 12

Slide 12 text

So, why do we still suck at it?

Slide 13

Slide 13 text

"invite_friends" : function() { var resizeLoader = function() { $("#loader").css("width", $(".places").width()); $("#loader").css("height", $(".places").height()-18); } resizeLoader(); var resizeTimer; $(window).bind('resize', function() { clearTimeout(resizeTimer); resizeTimer = setTimeout(resizeLoader, 50); }); $("a[href=#automatic_invite]").click(function(e){ SomeApp.utils.stopPropagation(e); if(!$(this).parents(".tab_title:first").is(".active")) { $(".tab_title:first") .toggleClass("active"); $(".tab_title:last") .toggleClass("active"); $("#automatic") .toggleClass("hidden"); $("#manual") .toggleClass("hidden"); } }); var suffixes = { "gmail": "@gmail.com", "yahoo": "", "live": "@hotmail.com", "other": ""

Slide 14

Slide 14 text

The solution is modularity.

Slide 15

Slide 15 text

Why modular?

Slide 16

Slide 16 text

Separation of concerns

Slide 17

Slide 17 text

Easier to expand

Slide 18

Slide 18 text

Keep your codebase maintainable

Slide 19

Slide 19 text

Reusability

Slide 20

Slide 20 text

Testability

Slide 21

Slide 21 text

Why not, then?

Slide 22

Slide 22 text

Devs just don’t know how to do it

Slide 23

Slide 23 text

Writing modular code can be hard

Slide 24

Slide 24 text

So, how do I do it?

Slide 25

Slide 25 text

Organization

Slide 26

Slide 26 text

Treat JavaScript as a real language

Slide 27

Slide 27 text

Design your code

Slide 28

Slide 28 text

Use modules

Slide 29

Slide 29 text

Object literal notation, Module Pattern, AMD, CommonJS, Harmony Modules

Slide 30

Slide 30 text

Object Literal

Slide 31

Slide 31 text

var Todo = { tasks: [] , addTask: function(task) {} , removeTask : function() {} , count : function() {} };

Slide 32

Slide 32 text

Module pattern

Slide 33

Slide 33 text

var Todo = (function(){ var tasks = []; // private variable // expose the public API return { addTask: function(task) {} , removeTask: function(task) {} , count: function() {} }; })();

Slide 34

Slide 34 text

An easy way of emulating method/attribute visibility.

Slide 35

Slide 35 text

var Todo = (function($, hb){ // all your code here })(jQuery, Handlebars);

Slide 36

Slide 36 text

I tend to use a IIFE & Namespace approach.

Slide 37

Slide 37 text

Module("MyApp.MyModule", function(MyModule){ MyModule.fn.initialize = function() { // this is the initializer }; MyModule.fn.someFunction = function() { // fn is just shortcut for // prototype alas jQuery }; });

Slide 38

Slide 38 text

No content

Slide 39

Slide 39 text

Modular code will generate lots of les, and that's ok.

Slide 40

Slide 40 text

Rails asset pipeline concats and mini es all the code.

Slide 41

Slide 41 text

//= require vendor/jquery //= require_tree ./vendor //= require_tree ./myapp

Slide 42

Slide 42 text

Dependency order is not a problem.

Slide 43

Slide 43 text

Single entry point.

Slide 44

Slide 44 text

// boot.js $(function(){ var html = $("html") , controller = html.data("controller") , action = html.data("action") ; MyApp.Application(controller, action); });

Slide 45

Slide 45 text

ASYNCRONOUS MODULE DEFINITION AMD

Slide 46

Slide 46 text

Require.js is the de facto library.

Slide 47

Slide 47 text

Module de nition and script/ le loader.

Slide 48

Slide 48 text

// sample.js define(function(){ var tasks = []; // private variable // expose the public API return { addTask: function(task) {} , removeTask: function(task) {} , count: function() {} }; });

Slide 49

Slide 49 text

// app.js require(["sample"], function(sample){ // do what you need to do with sample });

Slide 50

Slide 50 text

Explicit dependency is really nice.

Slide 51

Slide 51 text

On-demand script loading is not a real bene t for small-mid apps.

Slide 52

Slide 52 text

Use r.js before deploying your code.

Slide 53

Slide 53 text

AMD/Require.js is OK.

Slide 54

Slide 54 text

But don't say that it allows you to write modular code.

Slide 55

Slide 55 text

You can write modular code with vanilla JavaScript as well.

Slide 56

Slide 56 text

COMMONJS

Slide 57

Slide 57 text

Node's module implementation is based on CommonJS.

Slide 58

Slide 58 text

var tasks = []; // private variable // expose the public API module.exports = { addTask: function(task) {} , removeTask: function(task) {} , count: function() {} };

Slide 59

Slide 59 text

var Todo = require("./todo"); Todo.addTask(task);

Slide 60

Slide 60 text

I like it more than AMD.

Slide 61

Slide 61 text

Not that great on the browser.

Slide 62

Slide 62 text

THE NEW JAVASCRIPT VERSION HARMONY

Slide 63

Slide 63 text

module Todo { var tasks = []; // private variable // expose the public API export default { addTask: function(task) {} , removeTask: function(task) {} , count: function() {} }; }

Slide 64

Slide 64 text

import Todo from Todo; Todo.addTask(task);

Slide 65

Slide 65 text

You can import modules from urls.

Slide 66

Slide 66 text

// load from remote sources module $ from "http://example.org/jquery.js"; // Module loader API Loader.load("http://example.org/jquery.js", function($){ // do what you need });

Slide 67

Slide 67 text

You can be speci c about the importing.

Slide 68

Slide 68 text

import { a, b, c } from "some/file";

Slide 69

Slide 69 text

Just a proposal. http://wiki.ecmascript.org/doku.php?id=harmony:modules

Slide 70

Slide 70 text

Practical example

Slide 71

Slide 71 text

No content

Slide 72

Slide 72 text

$(".postbox textarea") .on("focus", function(){ $(this).closest(".postbox") .addClass("did-focus") .removeClass("is-contracted") ; }) .on("keyup", function(){ var lines = this.value.split(/\r?\n/); var textarea = $(this); if (lines.length >= 5) { textarea.addClass("is-taller"); } else { textarea.removeClass("is-taller"); } }) .on("blur", function(){ if (!this.value) { $(this).closest(".postbox").addClass("is-contracted"); } }) ;

Slide 73

Slide 73 text

Module("HOWTO.Postbox", function(Postbox){ Postbox.fn.initialize = function(container) { this.container = container; this.textarea = container.find(".pb-input"); this.button = container.find(".pb-button"); }; });

Slide 74

Slide 74 text

Module("HOWTO.Postbox", function(Postbox){ Postbox.fn.initialize = function(container) { // the initialization code this.addEventListeners(); }; Postbox.fn.addEventListeners = function() { this.textarea .on("focus", this.onTextareaFocus.bind(this)) .on("keyup", this.onTextareaKeyUp.bind(this)) .on("blur", this.onTextareaBlur.bind(this)) ; }; });

Slide 75

Slide 75 text

Module("HOWTO.Postbox", function(Postbox){ Postbox.fn.initialize = function(container) {}; Postbox.fn.addEventListeners = function() {}; Postbox.fn.onTextareaFocus = function(event) { this.container .addClass("did-focus") .removeClass("is-contracted") ; }; });

Slide 76

Slide 76 text

Module("HOWTO.Postbox", function(Postbox){ Postbox.fn.initialize = function(container) {}; Postbox.fn.addEventListeners = function() {}; Postbox.fn.onTextareaFocus = function(event) {}; var LINES = 5; Postbox.fn.onTextareaKeyUp = function(event) { var lines = event.target.value.split(/\r?\n/); if (lines.length >= LINES) { this.textarea.addClass("is-taller"); } else { this.textarea.removeClass("is-taller"); } }; });

Slide 77

Slide 77 text

Module("HOWTO.Postbox", function(Postbox){ Postbox.fn.initialize = function(container) {}; Postbox.fn.addEventListeners = function() {}; Postbox.fn.onTextareaFocus = function(event) {}; Postbox.fn.onTextareaKeyUp = function(event) {}; Postbox.fn.onTextareaBlur = function(event) { if (!event.target.value) { this.container.addClass("is-contract"); } }; });

Slide 78

Slide 78 text

describe("HOWTO.Postbox", function() { var container, postbox, textarea; beforeEach(function() { container = $("
") .append("") .append("") .appendTo("#sample") ; textarea = container.find("textarea"); postbox = HOWTO.Postbox(container); }); it("sets class when focusing box", function() { textarea.trigger("focus"); expect(container.is(".did-focus")).toBeTruthy(); }); // other specs });

Slide 79

Slide 79 text

So...

Slide 80

Slide 80 text

Every complex app must be composed of small components.

Slide 81

Slide 81 text

Remember that you never know how big it’s going to be.

Slide 82

Slide 82 text

hype Don’t buy into

Slide 83

Slide 83 text

Modular code can be written without using libraries.

Slide 84

Slide 84 text

Use what’s better for your work ow.

Slide 85

Slide 85 text

That’s it!