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

How to rewrite your JS app (at least) 10 times

Garann Means
October 11, 2013

How to rewrite your JS app (at least) 10 times

It would be nice if developers could download a JavaScript framework, plug in the custom logic required for their particular problem, and have a functional, scalable, and reliable application. As any who's tried can probably tell you, however, it doesn't work like that. It doesn't matter if your application has 5000 "pages" or less than 50 - it will eventually become a large application in terms of code, because size of code is not just a measure of the complexity of the app itself, but of its maturity. If you've tried taking an app from a minimal set of functionality to something complex enough to cover all the edge cases, you've probably done some rewriting.
If you haven't, it's your lucky day! We'll talk about several of the ways you can almost guarantee a rewrite in your app's future. If, on the other hand, rewrites don't sound like that much fun to you, we'll also talk about how to avoid them or at least minimise the risk they present.

Garann Means

October 11, 2013
Tweet

More Decks by Garann Means

Other Decks in Technology

Transcript

  1. how to rewrite your
    JS app ten times*
    Garann Means ☔ @garannm
    * at least

    View full-size slide

  2. the hardest problem in app
    development

    View full-size slide

  3. worries in starting
    ‘ how to split things up
    ‘ where does the app start?
    ‘ what utilities will I rely on?
    ‘ OMG do I have any idea what I’m doing?

    View full-size slide

  4. coding is easy.
    planning is hard.

    View full-size slide

  5. we tend to overprioritize
    the easy one.

    View full-size slide

  6. biggest worry
    ‘ am I going to end up rewriting all of this?

    View full-size slide

  7. different set of worries

    View full-size slide

  8. rewriting what already
    exists
    ‘ what’s the reason for the rewrite?
    ‘ what if I accidentally regress something?
    ‘ are there any yaks I can shave?
    ‘ OMG do I have any idea what I’m doing?

    View full-size slide

  9. ok. rewrites are inevitable.

    View full-size slide

  10. good rewrites
    ‘ a new technology comes along
    ‘ your business expands
    ‘ you upgrade your infrastructure
    ‘ plain old incremental refactors
    ‘ existing app is like EMERGENCY STATUS broken

    View full-size slide

  11. bad rewrites
    ‘ you’ve got 20% of the app written and you
    realize it’s all wrong

    View full-size slide

  12. bad rewrites require
    starting over [again].

    View full-size slide

  13. bad rewrites are not
    inevitable.

    View full-size slide

  14. comprehensive”>

    View full-size slide

  15. #1
    “let’s use [framework]!”

    View full-size slide

  16. we love [framework]!
    ‘ lots of posts about it on HN
    ‘ someone on your team used it once at a
    hackathon
    ‘ it’s MVC, you’ve already got some models!

    View full-size slide

  17. function ThisIsGoingSoWell( opts ) {
    this.init = function() {};
    this.url = “cool/api/path”;
    }
    Frmwrk.extend( ThisIsGoingSoWell, Model );

    View full-size slide

  18. function ActuallyDoStuff() {
    // TODO: state objects?
    // TODO: event handlers?
    // TODO: idk this isn’t in the docs??
    };

    View full-size slide

  19. ‘ solves easy problems
    ‘ provides common abstractions
    ‘ doesn’t help you organize your app
    love is fleeting

    View full-size slide

  20. the framework should be
    the last choice, not the
    first.

    View full-size slide

  21. #2
    “nevermind, we’ll write our
    own!”

    View full-size slide

  22. it’s gonna be artisanal,
    y’all
    ‘ suited to your app specifically
    ‘ you know the code inside and out
    ‘ no bloat from features you don’t need

    View full-size slide

  23. ( function MyFrmwrk( window ) {
    this.init = function() {};
    this.url = function() {};
    window.Frmwrk = this;
    })( window );

    View full-size slide

  24. ‘ you’re rewriting your favorite framework
    ‘ with just enough difference that other devs don’t
    understand it
    ‘ and turns out your favorite framework isn’t so
    easy to write
    congratulations!

    View full-size slide

  25. only write one application
    at a time.

    View full-size slide

  26. #3
    “we can’t define an API
    without any code!”

    View full-size slide

  27. do I look like a fortune
    teller!
    ‘ don’t want to outline an API too early
    ‘ just more places to change it
    ‘ how can you optimize that YOU CAN’T

    View full-size slide

  28. ViewOne.render = function() {
    // get data, populate template, transform
    inline
    };
    ViewTwo.render = function() {
    // get transformed data, populate template
    };
    ViewThree.render = function() {
    // get populated template from server
    };

    View full-size slide

  29. ViewOne.render = function() {
    // get data, populate template, transform
    inline
    $.get( “/viewOne”, function( data ) {
    container.html( tmpl( data ) );
    });
    };

    View full-size slide

  30. ViewTwo.render = function() {
    // get transformed data, populate template
    $.get(
    “/viewTwo”,
    { language: “en” },
    function( data ) {
    container.html( tmpl( data ) );
    });
    };

    View full-size slide

  31. ViewThree.render = function() {
    // get populated template from server
    $.get(
    “/viewThree”,
    { language: “en”, subtmpl: “error” },
    function( html ) {
    container.html( html );
    });
    };

    View full-size slide

  32. ‘ logic that’s not in a consistent place is hard to
    find
    ‘ and hard to reuse
    ‘ and makes it hard to have a predictable API
    ‘ unpredictable APIs beget unpredictable
    architectures
    where the $!% is this
    getting set?!

    View full-size slide

  33. specify APIs thoroughly
    and early.

    View full-size slide

  34. #4
    “good point, if it’s not JS
    we’ll do it in PHP”

    View full-size slide

  35. super-ultra-optimized
    ‘ static stuff rendered by server
    ‘ dynamic stuff by client
    ‘ server folks speak their language, JS folks speak
    theirs

    View full-size slide

  36. oh wait.
    ‘ this partial template right here?
    ‘ we need it on the client, too
    ‘ no big, just copy it in JS
    ‘ (six months pass)
    ‘ arrrrgh why didn’t we just write these templates
    in the same language

    View full-size slide

  37. plan the stuff outside your
    JavaScript as well.

    View full-size slide

  38. #5
    “this DOM doesn’t work
    with our webapp”

    View full-size slide

  39. Polly-who?
    ‘ there are a lot of inconsistencies (still)
    ‘ that’s a lot of extra code
    ‘ standard implementations may not be quite right
    ‘ let’s just write our own DOM!

    View full-size slide

  40. // _so classic_
    ( function FileUploader() {
    // we’ll just make a little file selector
    // and style it real pretty
    // and add some cool progress events
    // and the Flash movie that runs it all
    })();

    View full-size slide

  41. // oh.
    ( function FileUploadHandler() {
    // expose all that Flash stuff to JS
    // let the widget be used in a larger form
    })();

    View full-size slide

  42. // srsly?
    ( function FileUploaderDegrade() {
    // fall back to normal upload if no Flash
    // check for XHR2, add progress stuff
    // map DOM API so it matches FileUploader
    // let the widget be used in a larger form
    })();

    View full-size slide

  43. ‘ someone at [browser co, inc] is working on
    improving this stuff
    ‘ someone else made a polyfill
    ‘ someone else fancied it up and made a jQuery
    plugin
    ‘ if you’re not in the widget business, stop
    we used to have to do
    this; we don’t now

    View full-size slide

  44. only write one application
    at a time.

    View full-size slide

  45. #6
    “XHR? more like HTML
    amirite”

    View full-size slide

  46. we’re fetching HTML
    anyway
    ‘ let’s put all our stuff in it!
    ‘ object setting? data attribute
    ‘ i18n? data attribute
    ‘ entire app state??? DATA ATTRIBUTES

    View full-size slide

  47. MyApp.init = function() {
    // look, no options!
    // we’ll just select the necessary nodes..
    // and then find their attributes..
    // parse those to data types..
    };

    View full-size slide

  48. MyApp.onSomethingChanged = function() {
    // we’ll just select the necessary nodes..
    // and then set their attributes..
    // and update the server, too..
    // wat, 503?!
    // we’ll just select the necessary nodes..
    // and then unset their attributes..
    };

    View full-size slide

  49. ‘ it’s expensive and messy
    ‘ it violates DRY from the jump
    ‘ it doesn’t provide objects you can work with
    the DOM is not a data
    store

    View full-size slide

  50. data deserves a real
    home.

    View full-size slide

  51. #7
    “there’s a plugin/module
    for that!”

    View full-size slide

  52. the wheel is perfect
    ‘ and there are so many wheels to choose from!
    ‘ a tried and true solution for everything
    ‘ partway there still beats the starting line

    View full-size slide

  53. function veryImportant( item ) {
    var $item = $( item );
    $item.transformIntoMagicWidget();
    // NOW we can actually use it
    $item.on( “pluginEvent”, superImportantFn );
    }

    View full-size slide

  54. function superImportantFn( e ) {
    var $t = $( this ),
    important = $t.pluginVal();
    $t.addClass( “specialState” );
    $t.removeClass( “pluginState” );
    $t.find( “.aChild” ).append( coolStuff );
    $t.find( “.someBtn” ).prop( “disabled” );
    // $t.find( “ugh this is a nightmare” );
    }

    View full-size slide

  55. /* Name: MagicWidget™
    Author: not you!
    License: lol wat
    */
    $.fn.transformIntoMagicWidget = function() {
    return this.each( function() {
    // MODIFIED: grm 11-10-2013
    // added all that state and CSS stuff
    ...
    });
    };

    View full-size slide

  56. ‘ you’re writing a whole new plugin
    ‘ based on something you don’t control
    ‘ that might get abandoned
    ‘ and getting minimal value from the original
    oh hey.

    View full-size slide

  57. don’t use external tools
    that almost do something.

    View full-size slide

  58. #8
    “MVC means never having
    to say require”

    View full-size slide

  59. but this framework doesn’t
    use AMD
    ‘ single point of entry = one place to manage
    dependencies
    ‘ it’s already clear what the code is doing
    ‘ loading stuff is abstracted out anyway
    ‘ the internet says you don’t have to worry about
    speed if you don’t have any JPGs

    View full-size slide

  60. BigController = function() {
    BigView.renderEverything();
    };

    View full-size slide

  61. ► Uncaught Error: Object # has no
    method ‘renderEverything’

    View full-size slide

  62. BigController = function( refresh ) {
    if ( refresh ) {
    BigView.setData( data );
    }
    BigView.renderEverything();
    };

    View full-size slide

  63. ► Uncaught ReferenceError: data is not
    defined

    View full-size slide

  64. BigController = function( refresh ) {
    if ( refresh ) {
    if ( data ) {
    BigView.setData( data );
    } else {
    $.get( “/newData”, function( d ) {
    BigView.setData( d );
    });
    }
    }
    BigView.renderEverything();
    };

    View full-size slide

  65. ► Uncaught Error: u should use a dependency
    loader

    View full-size slide

  66. ‘ relying on globals or sub-globals is fragile
    ‘ lots of tests to see whether things are available
    ‘ whole chain has to be reexamined for each edge
    case
    ‘ can’t abstract out loading
    lack of modularity
    encourages messes

    View full-size slide

  67. assume everything will be
    a module.

    View full-size slide

  68. #9
    “it works with [terrible thing
    you use now]!”

    View full-size slide

  69. we’re limiting our risk!
    ‘ less to rewrite
    ‘ more time to improve
    ‘ makes use of all that hard work we did on the
    original

    View full-size slide

  70. /* TODO: delete me i am being replaced
    function doStuff() {
    var output = TerribleThing.use();
    Module.transform( output );
    OtherModule.render( output );
    CoolModule.observe( output );
    }
    */

    View full-size slide

  71. function doStuff() {
    var output = TerribleThing.use();
    Frmwrk.transform( output );
    Frmwrk.TrriblView.render( output );
    Frmwrk.Events.observe( output );
    }

    View full-size slide

  72. ‘ rewriting around existing code tends to give you..
    the same code
    ‘ if a tool is bad or niche, no framework on earth
    can save you from it
    ‘ trying to avoid change limits your ability to improve
    ‘ which leaves you itching to.. rewrite
    you saved 4 LoC!

    View full-size slide

  73. throw out assumptions
    about how things will work.

    View full-size slide

  74. #10
    “we found our solution;
    what’s the problem?”

    View full-size slide

  75. this thing looks great!
    ‘ super modern
    ‘ fast benchmarks
    ‘ incredibly flexible, rich tooling, great community,
    thorough docs, brilliant API, scales to infinity, tiny
    download, hipster syntax, cool colors, foot
    massages, free unicorns, and a trip to space!

    View full-size slide

  76. but does it solve your
    problem?
    ‘ easy to gloss over if you haven’t defined your
    problem
    ‘ no i mean like broken it down
    ‘ no into more than three bullet points
    ‘ taking the time to define problems avoids irrelevant
    solutions

    View full-size slide

  77. to proof of concept you
    have to know what to
    prove.

    View full-size slide

  78. no more.
    we don’t want any of
    that.

    View full-size slide

  79. none of those are
    uncommon.

    View full-size slide

  80. it’s hard to avoid rewriting
    completely..

    View full-size slide

  81. the goal is not to do it
    more than once.

    View full-size slide

  82. rewrite planning
    ‗ can you devote the people?
    ‗ do you know the problems the rewrite should
    solve?
    ‗ do you have tests to avoid regressions?
    ‗ most important: can you commit?

    View full-size slide

  83. #0 way to rewrite a lot:
    cold feet.

    View full-size slide

  84. you have to commit
    ‗ don’t expect it to happen overnight
    ‗ don’t expect to iterate on atomic pieces
    ‗ don’t fail fast (you did that your current app)
    ‗ don’t start coding until you have a plan

    View full-size slide

  85. throw out everything you
    know about RAD.

    View full-size slide

  86. a plan you can’t commit
    to isn’t one.

    View full-size slide

  87. good plans keep you from
    getting to ten rewrites.

    View full-size slide

  88. thanks!
    @garannm ☔ [email protected] ☔ garann.com

    View full-size slide