Upgrade to Pro — share decks privately, control downloads, hide ads and more …

DRYing Out Your Client-Side Apps

Garann Means
February 12, 2012

DRYing Out Your Client-Side Apps

There's plenty of cool stuff Node offers purely in terms of server-side architectures, but it also offers a way to solve a problem we've been wrestling with since client-side applications became a big deal: writing everything twice. Rather than having the templates that produce markup exist in one backend language and in JavaScript, you can reuse them. Instead of validating in JavaScript on the client for the user's convenience and then again in some other language on the server for security, you can share a validation module that can be used in both scenarios. And so on. We'll look at some of the ways to stop repeating ourselves in Node apps and focus on getting the most out of existing client-side code.

Garann Means

February 12, 2012
Tweet

More Decks by Garann Means

Other Decks in Technology

Transcript

  1. DRYing out
    your client-side apps
    Sunday, February 12, 12

    View Slide

  2. hello!
    ’ Garann (like Karen with a G) Means
    ’ Austin All-Girl Hack Night + Girl Develop It Austin
    ’ Node for Front-End Developers (O’Reilly)
    [email protected] or @garannm
    Sunday, February 12, 12

    View Slide

  3. so node is pretty great, right?
    Sunday, February 12, 12

    View Slide

  4. and why?
    ’ fast!
    ’ evented!
    ’ super easy to set up!
    ’ awesome dev community!
    ’ reusable application code!
    Sunday, February 12, 12

    View Slide

  5. maybe a little trickier
    ’ fast!
    ’ evented!
    ’ super easy to set up!
    ’ awesome dev community!
    ’ reusable application code!
    Sunday, February 12, 12

    View Slide

  6. we never needed that before
    ’ client-side strictly presentational
    ’ DHTML
    ’ Ajax
    ’ explosion of JS libraries
    ’ client-side apps
    Sunday, February 12, 12

    View Slide

  7. we never had anything to reuse*
    Sunday, February 12, 12

    View Slide

  8. attempting reuse with a traditional
    server
    ’ server-side interpreters
    ’ compiled versions of logic for client
    ’ limited vocabulary that can be truly shared
    Sunday, February 12, 12

    View Slide

  9. things we can reuse
    ’ models
    ’ views/templates
    ’ route patterns
    ’ external or third-party utilities
    Sunday, February 12, 12

    View Slide

  10. caveats
    ’ essentially one way to import in node
    ’ modules have to check their context
    ’ may need to be both synchronous and asynchronous
    ’ user interaction has to be abstracted
    ’ no global scope on the server
    Sunday, February 12, 12

    View Slide

  11. the whats
    Sunday, February 12, 12

    View Slide

  12. models
    ’ easy-peasy!
    ’ sensible and simple to structure data same way
    ’ validation and rendering signatures can be the same
    ’ (even if functionality differs)
    Sunday, February 12, 12

    View Slide

  13. models
    function Model( config ) {
    var that = {
    thing: config.thing,
    stuff: config.stuff || []
    };
    that.validate = function() {
    if ( that.stuff.length ) return true;
    }
    return that;
    }
    Sunday, February 12, 12

    View Slide

  14. server
    socket.on( “modelUpdated”, function( data ) {
    var m = new Model( data );
    if ( !m.validate() ) {
    socket.emit( “badData”, { message: “onoez” } );
    }
    });
    Sunday, February 12, 12

    View Slide

  15. client
    btn.addEventListener( “click”, function() {
    var m = new Model({
    thing: txtField.value,
    stuff: convenientlyDefinedArray
    });
    if ( m.validate() ) {
    socket.emit ( “modelUpdated”, m );
    } else {
    alert( “Oops - not enough stuff!” );
    }
    });
    Sunday, February 12, 12

    View Slide

  16. templates
    ’ not all JS templates work client/server
    ’ all can be *made* to work client/server
    ’ used differently, loaded differently
    Sunday, February 12, 12

    View Slide

  17. server
    ’ maximize size
    ’ minimize requests
    ’ child templates as dependencies
    ’ no need to cache
    ’ response has to wait for loading, compositing, rendering
    Sunday, February 12, 12

    View Slide

  18. client
    ’ minimize size
    ’ minimize DOM interaction
    ’ swap out small bits of innerHTML
    ’ caching probably important
    ’ may be re-rendering constantly
    Sunday, February 12, 12

    View Slide

  19. routes
    ’ generic functions or publish/subscribe
    ’ probably need to abstract input and output
    ’ RPC/RMI may substitute
    Sunday, February 12, 12

    View Slide

  20. routes
    namespace.save = function( input, output ) {
    output.render ( “save”, input );
    }
    Sunday, February 12, 12

    View Slide

  21. server
    app.get( “/save”, function( req, res ) {
    routes.save( req.body, res );
    });
    Sunday, February 12, 12

    View Slide

  22. client
    btn.addEventListener( “click”, function() {
    var formData = serializeData( “#myForm” );
    routes.save( formData, myRenderer );
    });
    var myRenderer = function() {
    this.render = function( tmplName, data ) {
    document.querySelector( “#page” ).innerHTML =
    tmplEngine.template( tmplName, data );
    };
    };
    Sunday, February 12, 12

    View Slide

  23. alternatively..
    namespace.save = function( input ) {
    pubsub.publish( “loadSave”, input );
    };
    Sunday, February 12, 12

    View Slide

  24. utilities
    ’ client-side utils may rely on a global namespace
    ’ node modules probably expect exports
    ’ like templates, can be *made* to work bi-directionally
    Sunday, February 12, 12

    View Slide

  25. the hows
    Sunday, February 12, 12

    View Slide

  26. generally..
    ’ files live on client
    ’ pretend you never heard of global scope
    ’ everything decoupled from DOM*
    ’ pass reference to anything with state
    Sunday, February 12, 12

    View Slide

  27. 1. create server-side DOM
    2. ???
    3. profit
    Sunday, February 12, 12

    View Slide

  28. server-side DOM
    ’ existing tools to create DOM in V8
    ’ slow
    ’ server-side DOM rarely needed
    ’ for entire apps, almost never
    ’ have to replace or trigger user interactions
    Sunday, February 12, 12

    View Slide

  29. perfect candidates
    ’ testing
    ’ spidering
    ’ scraping
    ’ anything that requires parsing markup
    Sunday, February 12, 12

    View Slide

  30. WTF candidates
    ’ games
    ’ visual editors
    ’ anything where markup is merely the final representation
    ’ anything highly interactive
    Sunday, February 12, 12

    View Slide

  31. where it gets used
    ’ templates
    ’ build up DOM with reference to elements (vs. string)
    ’ events “belong” to elements
    ’ existing client-side apps
    ’ quick n’ dirty
    Sunday, February 12, 12

    View Slide

  32. write once, import twice
    Sunday, February 12, 12

    View Slide

  33. require.js and r.js
    ’ node’s require is subtly different
    ’ formal dependency management solves namespace issue
    ’ kind of
    ’ text! prefix for loading unexecuted code
    Sunday, February 12, 12

    View Slide

  34. server
    var requirejs = require( “requirejs” );
    requirejs.config( { nodeRequire: require } );
    requirejs( [“thing1”, “thing2”],
    function( t1, t2 ) {
    // whatever..
    });
    requirejs( [“text!public/template.html”],
    function( tmpl ) {
    // whatever (rendering version)..
    });
    Sunday, February 12, 12

    View Slide

  35. client

    <br/>requirejs( [“thing1”, “thing2”],<br/>function( t1, t2 ) {<br/>// whatever..<br/>});<br/>requirejs( [“text!public/template.html”],<br/>function( tmpl ) {<br/>// whatever (rendering version)..<br/>});<br/>
    Sunday, February 12, 12

    View Slide

  36. exports || namespace
    ’ everything in an IIFE
    ’ pass in scope
    ’ requires hard-coding client namespace
    Sunday, February 12, 12

    View Slide

  37. exports || namespace
    (function( ns ) {
    ns.thing = function() {
    // whatever..
    };
    return ns;
    }( ( typeof process !== "undefined" &&
    process.title === "node" )
    ? exports : clientNamespace ));
    Sunday, February 12, 12

    View Slide

  38. Remote procedure calls
    Sunday, February 12, 12

    View Slide

  39. RPC/rmi
    ’ write code once to run in two places
    ’ both, not either
    ’ pass control with callbacks (which node needs anyway)
    Sunday, February 12, 12

    View Slide

  40. server
    var dnode = require( “dnode” );
    dnode( function( client, connection ) {
    this.biznessLogic = function() {
    // whatever..
    }
    }).listen( 1337 );
    Sunday, February 12, 12

    View Slide

  41. client
    var dnode = require( “dnode” );
    dnode.connect( function( remote ) {
    btn.addEventListener( “click”, function() {
    remote.biznessLogic();
    });
    });
    Sunday, February 12, 12

    View Slide

  42. end-to-end frameworks
    Sunday, February 12, 12

    View Slide

  43. the future
    ’ assembling this stuff by hand is silly
    ’ reuse should be the default
    ’ room for many frameworks, many methodologies
    Sunday, February 12, 12

    View Slide

  44. how would that look?
    ’ build step required?
    ’ framework creates server
    ’ server generates client-side assets from server code
    ’ controllers wrap RPC/RMI calls
    Sunday, February 12, 12

    View Slide

  45. full-stack solutions
    ’ batman.js
    ’ derby.js
    ’ flatiron.js
    ’ thorax.js
    ’ drumkit.js
    ’ zomg: http://toolbox.no.de/categories/Frameworks
    Sunday, February 12, 12

    View Slide

  46. changing everything
    ’ trying to do this since early 2000s, at least
    ’ and it’s sucked
    ’ browsers behaving more like servers
    ’ sockets, storage, I/O
    ’ and servers behaving more like browsers
    ’ \m/, JavaScript ,\m/
    Sunday, February 12, 12

    View Slide

  47. why the proliferation?
    ’ everyone coming to the same conclusion at once
    ’ different needs, but not really
    ’ different preferences
    ’ which fits your needs?
    Sunday, February 12, 12

    View Slide

  48. lots of ways to share code
    ’ which pieces do you have?
    ’ which are crucial and which are “glue”?
    ’ e.g. templates may be unrelated to biz logic
    ’ are there constraints to how they’re handled?
    ’ e.g. maybe you can’t jump to a route/state by URL
    Sunday, February 12, 12

    View Slide

  49. bottom line: Don’t repeat yourself
    ’ no reason to run logic on a different side than it’s used
    ’ no reason to duplicate code
    Sunday, February 12, 12

    View Slide

  50. thanks!
    Sunday, February 12, 12

    View Slide

  51. — image credits —
    ’ http://www.flickr.com/photos/breakfastcore/2285501111/
    ’ http://www.flickr.com/photos/bondidwhat/6114903414/
    ’ http://www.flickr.com/photos/rchappo2002/2694370462/
    ’ http://www.flickr.com/photos/[email protected]/4188316428/
    ’ http://www.flickr.com/photos/blackcountrymuseums/5218004706/
    ’ http://www.flickr.com/photos/catechism/3001280935/
    ’ http://www.flickr.com/photos/murrus/2344711309/
    ’ http://www.flickr.com/photos/carbonated/2105145079/
    Sunday, February 12, 12

    View Slide