organizing javascript
DESCRIPTION
Organizing JavaScript into modules, both file-based and logical.TRANSCRIPT
Modules in JavaScriptOr How to Break Your Code
(Into Little Pieces)
A Talk by Michael Cordingley
Module Types
● Modules are sometimes misunderstood
– Confusion in naming● They come in different
flavors
– File
– Logical● In an ideal world, the two
overlap 1:1
● File Modules
– Each piece of code to its own file
● Logical Modules
– Each piece of code to its own predictable code location
The Cost of Structure
● Three different difficulty levels
– Different trade-offs of fixed versus variable costs
Complexity vs. Scale
Simple Moderate Complex
Project Scale
Pro
ject
Co
mp
lexi
ty
File Modules
● Break your code out into separate files
– Ideally, one file per idea● Files should be small and logically arranged on the file-
system
● Don't forget about production!
– Files need to be concatenated and minified as part of your build process.
File Modules – Simple
● If a project uses very little JavaScript, throw it it all into a single file for each page.
● Didn't you just say one idea per file?
– I lied.● It's more maintainable to have everything in one place, if that
place isn't too cluttered.
– We only need organization schemes when we have too much.
● When starting a new project, START WITH THIS ONE unless you have good reason to do otherwise!
File Modules – Moderate
● Break code out into separate files and load them each with a script tag.
– Don't forget to bundle these into a single file that gets loaded as a giant blob for production
● Doesn't this get hard to keep up with all of the dependencies?
– Only if you have several files
– Most projects never reach that scale
Transitioning to Moderation
● It isn't a clean break
● Just start pulling your nouns out into separate files as your project acquires them
– These are probably reusable across pages anyway
– Pulling them out also encourages you to write a clean interface
● If you page script exceeds 200 lines, you probably have lurking nouns, or at least some code that could be DRYed out.
– Please don't wait this long!
File Modules – Complex
● So you went for the moderate route and now you're drowning in files?
– Time to level up.● Pull in a formalized way to load and compile files
– require.js
– yepnope.js
– etc.
Caveat Emptor
● Things like require.js are geared more for single-page apps than for multi-page apps
– Most of your projects are probably multi-page apps
– You're probably only drowning in JS files if you have a single-page app
– require.js becomes painful very quickly if you want to use it on a multi-page app
Transitioning to Complexity
● Update your file module to conform to your module-loader of choice
● Update every usage of that module to be loaded with the module-loader
● Don't forget the whole concatenation/minification thing
– This is where the pain ramps up
– You need to define blobs● Separate bundlings of code that load together
File Modules in the Future
● ECMAScript 6 (Harmony) will bring native modules to the language
– Shim: https://github.com/ModuleLoader/es6-module-loader
– Despite the shim, this is not yet ready for general consumption
● The spec isn't finished yet
Logical Modules
● Where do your objects, functions, and variables all live?
– Hint: Not in the global namespace.
– I'm not lying this time!
Logical Modules – Simple
● Just keep 'em in your page script
– If you haven't broken it out into its own file anyway, it probably isn't very big or very complicated
● Pull it out into a logical module at the same time that you'd pull it out into a file module and for the same reasons
Logical Modules – Moderate
● OK, so it's out into its own file
– Don't make it a global!● Projects get cluttered this way
– It needs a home that is globally-accessible● It may be an object that you reuse across pages● It may be repeated functionality
– Like enhancing your site navigation
Introducing the Application Object
● Make a global
– But only one!
– For now, it's just an object literal● Call it “App” or the name of your project: “FooBarFighters”
– No, I'm not actually familiar with their music
– Yes, the puns are always intentional, even when bad
Application Object – Continued
● Attach your modules to this object
– e.g. App.Navigation, App.Forms, App.InstantiableObject
– Submodules go as properties on their parent modules● If your module needs initialization, add an “init” or
“initialize” method to it.
– e.g. App.Navigation.initialize();
– This is responsible for calling submodule intializers● If you have modules that need initialization, also have an
“App.initialize();” method that gets called on DOM ready
Application Object – Finish
● This application object can and should be broken out across multiple files.
– The “App.initialize()” method saves you from having to worry about the order in which they load
● The Application object just comes first● Don't forget about “this”
– Useful to avoid having to bake the full module name into functions that use other functions
– e.g. Inside of “App.Navigation.initialize()” “this” is “App.Navigation”
The Catch
● “This is great! Everything is cleanly separated out into its own place, but I need to load a module after the page load and then initialize it.”
– OK.● “Oh yeah, and I don't know if it'll have loaded before the
Application starts or not.”
– Um, K.● “And this other piece needs to run only (before|after) the rest
is all set up.”
– …why are you doing this to me?
Logical Modules – Complex
● Introducing the Application object!
– But this time, it's a real, instantiated object● “var App = new Application();”
– You could write the definition of “Application” yourself, but it's best not to
– We'll get to that
The New Application Object
● When a new module gets loaded after the application has started, this will automatically start it.
– Otherwise, it'll wait until the application starts● It also publishes events
– So you can run code just before and just after the application starts
– It even doubles as a free event bus● The modules also get events
– Same deal as the Application
And where do I get this?
● What, you don't want to reinvent the wheel?
– Fine, here it is: https://github.com/marionettejs/backbone.marionette/blob/master/docs/marionette.application.md
● “But, I don't use or want Underscore, Backbone, and the whole rest of Marionette!”
– Jeez, you're picky.
– https://github.com/mcordingley/Appliance
The End Goal
● Reduce complexity
– Whenever you introduce a new organizational tool, make sure it reduces project complexity
– Use the simplest scheme you can get away with
– Make things as easy as possible for anyone who has to maintain your code after you've left it behind
Thank You
● This talk can be found in article format at:
– http://michaelcordingley.me/articles/when-spaghetti-overflows-your-plate