Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Speaker Deck
PRO
Sign in
Sign up
for free
JavaScript, Spaghetti, and Meatballs (or why modularity matters)
Nando Vieira
June 22, 2013
Programming
9
840
JavaScript, Spaghetti, and Meatballs (or why modularity matters)
My talk on JSconfBR 2013
Nando Vieira
June 22, 2013
Tweet
Share
More Decks by Nando Vieira
See All by Nando Vieira
fnando
8
1.3k
fnando
3
480
fnando
24
2.5k
fnando
4
550
fnando
35
1.8k
fnando
11
500
fnando
36
1.7k
fnando
31
2.8k
fnando
20
860
Other Decks in Programming
See All in Programming
yotuba088
1
590
ianaya89
1
170
prof18
0
1.1k
ryokbt
2
290
takahi5
1
420
larsrh
0
110
mihyaeru21
0
360
grapecity_dev
0
180
nkjzm
1
170
ntaro
0
160
legalforce
PRO
0
630
dqneo
3
300
Featured
See All Featured
chriscoyier
779
240k
rasmusluckow
318
18k
roundedbygravity
84
7.9k
jmmastey
10
610
bermonpainter
342
26k
andyhume
63
3.7k
pedronauck
652
110k
nonsquared
81
3.4k
holman
448
130k
jacobian
255
20k
colly
66
3k
jnunemaker
PRO
40
4.6k
Transcript
JavaScript, Spaghetti (or why modularity matters) and Meatballs @fnando http://nandovieira.com
None
THE FIRST REVOLUTION 2004
ASYNCRONOUS JAVASCRIPT AND XML AJAX
THE SECOND REVOLUTION 2006
None
THE THIRD REVOLUTION 2009
None
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.
JavaScript is the most important language nowadays.
And JavaScript is almost 20 years old.
So, why do we still suck at it?
"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": ""
The solution is modularity.
Why modular?
Separation of concerns
Easier to expand
Keep your codebase maintainable
Reusability
Testability
Why not, then?
Devs just don’t know how to do it
Writing modular code can be hard
So, how do I do it?
Organization
Treat JavaScript as a real language
Design your code
Use modules
Object literal notation, Module Pattern, AMD, CommonJS, Harmony Modules
Object Literal
var Todo = { tasks: [] , addTask: function(task) {}
, removeTask : function() {} , count : function() {} };
Module pattern
var Todo = (function(){ var tasks = []; // private
variable // expose the public API return { addTask: function(task) {} , removeTask: function(task) {} , count: function() {} }; })();
An easy way of emulating method/attribute visibility.
var Todo = (function($, hb){ // all your code here
})(jQuery, Handlebars);
I tend to use a IIFE & Namespace approach.
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 }; });
None
Modular code will generate lots of les, and that's ok.
Rails asset pipeline concats and mini es all the code.
//= require vendor/jquery //= require_tree ./vendor //= require_tree ./myapp
Dependency order is not a problem.
Single entry point.
// boot.js $(function(){ var html = $("html") , controller =
html.data("controller") , action = html.data("action") ; MyApp.Application(controller, action); });
ASYNCRONOUS MODULE DEFINITION AMD
Require.js is the de facto library.
Module de nition and script/ le loader.
// sample.js define(function(){ var tasks = []; // private variable
// expose the public API return { addTask: function(task) {} , removeTask: function(task) {} , count: function() {} }; });
// app.js require(["sample"], function(sample){ // do what you need to
do with sample });
Explicit dependency is really nice.
On-demand script loading is not a real bene t for
small-mid apps.
Use r.js before deploying your code.
AMD/Require.js is OK.
But don't say that it allows you to write modular
code.
You can write modular code with vanilla JavaScript as well.
COMMONJS
Node's module implementation is based on CommonJS.
var tasks = []; // private variable // expose the
public API module.exports = { addTask: function(task) {} , removeTask: function(task) {} , count: function() {} };
var Todo = require("./todo"); Todo.addTask(task);
I like it more than AMD.
Not that great on the browser.
THE NEW JAVASCRIPT VERSION HARMONY
module Todo { var tasks = []; // private variable
// expose the public API export default { addTask: function(task) {} , removeTask: function(task) {} , count: function() {} }; }
import Todo from Todo; Todo.addTask(task);
You can import modules from urls.
// 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 });
You can be speci c about the importing.
import { a, b, c } from "some/file";
Just a proposal. http://wiki.ecmascript.org/doku.php?id=harmony:modules
Practical example
None
$(".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"); } }) ;
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"); }; });
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)) ; }; });
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") ; }; });
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"); } }; });
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"); } }; });
describe("HOWTO.Postbox", function() { var container, postbox, textarea; beforeEach(function() { container
= $("<div/>") .append("<textarea class='pb-input'/>") .append("<button class='pb-button' value='Reply'/>") .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 });
So...
Every complex app must be composed of small components.
Remember that you never know how big it’s going to
be.
hype Don’t buy into
Modular code can be written without using libraries.
Use what’s better for your work ow.
That’s it!