Slide 1

Slide 1 text

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

Slide 2

Slide 2 text

the hardest problem in app development

Slide 3

Slide 3 text

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?

Slide 4

Slide 4 text

coding is easy. planning is hard.

Slide 5

Slide 5 text

we tend to overprioritize the easy one.

Slide 6

Slide 6 text

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

Slide 7

Slide 7 text

different set of worries

Slide 8

Slide 8 text

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?

Slide 9

Slide 9 text

ok. rewrites are inevitable.

Slide 10

Slide 10 text

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

Slide 11

Slide 11 text

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

Slide 12

Slide 12 text

bad rewrites require starting over [again].

Slide 13

Slide 13 text

bad rewrites are not inevitable.

Slide 14

Slide 14 text

Slide 15

Slide 15 text

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

Slide 16

Slide 16 text

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!

Slide 17

Slide 17 text

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

Slide 18

Slide 18 text

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

Slide 19

Slide 19 text

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

Slide 20

Slide 20 text

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

Slide 21

Slide 21 text

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

Slide 22

Slide 22 text

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

Slide 23

Slide 23 text

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

Slide 24

Slide 24 text

‘ 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!

Slide 25

Slide 25 text

only write one application at a time.

Slide 26

Slide 26 text

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

Slide 27

Slide 27 text

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

Slide 28

Slide 28 text

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 };

Slide 29

Slide 29 text

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

Slide 30

Slide 30 text

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

Slide 31

Slide 31 text

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

Slide 32

Slide 32 text

‘ 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?!

Slide 33

Slide 33 text

specify APIs thoroughly and early.

Slide 34

Slide 34 text

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

Slide 35

Slide 35 text

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

Slide 36

Slide 36 text

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

Slide 37

Slide 37 text

plan the stuff outside your JavaScript as well.

Slide 38

Slide 38 text

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

Slide 39

Slide 39 text

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!

Slide 40

Slide 40 text

// _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 })();

Slide 41

Slide 41 text

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

Slide 42

Slide 42 text

// 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 })();

Slide 43

Slide 43 text

‘ 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

Slide 44

Slide 44 text

only write one application at a time.

Slide 45

Slide 45 text

#6 “XHR? more like HTML amirite”

Slide 46

Slide 46 text

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

Slide 47

Slide 47 text

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

Slide 48

Slide 48 text

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.. };

Slide 49

Slide 49 text

‘ 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

Slide 50

Slide 50 text

data deserves a real home.

Slide 51

Slide 51 text

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

Slide 52

Slide 52 text

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

Slide 53

Slide 53 text

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

Slide 54

Slide 54 text

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” ); }

Slide 55

Slide 55 text

/* 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 ... }); };

Slide 56

Slide 56 text

‘ 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.

Slide 57

Slide 57 text

don’t use external tools that almost do something.

Slide 58

Slide 58 text

#8 “MVC means never having to say require”

Slide 59

Slide 59 text

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

Slide 60

Slide 60 text

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

Slide 61

Slide 61 text

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

Slide 62

Slide 62 text

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

Slide 63

Slide 63 text

► Uncaught ReferenceError: data is not defined

Slide 64

Slide 64 text

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

Slide 65

Slide 65 text

► Uncaught Error: u should use a dependency loader

Slide 66

Slide 66 text

‘ 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

Slide 67

Slide 67 text

assume everything will be a module.

Slide 68

Slide 68 text

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

Slide 69

Slide 69 text

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

Slide 70

Slide 70 text

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

Slide 71

Slide 71 text

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

Slide 72

Slide 72 text

‘ 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!

Slide 73

Slide 73 text

throw out assumptions about how things will work.

Slide 74

Slide 74 text

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

Slide 75

Slide 75 text

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!

Slide 76

Slide 76 text

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

Slide 77

Slide 77 text

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

Slide 78

Slide 78 text

Slide 79

Slide 79 text

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

Slide 80

Slide 80 text

none of those are uncommon.

Slide 81

Slide 81 text

it’s hard to avoid rewriting completely..

Slide 82

Slide 82 text

the goal is not to do it more than once.

Slide 83

Slide 83 text

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?

Slide 84

Slide 84 text

#0 way to rewrite a lot: cold feet.

Slide 85

Slide 85 text

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

Slide 86

Slide 86 text

throw out everything you know about RAD.

Slide 87

Slide 87 text

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

Slide 88

Slide 88 text

good plans keep you from getting to ten rewrites.

Slide 89

Slide 89 text

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