Javascript spaghetti stirtrek_5_17
-
Upload
jared-faris -
Category
Technology
-
view
542 -
download
0
description
Transcript of Javascript spaghetti stirtrek_5_17
![Page 1: Javascript spaghetti stirtrek_5_17](https://reader034.fdocuments.us/reader034/viewer/2022051322/545aee7cb1af9fcf338b5f85/html5/thumbnails/1.jpg)
Building Rich User Experienceswithout
JavaScript Spaghetti
by Jared Faris
@jaredthenerd
jaredthenerd.com
![Page 2: Javascript spaghetti stirtrek_5_17](https://reader034.fdocuments.us/reader034/viewer/2022051322/545aee7cb1af9fcf338b5f85/html5/thumbnails/2.jpg)
About me
![Page 3: Javascript spaghetti stirtrek_5_17](https://reader034.fdocuments.us/reader034/viewer/2022051322/545aee7cb1af9fcf338b5f85/html5/thumbnails/3.jpg)
![Page 4: Javascript spaghetti stirtrek_5_17](https://reader034.fdocuments.us/reader034/viewer/2022051322/545aee7cb1af9fcf338b5f85/html5/thumbnails/4.jpg)
Traditional Web Development
Web assets are created last to glue together things.
Stakeholders, architects and developers define the
“real” application.
The application is built model first (from the DB up).
![Page 5: Javascript spaghetti stirtrek_5_17](https://reader034.fdocuments.us/reader034/viewer/2022051322/545aee7cb1af9fcf338b5f85/html5/thumbnails/5.jpg)
Traditional Web Development
The design is focused on making the CRUD pretty, not
usable
The design of the UI/UX happens in Photoshop... if it
happens at all.
Most of the application is just CRUD.
![Page 6: Javascript spaghetti stirtrek_5_17](https://reader034.fdocuments.us/reader034/viewer/2022051322/545aee7cb1af9fcf338b5f85/html5/thumbnails/6.jpg)
We have a widgets
table
We need a
widgets
screen!
![Page 7: Javascript spaghetti stirtrek_5_17](https://reader034.fdocuments.us/reader034/viewer/2022051322/545aee7cb1af9fcf338b5f85/html5/thumbnails/7.jpg)
Traditional Web Development
“Advanced” web developers write lots of unorganized
bits of jQuery.
Most user interactions result in lots of POSTS back
to the server.
JavaScripts are something someone download from
hotscripts.com.
![Page 8: Javascript spaghetti stirtrek_5_17](https://reader034.fdocuments.us/reader034/viewer/2022051322/545aee7cb1af9fcf338b5f85/html5/thumbnails/8.jpg)
We have a widgets
table
We need a
widgets
screen!
Make sure you
add a date picker
And a lighbox!
![Page 9: Javascript spaghetti stirtrek_5_17](https://reader034.fdocuments.us/reader034/viewer/2022051322/545aee7cb1af9fcf338b5f85/html5/thumbnails/9.jpg)
JavaScript: Not a “Real” Language
Patternless design.
Built as a glue to bind pieces together, not as a core
component of the application.
Not thought through like server-side code.
![Page 10: Javascript spaghetti stirtrek_5_17](https://reader034.fdocuments.us/reader034/viewer/2022051322/545aee7cb1af9fcf338b5f85/html5/thumbnails/10.jpg)
Not Real? Why?
A lot of development tools traditionally hid the JS behind
configurable controls.
Libraries like jQuery make it really easy to pile on lots of
little events.
JS used to be a tool for doing image rollovers.
![Page 11: Javascript spaghetti stirtrek_5_17](https://reader034.fdocuments.us/reader034/viewer/2022051322/545aee7cb1af9fcf338b5f85/html5/thumbnails/11.jpg)
Is That A Problem?
In a workflow-based application it falls apart.
For form-based apps that was mostly fine.
Customized, reusable controls and a modular
application design needs something more.
![Page 12: Javascript spaghetti stirtrek_5_17](https://reader034.fdocuments.us/reader034/viewer/2022051322/545aee7cb1af9fcf338b5f85/html5/thumbnails/12.jpg)
Questions So Far?
![Page 13: Javascript spaghetti stirtrek_5_17](https://reader034.fdocuments.us/reader034/viewer/2022051322/545aee7cb1af9fcf338b5f85/html5/thumbnails/13.jpg)
A Typical Product LifecycleSomewhat dramatized...
![Page 14: Javascript spaghetti stirtrek_5_17](https://reader034.fdocuments.us/reader034/viewer/2022051322/545aee7cb1af9fcf338b5f85/html5/thumbnails/14.jpg)
Designer Developer
![Page 15: Javascript spaghetti stirtrek_5_17](https://reader034.fdocuments.us/reader034/viewer/2022051322/545aee7cb1af9fcf338b5f85/html5/thumbnails/15.jpg)
We need this
feature
![Page 16: Javascript spaghetti stirtrek_5_17](https://reader034.fdocuments.us/reader034/viewer/2022051322/545aee7cb1af9fcf338b5f85/html5/thumbnails/16.jpg)
I got this
![Page 17: Javascript spaghetti stirtrek_5_17](https://reader034.fdocuments.us/reader034/viewer/2022051322/545aee7cb1af9fcf338b5f85/html5/thumbnails/17.jpg)
?
![Page 18: Javascript spaghetti stirtrek_5_17](https://reader034.fdocuments.us/reader034/viewer/2022051322/545aee7cb1af9fcf338b5f85/html5/thumbnails/18.jpg)
Tweaking time...
![Page 19: Javascript spaghetti stirtrek_5_17](https://reader034.fdocuments.us/reader034/viewer/2022051322/545aee7cb1af9fcf338b5f85/html5/thumbnails/19.jpg)
I got another
great idea
![Page 20: Javascript spaghetti stirtrek_5_17](https://reader034.fdocuments.us/reader034/viewer/2022051322/545aee7cb1af9fcf338b5f85/html5/thumbnails/20.jpg)
Now you tell
me
![Page 21: Javascript spaghetti stirtrek_5_17](https://reader034.fdocuments.us/reader034/viewer/2022051322/545aee7cb1af9fcf338b5f85/html5/thumbnails/21.jpg)
The developer bolts on some more code
![Page 22: Javascript spaghetti stirtrek_5_17](https://reader034.fdocuments.us/reader034/viewer/2022051322/545aee7cb1af9fcf338b5f85/html5/thumbnails/22.jpg)
And another
thing...
![Page 23: Javascript spaghetti stirtrek_5_17](https://reader034.fdocuments.us/reader034/viewer/2022051322/545aee7cb1af9fcf338b5f85/html5/thumbnails/23.jpg)
grrr
![Page 24: Javascript spaghetti stirtrek_5_17](https://reader034.fdocuments.us/reader034/viewer/2022051322/545aee7cb1af9fcf338b5f85/html5/thumbnails/24.jpg)
We don’t
‘really’need this
![Page 25: Javascript spaghetti stirtrek_5_17](https://reader034.fdocuments.us/reader034/viewer/2022051322/545aee7cb1af9fcf338b5f85/html5/thumbnails/25.jpg)
Uh, yeah we
do
![Page 26: Javascript spaghetti stirtrek_5_17](https://reader034.fdocuments.us/reader034/viewer/2022051322/545aee7cb1af9fcf338b5f85/html5/thumbnails/26.jpg)
![Page 27: Javascript spaghetti stirtrek_5_17](https://reader034.fdocuments.us/reader034/viewer/2022051322/545aee7cb1af9fcf338b5f85/html5/thumbnails/27.jpg)
The developer bolts on some more code
![Page 28: Javascript spaghetti stirtrek_5_17](https://reader034.fdocuments.us/reader034/viewer/2022051322/545aee7cb1af9fcf338b5f85/html5/thumbnails/28.jpg)
Some time passes
‘Some time’ is defined as:
Just long enough that the developer doesn’t remember
exactly how his original code works.
![Page 29: Javascript spaghetti stirtrek_5_17](https://reader034.fdocuments.us/reader034/viewer/2022051322/545aee7cb1af9fcf338b5f85/html5/thumbnails/29.jpg)
I’ve got a new
feature
![Page 30: Javascript spaghetti stirtrek_5_17](https://reader034.fdocuments.us/reader034/viewer/2022051322/545aee7cb1af9fcf338b5f85/html5/thumbnails/30.jpg)
Angry developers
can really do this.
IT managers be
warned.
![Page 31: Javascript spaghetti stirtrek_5_17](https://reader034.fdocuments.us/reader034/viewer/2022051322/545aee7cb1af9fcf338b5f85/html5/thumbnails/31.jpg)
Protective Beret
![Page 32: Javascript spaghetti stirtrek_5_17](https://reader034.fdocuments.us/reader034/viewer/2022051322/545aee7cb1af9fcf338b5f85/html5/thumbnails/32.jpg)
More messy code
![Page 33: Javascript spaghetti stirtrek_5_17](https://reader034.fdocuments.us/reader034/viewer/2022051322/545aee7cb1af9fcf338b5f85/html5/thumbnails/33.jpg)
The last bug
Oh wait, one more
![Page 34: Javascript spaghetti stirtrek_5_17](https://reader034.fdocuments.us/reader034/viewer/2022051322/545aee7cb1af9fcf338b5f85/html5/thumbnails/34.jpg)
Finally
(14 tests ought to be enough for anybody)
![Page 35: Javascript spaghetti stirtrek_5_17](https://reader034.fdocuments.us/reader034/viewer/2022051322/545aee7cb1af9fcf338b5f85/html5/thumbnails/35.jpg)
The next day...
![Page 36: Javascript spaghetti stirtrek_5_17](https://reader034.fdocuments.us/reader034/viewer/2022051322/545aee7cb1af9fcf338b5f85/html5/thumbnails/36.jpg)
![Page 37: Javascript spaghetti stirtrek_5_17](https://reader034.fdocuments.us/reader034/viewer/2022051322/545aee7cb1af9fcf338b5f85/html5/thumbnails/37.jpg)
Two weeks pass.
![Page 38: Javascript spaghetti stirtrek_5_17](https://reader034.fdocuments.us/reader034/viewer/2022051322/545aee7cb1af9fcf338b5f85/html5/thumbnails/38.jpg)
I’ve got a new
featureGahh!
![Page 39: Javascript spaghetti stirtrek_5_17](https://reader034.fdocuments.us/reader034/viewer/2022051322/545aee7cb1af9fcf338b5f85/html5/thumbnails/39.jpg)
![Page 40: Javascript spaghetti stirtrek_5_17](https://reader034.fdocuments.us/reader034/viewer/2022051322/545aee7cb1af9fcf338b5f85/html5/thumbnails/40.jpg)
No developers were harmed in the making
of this dramatic reenactment.
![Page 41: Javascript spaghetti stirtrek_5_17](https://reader034.fdocuments.us/reader034/viewer/2022051322/545aee7cb1af9fcf338b5f85/html5/thumbnails/41.jpg)
Poor design patterns
+ crappy code
= JavaScript spaghetti
![Page 42: Javascript spaghetti stirtrek_5_17](https://reader034.fdocuments.us/reader034/viewer/2022051322/545aee7cb1af9fcf338b5f85/html5/thumbnails/42.jpg)
Why does this happen?
![Page 43: Javascript spaghetti stirtrek_5_17](https://reader034.fdocuments.us/reader034/viewer/2022051322/545aee7cb1af9fcf338b5f85/html5/thumbnails/43.jpg)
Some Reasons
• JavaScript isn’t real code
• We don’t treat client side things as real features
• We can’t easily test it
• We don’t like writing it
• It behaves differently in different browsers*
* Or at least it used to
![Page 44: Javascript spaghetti stirtrek_5_17](https://reader034.fdocuments.us/reader034/viewer/2022051322/545aee7cb1af9fcf338b5f85/html5/thumbnails/44.jpg)
This really all boils down to one thing.
We developers suck.
![Page 45: Javascript spaghetti stirtrek_5_17](https://reader034.fdocuments.us/reader034/viewer/2022051322/545aee7cb1af9fcf338b5f85/html5/thumbnails/45.jpg)
Three JavaScript Principles
Push events, not state
Write small, discrete bits of code
Decouple everything
![Page 46: Javascript spaghetti stirtrek_5_17](https://reader034.fdocuments.us/reader034/viewer/2022051322/545aee7cb1af9fcf338b5f85/html5/thumbnails/46.jpg)
Decouple Everything
Apply your OO best practices here too.
Remove dependencies between objects.
Start thinking about UI pieces as individual JS objects.
![Page 47: Javascript spaghetti stirtrek_5_17](https://reader034.fdocuments.us/reader034/viewer/2022051322/545aee7cb1af9fcf338b5f85/html5/thumbnails/47.jpg)
Small Chunks Of Code
Even if you don’t test everything, learning how to
write testable code means learning
how to write better code
Put the rest of the stuff in classes that you can test.
Separate DOM dependent stuff into a single layer.
![Page 48: Javascript spaghetti stirtrek_5_17](https://reader034.fdocuments.us/reader034/viewer/2022051322/545aee7cb1af9fcf338b5f85/html5/thumbnails/48.jpg)
Push Events, Not State
Inform other controls that “X happened to Y”,
not “Y is in X state”
Let controls worry about their own state.
Know about the Law of Demeter.
![Page 49: Javascript spaghetti stirtrek_5_17](https://reader034.fdocuments.us/reader034/viewer/2022051322/545aee7cb1af9fcf338b5f85/html5/thumbnails/49.jpg)
Writing Better JavaScript
Find the tools that make your life easier.
Use the design patterns you already know.
Leverage language features whether JS has them or not.
![Page 50: Javascript spaghetti stirtrek_5_17](https://reader034.fdocuments.us/reader034/viewer/2022051322/545aee7cb1af9fcf338b5f85/html5/thumbnails/50.jpg)
Language Features
Keep state inside of the objects and expose methods.
Objects have state and behavior.
JavaScript loves its objects. Create them to represent
page elements.
![Page 51: Javascript spaghetti stirtrek_5_17](https://reader034.fdocuments.us/reader034/viewer/2022051322/545aee7cb1af9fcf338b5f85/html5/thumbnails/51.jpg)
Language “Features”
Consider using namespaces.
![Page 52: Javascript spaghetti stirtrek_5_17](https://reader034.fdocuments.us/reader034/viewer/2022051322/545aee7cb1af9fcf338b5f85/html5/thumbnails/52.jpg)
JavaScript Namespacing
![Page 53: Javascript spaghetti stirtrek_5_17](https://reader034.fdocuments.us/reader034/viewer/2022051322/545aee7cb1af9fcf338b5f85/html5/thumbnails/53.jpg)
Language “Features”
Use inheritance or faux subclassing.
Consider using namespaces.
![Page 54: Javascript spaghetti stirtrek_5_17](https://reader034.fdocuments.us/reader034/viewer/2022051322/545aee7cb1af9fcf338b5f85/html5/thumbnails/54.jpg)
JavaScript Prototyping
![Page 55: Javascript spaghetti stirtrek_5_17](https://reader034.fdocuments.us/reader034/viewer/2022051322/545aee7cb1af9fcf338b5f85/html5/thumbnails/55.jpg)
Coffeescript Classes
![Page 56: Javascript spaghetti stirtrek_5_17](https://reader034.fdocuments.us/reader034/viewer/2022051322/545aee7cb1af9fcf338b5f85/html5/thumbnails/56.jpg)
Language “Features”
Pass JSON around asynchronously.
Use inheritance or faux subclassing.
Consider using namespaces.
![Page 57: Javascript spaghetti stirtrek_5_17](https://reader034.fdocuments.us/reader034/viewer/2022051322/545aee7cb1af9fcf338b5f85/html5/thumbnails/57.jpg)
Design Patterns
![Page 58: Javascript spaghetti stirtrek_5_17](https://reader034.fdocuments.us/reader034/viewer/2022051322/545aee7cb1af9fcf338b5f85/html5/thumbnails/58.jpg)
Mediator Pattern
“The essence of the Mediator Pattern is to ‘Define an
object that encapsulates how a set of objects interact.
Mediator promotes loose coupling by keeping objects
from referring to each other explicitly, and it lets you
vary their interaction independently.’”
-Design Patterns: Elements of Reusable Object-Oriented Software
![Page 59: Javascript spaghetti stirtrek_5_17](https://reader034.fdocuments.us/reader034/viewer/2022051322/545aee7cb1af9fcf338b5f85/html5/thumbnails/59.jpg)
NavControlMediator
itemSelected()
Events from some
other object
unselectAll()
![Page 60: Javascript spaghetti stirtrek_5_17](https://reader034.fdocuments.us/reader034/viewer/2022051322/545aee7cb1af9fcf338b5f85/html5/thumbnails/60.jpg)
Observer Pattern
"Define a one-to-many dependency between objects so
that when one object changes state, all its dependents
are notified and updated automatically."
-Design Patterns: Elements of Reusable Object-Oriented Software
Think jQuery $(‘.something’).click()
![Page 61: Javascript spaghetti stirtrek_5_17](https://reader034.fdocuments.us/reader034/viewer/2022051322/545aee7cb1af9fcf338b5f85/html5/thumbnails/61.jpg)
NavControlMediator
itemSelected()
Events from some
other object
unselectAll()
viewModel
![Page 62: Javascript spaghetti stirtrek_5_17](https://reader034.fdocuments.us/reader034/viewer/2022051322/545aee7cb1af9fcf338b5f85/html5/thumbnails/62.jpg)
Tools & Frameworks
![Page 63: Javascript spaghetti stirtrek_5_17](https://reader034.fdocuments.us/reader034/viewer/2022051322/545aee7cb1af9fcf338b5f85/html5/thumbnails/63.jpg)
Knockout
Magic.
Setup a template with some markup binding it.
Setup a JavaScript object with some KO code.
![Page 64: Javascript spaghetti stirtrek_5_17](https://reader034.fdocuments.us/reader034/viewer/2022051322/545aee7cb1af9fcf338b5f85/html5/thumbnails/64.jpg)
![Page 65: Javascript spaghetti stirtrek_5_17](https://reader034.fdocuments.us/reader034/viewer/2022051322/545aee7cb1af9fcf338b5f85/html5/thumbnails/65.jpg)
![Page 66: Javascript spaghetti stirtrek_5_17](https://reader034.fdocuments.us/reader034/viewer/2022051322/545aee7cb1af9fcf338b5f85/html5/thumbnails/66.jpg)
A KO Warning
It’s really easy to go overboard with KO events.
I prefer to use KO for the VM binding (observables and
computeds) but rely on jQuery for events.
jQuery’s .on() binding and a good understanding of
‘this’ makes for much cleaner events.
![Page 67: Javascript spaghetti stirtrek_5_17](https://reader034.fdocuments.us/reader034/viewer/2022051322/545aee7cb1af9fcf338b5f85/html5/thumbnails/67.jpg)
Backbone
Views help you control the visual rendering.
Routers help you organize page flow.
While KO is Model < > View magic, Backbone is structure.
Models help you keep track of state.
![Page 68: Javascript spaghetti stirtrek_5_17](https://reader034.fdocuments.us/reader034/viewer/2022051322/545aee7cb1af9fcf338b5f85/html5/thumbnails/68.jpg)
Backbone Use Case
![Page 69: Javascript spaghetti stirtrek_5_17](https://reader034.fdocuments.us/reader034/viewer/2022051322/545aee7cb1af9fcf338b5f85/html5/thumbnails/69.jpg)
What about all the other
frameworks?
![Page 70: Javascript spaghetti stirtrek_5_17](https://reader034.fdocuments.us/reader034/viewer/2022051322/545aee7cb1af9fcf338b5f85/html5/thumbnails/70.jpg)
Pub/Sub + Fairy Dust = Service Bus
Pub/Sub is great to make sure events propagate.
It starts to get brittle with lots of different controls.
![Page 71: Javascript spaghetti stirtrek_5_17](https://reader034.fdocuments.us/reader034/viewer/2022051322/545aee7cb1af9fcf338b5f85/html5/thumbnails/71.jpg)
Way Too Much Pubbing and Subbing
![Page 72: Javascript spaghetti stirtrek_5_17](https://reader034.fdocuments.us/reader034/viewer/2022051322/545aee7cb1af9fcf338b5f85/html5/thumbnails/72.jpg)
Service Bus
Your controls are then only coupled to a single thing.
Controls that want to communicate speak through it.
A service bus is another layer that sits outside controls.
![Page 73: Javascript spaghetti stirtrek_5_17](https://reader034.fdocuments.us/reader034/viewer/2022051322/545aee7cb1af9fcf338b5f85/html5/thumbnails/73.jpg)
Postal.js
![Page 74: Javascript spaghetti stirtrek_5_17](https://reader034.fdocuments.us/reader034/viewer/2022051322/545aee7cb1af9fcf338b5f85/html5/thumbnails/74.jpg)
Service Bus + Mediator
• Controls no longer need to know about others.
• We can remove/replace controls individually.
• We can add controls that listen to the same events
without modifying the publisher.
• We can re-use pieces more easily because they work
in a standard way.
![Page 75: Javascript spaghetti stirtrek_5_17](https://reader034.fdocuments.us/reader034/viewer/2022051322/545aee7cb1af9fcf338b5f85/html5/thumbnails/75.jpg)
NavControlMediator
itemSelected()
Events from some
other object
unselectAll()
viewModel
ReportMediator
itemChanged()
unselectAll()
viewModel
Service Bus
![Page 76: Javascript spaghetti stirtrek_5_17](https://reader034.fdocuments.us/reader034/viewer/2022051322/545aee7cb1af9fcf338b5f85/html5/thumbnails/76.jpg)
NavControlMediator
itemSelected()
Events from some
other object
unselectAll()
viewModel
ReportMediator
itemChanged()
unselectAll()
viewModel
Service Bus
HistoryControl
![Page 77: Javascript spaghetti stirtrek_5_17](https://reader034.fdocuments.us/reader034/viewer/2022051322/545aee7cb1af9fcf338b5f85/html5/thumbnails/77.jpg)
Service Bus
TeamControl
Gets team changed
message, makes AJAX
call for this team’s data,
rewrites team with template
No view model
![Page 78: Javascript spaghetti stirtrek_5_17](https://reader034.fdocuments.us/reader034/viewer/2022051322/545aee7cb1af9fcf338b5f85/html5/thumbnails/78.jpg)
Service Bus
![Page 79: Javascript spaghetti stirtrek_5_17](https://reader034.fdocuments.us/reader034/viewer/2022051322/545aee7cb1af9fcf338b5f85/html5/thumbnails/79.jpg)
Testing
Try to have layers of your application’s JS that don’t
touch any HTML elements.
Store data in models inside individual controls and test
that published messages change the state of those
models correctly.
![Page 80: Javascript spaghetti stirtrek_5_17](https://reader034.fdocuments.us/reader034/viewer/2022051322/545aee7cb1af9fcf338b5f85/html5/thumbnails/80.jpg)
Underscore
![Page 81: Javascript spaghetti stirtrek_5_17](https://reader034.fdocuments.us/reader034/viewer/2022051322/545aee7cb1af9fcf338b5f85/html5/thumbnails/81.jpg)
Underscore
![Page 82: Javascript spaghetti stirtrek_5_17](https://reader034.fdocuments.us/reader034/viewer/2022051322/545aee7cb1af9fcf338b5f85/html5/thumbnails/82.jpg)
Underscore w/ Coffeescript
![Page 83: Javascript spaghetti stirtrek_5_17](https://reader034.fdocuments.us/reader034/viewer/2022051322/545aee7cb1af9fcf338b5f85/html5/thumbnails/83.jpg)
What Else?
I don’t have a third bullet point here
Browser Debuggers
Templates
![Page 84: Javascript spaghetti stirtrek_5_17](https://reader034.fdocuments.us/reader034/viewer/2022051322/545aee7cb1af9fcf338b5f85/html5/thumbnails/84.jpg)
A Typical Product LifecycleRound Two
![Page 85: Javascript spaghetti stirtrek_5_17](https://reader034.fdocuments.us/reader034/viewer/2022051322/545aee7cb1af9fcf338b5f85/html5/thumbnails/85.jpg)
We need this
feature
![Page 86: Javascript spaghetti stirtrek_5_17](https://reader034.fdocuments.us/reader034/viewer/2022051322/545aee7cb1af9fcf338b5f85/html5/thumbnails/86.jpg)
I got a few
questions
![Page 87: Javascript spaghetti stirtrek_5_17](https://reader034.fdocuments.us/reader034/viewer/2022051322/545aee7cb1af9fcf338b5f85/html5/thumbnails/87.jpg)
?
![Page 88: Javascript spaghetti stirtrek_5_17](https://reader034.fdocuments.us/reader034/viewer/2022051322/545aee7cb1af9fcf338b5f85/html5/thumbnails/88.jpg)
Tweaking time...
![Page 89: Javascript spaghetti stirtrek_5_17](https://reader034.fdocuments.us/reader034/viewer/2022051322/545aee7cb1af9fcf338b5f85/html5/thumbnails/89.jpg)
I got another
great idea
![Page 90: Javascript spaghetti stirtrek_5_17](https://reader034.fdocuments.us/reader034/viewer/2022051322/545aee7cb1af9fcf338b5f85/html5/thumbnails/90.jpg)
Ok, Cool
![Page 91: Javascript spaghetti stirtrek_5_17](https://reader034.fdocuments.us/reader034/viewer/2022051322/545aee7cb1af9fcf338b5f85/html5/thumbnails/91.jpg)
And another
thing...
![Page 92: Javascript spaghetti stirtrek_5_17](https://reader034.fdocuments.us/reader034/viewer/2022051322/545aee7cb1af9fcf338b5f85/html5/thumbnails/92.jpg)
Done.
![Page 93: Javascript spaghetti stirtrek_5_17](https://reader034.fdocuments.us/reader034/viewer/2022051322/545aee7cb1af9fcf338b5f85/html5/thumbnails/93.jpg)
Two weeks pass...
![Page 94: Javascript spaghetti stirtrek_5_17](https://reader034.fdocuments.us/reader034/viewer/2022051322/545aee7cb1af9fcf338b5f85/html5/thumbnails/94.jpg)
I’ve got a new
feature
![Page 95: Javascript spaghetti stirtrek_5_17](https://reader034.fdocuments.us/reader034/viewer/2022051322/545aee7cb1af9fcf338b5f85/html5/thumbnails/95.jpg)
No worries.
![Page 96: Javascript spaghetti stirtrek_5_17](https://reader034.fdocuments.us/reader034/viewer/2022051322/545aee7cb1af9fcf338b5f85/html5/thumbnails/96.jpg)
Wha? Ohhhk.
![Page 97: Javascript spaghetti stirtrek_5_17](https://reader034.fdocuments.us/reader034/viewer/2022051322/545aee7cb1af9fcf338b5f85/html5/thumbnails/97.jpg)
A short time later...
![Page 98: Javascript spaghetti stirtrek_5_17](https://reader034.fdocuments.us/reader034/viewer/2022051322/545aee7cb1af9fcf338b5f85/html5/thumbnails/98.jpg)
![Page 99: Javascript spaghetti stirtrek_5_17](https://reader034.fdocuments.us/reader034/viewer/2022051322/545aee7cb1af9fcf338b5f85/html5/thumbnails/99.jpg)
Examples
![Page 100: Javascript spaghetti stirtrek_5_17](https://reader034.fdocuments.us/reader034/viewer/2022051322/545aee7cb1af9fcf338b5f85/html5/thumbnails/100.jpg)
Questions?
![Page 101: Javascript spaghetti stirtrek_5_17](https://reader034.fdocuments.us/reader034/viewer/2022051322/545aee7cb1af9fcf338b5f85/html5/thumbnails/101.jpg)
Special thanks to
He did the frame art
Blame me for
everything else