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. 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?
  2. 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?
  3. 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
  4. bad rewrites ‘ you’ve got 20% of the app written

    and you realize it’s all wrong
  5. 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!
  6. function ThisIsGoingSoWell( opts ) { this.init = function() {}; this.url

    = “cool/api/path”; } Frmwrk.extend( ThisIsGoingSoWell, Model );
  7. function ActuallyDoStuff() { // TODO: state objects? // TODO: event

    handlers? // TODO: idk this isn’t in the docs?? };
  8. 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
  9. ( function MyFrmwrk( window ) { this.init = function() {};

    this.url = function() {}; window.Frmwrk = this; })( window );
  10. ‘ 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!
  11. 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
  12. 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 };
  13. ViewOne.render = function() { // get data, populate template, transform

    inline $.get( “/viewOne”, function( data ) { container.html( tmpl( data ) ); }); };
  14. ViewTwo.render = function() { // get transformed data, populate template

    $.get( “/viewTwo”, { language: “en” }, function( data ) { container.html( tmpl( data ) ); }); };
  15. ViewThree.render = function() { // get populated template from server

    $.get( “/viewThree”, { language: “en”, subtmpl: “error” }, function( html ) { container.html( html ); }); };
  16. ‘ 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?!
  17. super-ultra-optimized ‘ static stuff rendered by server ‘ dynamic stuff

    by client ‘ server folks speak their language, JS folks speak theirs
  18. 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
  19. 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!
  20. // _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 })();
  21. // oh. ( function FileUploadHandler() { // expose all that

    Flash stuff to JS // let the widget be used in a larger form })();
  22. // 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 })();
  23. ‘ 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
  24. 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
  25. MyApp.init = function() { // look, no options! // we’ll

    just select the necessary nodes.. // and then find their attributes.. // parse those to data types.. };
  26. 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.. };
  27. ‘ 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
  28. 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
  29. function veryImportant( item ) { var $item = $( item

    ); $item.transformIntoMagicWidget(); // NOW we can actually use it $item.on( “pluginEvent”, superImportantFn ); }
  30. 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” ); }
  31. /* 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 ... }); };
  32. ‘ 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.
  33. 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
  34. BigController = function( refresh ) { if ( refresh )

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

    { if ( data ) { BigView.setData( data ); } else { $.get( “/newData”, function( d ) { BigView.setData( d ); }); } } BigView.renderEverything(); };
  36. ‘ 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
  37. we’re limiting our risk! ‘ less to rewrite ‘ more

    time to improve ‘ makes use of all that hard work we did on the original
  38. /* TODO: delete me i am being replaced function doStuff()

    { var output = TerribleThing.use(); Module.transform( output ); OtherModule.render( output ); CoolModule.observe( output ); } */
  39. function doStuff() { var output = TerribleThing.use(); Frmwrk.transform( output );

    Frmwrk.TrriblView.render( output ); Frmwrk.Events.observe( output ); }
  40. ‘ 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!
  41. 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!
  42. 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
  43. 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?
  44. 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