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

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

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 Slide

  2. the hardest problem in app
    development

    View 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 Slide

  4. coding is easy.
    planning is hard.

    View Slide

  5. we tend to overprioritize
    the easy one.

    View Slide

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

    View Slide

  7. different set of worries

    View 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 Slide

  9. ok. rewrites are inevitable.

    View 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 Slide

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

    View Slide

  12. bad rewrites require
    starting over [again].

    View Slide

  13. bad rewrites are not
    inevitable.

    View Slide

  14. comprehensive”>

    View Slide

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

    View 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 Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View 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 Slide

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

    View 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 Slide

  25. only write one application
    at a time.

    View Slide

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

    View 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 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 Slide

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

    View Slide

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

    View Slide

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

    View 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 Slide

  33. specify APIs thoroughly
    and early.

    View Slide

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

    View Slide

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

    View 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 Slide

  37. plan the stuff outside your
    JavaScript as well.

    View Slide

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

    View 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 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 Slide

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

    View 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 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 Slide

  44. only write one application
    at a time.

    View Slide

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

    View 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 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 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 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 Slide

  50. data deserves a real
    home.

    View Slide

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

    View 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 Slide

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

    View 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 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 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 Slide

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

    View Slide

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

    View 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 Slide

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

    View Slide

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

    View Slide

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

    View Slide

  63. ► Uncaught ReferenceError: data is not
    defined

    View Slide

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

    View Slide

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

    View 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 Slide

  67. assume everything will be
    a module.

    View Slide

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

    View 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 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 Slide

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

    View 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 Slide

  73. throw out assumptions
    about how things will work.

    View Slide

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

    View 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 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 Slide

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

    View Slide


  78. View Slide

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

    View Slide

  80. none of those are
    uncommon.

    View Slide

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

    View Slide

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

    View Slide

  83. 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 Slide

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

    View Slide

  85. 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 Slide

  86. throw out everything you
    know about RAD.

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide