real world single page app - a knockout case study
DESCRIPTION
This presentation explores lessons learned from building a highly complex single page application that's used by 100's of automotive dealerships to finance and sell cars. We’ll walk through how to manage a pure client-side application with 1000’s of lines of custom JavaScript and review how Web API, Knockout, Durandal, RequireJS, KendoUI, and surprisingly little jQuery can join forces to make the browser sing. You’ll gain a clear understanding of when a single page app approach makes sense and learn how to pragmatically divide responsibilities between the client and server. This session will give you an appreciation for how far you can push ultra-responsive client-side rendering in the real-world.TRANSCRIPT
![Page 1: Real World Single Page App - A Knockout Case Study](https://reader035.vdocuments.net/reader035/viewer/2022070302/5470887bb4af9fae0a8b4786/html5/thumbnails/1.jpg)
REAL WORLD SPAA Knockout Case Study
Cory House @housecor
.com
![Page 2: Real World Single Page App - A Knockout Case Study](https://reader035.vdocuments.net/reader035/viewer/2022070302/5470887bb4af9fae0a8b4786/html5/thumbnails/2.jpg)
Learn From My Mistakes
![Page 3: Real World Single Page App - A Knockout Case Study](https://reader035.vdocuments.net/reader035/viewer/2022070302/5470887bb4af9fae0a8b4786/html5/thumbnails/3.jpg)
Knowledge Survey
Have you built a SPA?
Know Ember, Angular, Backbone?
Worked with Knockout, Durandal, Require, Fiddler, AJAX?
![Page 4: Real World Single Page App - A Knockout Case Study](https://reader035.vdocuments.net/reader035/viewer/2022070302/5470887bb4af9fae0a8b4786/html5/thumbnails/4.jpg)
Here’s the Focus1. App walk-through
2. 10 Lessons Learned
3. Does this even make sense?
![Page 5: Real World Single Page App - A Knockout Case Study](https://reader035.vdocuments.net/reader035/viewer/2022070302/5470887bb4af9fae0a8b4786/html5/thumbnails/5.jpg)
What monthly payment would you
like?
![Page 6: Real World Single Page App - A Knockout Case Study](https://reader035.vdocuments.net/reader035/viewer/2022070302/5470887bb4af9fae0a8b4786/html5/thumbnails/6.jpg)
App Demo
![Page 7: Real World Single Page App - A Knockout Case Study](https://reader035.vdocuments.net/reader035/viewer/2022070302/5470887bb4af9fae0a8b4786/html5/thumbnails/7.jpg)
New App: Two Goals
1. Cross Platform
2. Speed
![Page 8: Real World Single Page App - A Knockout Case Study](https://reader035.vdocuments.net/reader035/viewer/2022070302/5470887bb4af9fae0a8b4786/html5/thumbnails/8.jpg)
10Lessons Learned
![Page 9: Real World Single Page App - A Knockout Case Study](https://reader035.vdocuments.net/reader035/viewer/2022070302/5470887bb4af9fae0a8b4786/html5/thumbnails/9.jpg)
1Decisions are Hard.And we were wrong. A lot.
![Page 10: Real World Single Page App - A Knockout Case Study](https://reader035.vdocuments.net/reader035/viewer/2022070302/5470887bb4af9fae0a8b4786/html5/thumbnails/10.jpg)
Sea of Decisions
![Page 11: Real World Single Page App - A Knockout Case Study](https://reader035.vdocuments.net/reader035/viewer/2022070302/5470887bb4af9fae0a8b4786/html5/thumbnails/11.jpg)
but…
![Page 12: Real World Single Page App - A Knockout Case Study](https://reader035.vdocuments.net/reader035/viewer/2022070302/5470887bb4af9fae0a8b4786/html5/thumbnails/12.jpg)
![Page 13: Real World Single Page App - A Knockout Case Study](https://reader035.vdocuments.net/reader035/viewer/2022070302/5470887bb4af9fae0a8b4786/html5/thumbnails/13.jpg)
LightUnopinionatedLibrary
RichOpinionatedFramework
![Page 14: Real World Single Page App - A Knockout Case Study](https://reader035.vdocuments.net/reader035/viewer/2022070302/5470887bb4af9fae0a8b4786/html5/thumbnails/14.jpg)
LightUnopinionatedLibrary
RichOpinionatedFramework
![Page 15: Real World Single Page App - A Knockout Case Study](https://reader035.vdocuments.net/reader035/viewer/2022070302/5470887bb4af9fae0a8b4786/html5/thumbnails/15.jpg)
Pick a Language?!
![Page 16: Real World Single Page App - A Knockout Case Study](https://reader035.vdocuments.net/reader035/viewer/2022070302/5470887bb4af9fae0a8b4786/html5/thumbnails/16.jpg)
Service Layer
WebAPI
![Page 17: Real World Single Page App - A Knockout Case Study](https://reader035.vdocuments.net/reader035/viewer/2022070302/5470887bb4af9fae0a8b4786/html5/thumbnails/17.jpg)
And Pick a Promise Library…
Q RSVP
Bluebird jQuery
![Page 18: Real World Single Page App - A Knockout Case Study](https://reader035.vdocuments.net/reader035/viewer/2022070302/5470887bb4af9fae0a8b4786/html5/thumbnails/18.jpg)
And a Testing Framework…
![Page 19: Real World Single Page App - A Knockout Case Study](https://reader035.vdocuments.net/reader035/viewer/2022070302/5470887bb4af9fae0a8b4786/html5/thumbnails/19.jpg)
Utility Libraries
![Page 20: Real World Single Page App - A Knockout Case Study](https://reader035.vdocuments.net/reader035/viewer/2022070302/5470887bb4af9fae0a8b4786/html5/thumbnails/20.jpg)
Data
![Page 21: Real World Single Page App - A Knockout Case Study](https://reader035.vdocuments.net/reader035/viewer/2022070302/5470887bb4af9fae0a8b4786/html5/thumbnails/21.jpg)
Network TransportAJAX
Go 2-way:
WebSocket
AJAX Long-polling
Adobe® Flash® Socket
AJAX multipart streaming
Forever Iframe
JSONP Polling
Or punt:
![Page 22: Real World Single Page App - A Knockout Case Study](https://reader035.vdocuments.net/reader035/viewer/2022070302/5470887bb4af9fae0a8b4786/html5/thumbnails/22.jpg)
NoSQL?
![Page 23: Real World Single Page App - A Knockout Case Study](https://reader035.vdocuments.net/reader035/viewer/2022070302/5470887bb4af9fae0a8b4786/html5/thumbnails/23.jpg)
2Unobtrusive JSDead?
![Page 24: Real World Single Page App - A Knockout Case Study](https://reader035.vdocuments.net/reader035/viewer/2022070302/5470887bb4af9fae0a8b4786/html5/thumbnails/24.jpg)
Inline Unobtrusive
Databinding
1999 2007 2013
![Page 25: Real World Single Page App - A Knockout Case Study](https://reader035.vdocuments.net/reader035/viewer/2022070302/5470887bb4af9fae0a8b4786/html5/thumbnails/25.jpg)
Unobtrusive JavaScript Movement: Dead?
1999 Inline
2007 Unobtrusive
Knockout
Angular
2013 Databinding
![Page 26: Real World Single Page App - A Knockout Case Study](https://reader035.vdocuments.net/reader035/viewer/2022070302/5470887bb4af9fae0a8b4786/html5/thumbnails/26.jpg)
Databinding Advantages
Discoverability
Clarity
Less Code
![Page 27: Real World Single Page App - A Knockout Case Study](https://reader035.vdocuments.net/reader035/viewer/2022070302/5470887bb4af9fae0a8b4786/html5/thumbnails/27.jpg)
Consider the Maintenance Programmer
Physically separating concerns that are logically intertwined without an explicit interface obfuscates rather than aids understanding.
![Page 28: Real World Single Page App - A Knockout Case Study](https://reader035.vdocuments.net/reader035/viewer/2022070302/5470887bb4af9fae0a8b4786/html5/thumbnails/28.jpg)
3Bundle & MinifyMaybe not?
![Page 29: Real World Single Page App - A Knockout Case Study](https://reader035.vdocuments.net/reader035/viewer/2022070302/5470887bb4af9fae0a8b4786/html5/thumbnails/29.jpg)
Heavy Load
93 JS
19 HTML
5 CSS
11 Images
----------------
132 HTTP requests?!
![Page 30: Real World Single Page App - A Knockout Case Study](https://reader035.vdocuments.net/reader035/viewer/2022070302/5470887bb4af9fae0a8b4786/html5/thumbnails/30.jpg)
The Full SPA
93 JS files
53 viewmodels
9 libraries
39 Popup windows
56 HTML files
94 RESTful endpoints
![Page 31: Real World Single Page App - A Knockout Case Study](https://reader035.vdocuments.net/reader035/viewer/2022070302/5470887bb4af9fae0a8b4786/html5/thumbnails/31.jpg)
Why Minify and Bundle?
1. Reduce HTTP requests to reduce load on server
2. Speed page load
3. Obfuscate code
![Page 32: Real World Single Page App - A Knockout Case Study](https://reader035.vdocuments.net/reader035/viewer/2022070302/5470887bb4af9fae0a8b4786/html5/thumbnails/32.jpg)
Why Not Minify and Bundle?
1. Prod no longer matches dev
2. Risk of introducing obscure bugs
3. Debugging in prod is more complex
4. Complexity (and thus risk) must be justified
![Page 33: Real World Single Page App - A Knockout Case Study](https://reader035.vdocuments.net/reader035/viewer/2022070302/5470887bb4af9fae0a8b4786/html5/thumbnails/33.jpg)
How’s Performance? It Depends.
Chrome IE8
Empty cache 6 13
Warm cache 3 3
Load first deal 1 2
Load second deal 1 2
Recalculate payment
1 2
To nearest second
![Page 34: Real World Single Page App - A Knockout Case Study](https://reader035.vdocuments.net/reader035/viewer/2022070302/5470887bb4af9fae0a8b4786/html5/thumbnails/34.jpg)
4We’re blind to errors!That’s malpractice.
![Page 35: Real World Single Page App - A Knockout Case Study](https://reader035.vdocuments.net/reader035/viewer/2022070302/5470887bb4af9fae0a8b4786/html5/thumbnails/35.jpg)
![Page 36: Real World Single Page App - A Knockout Case Study](https://reader035.vdocuments.net/reader035/viewer/2022070302/5470887bb4af9fae0a8b4786/html5/thumbnails/36.jpg)
‘Twas Blind, but Now I See…
![Page 37: Real World Single Page App - A Knockout Case Study](https://reader035.vdocuments.net/reader035/viewer/2022070302/5470887bb4af9fae0a8b4786/html5/thumbnails/37.jpg)
5Fast in Chrome?Meaningless.
![Page 38: Real World Single Page App - A Knockout Case Study](https://reader035.vdocuments.net/reader035/viewer/2022070302/5470887bb4af9fae0a8b4786/html5/thumbnails/38.jpg)
Old IE, The Laggard
10x slower 5x slower
![Page 39: Real World Single Page App - A Knockout Case Study](https://reader035.vdocuments.net/reader035/viewer/2022070302/5470887bb4af9fae0a8b4786/html5/thumbnails/39.jpg)
In memory? No problem.
In a table? Uh oh.
1000 rows…
![Page 40: Real World Single Page App - A Knockout Case Study](https://reader035.vdocuments.net/reader035/viewer/2022070302/5470887bb4af9fae0a8b4786/html5/thumbnails/40.jpg)
DOM Weight
Traditional
Duplicate elements rendered
Client-side
Single template
![Page 41: Real World Single Page App - A Knockout Case Study](https://reader035.vdocuments.net/reader035/viewer/2022070302/5470887bb4af9fae0a8b4786/html5/thumbnails/41.jpg)
Cross Browser Testing
Many options: http://bit.ly/16cXevo
XP-More
![Page 42: Real World Single Page App - A Knockout Case Study](https://reader035.vdocuments.net/reader035/viewer/2022070302/5470887bb4af9fae0a8b4786/html5/thumbnails/42.jpg)
6Unix or Windows Mindset?No right answer.
![Page 43: Real World Single Page App - A Knockout Case Study](https://reader035.vdocuments.net/reader035/viewer/2022070302/5470887bb4af9fae0a8b4786/html5/thumbnails/43.jpg)
Our Tech Stack
![Page 44: Real World Single Page App - A Knockout Case Study](https://reader035.vdocuments.net/reader035/viewer/2022070302/5470887bb4af9fae0a8b4786/html5/thumbnails/44.jpg)
WebAPIORMLiteMSTest
KnockoutJS
Durandal
RequireJS
KendoUIKnockout.Mapping & Knockout-
KendoToastr
jQuery Q.js QUnit
Our Stack
![Page 45: Real World Single Page App - A Knockout Case Study](https://reader035.vdocuments.net/reader035/viewer/2022070302/5470887bb4af9fae0a8b4786/html5/thumbnails/45.jpg)
Why Use Knockoutwith Durandal?
14% of our customers :_(
![Page 46: Real World Single Page App - A Knockout Case Study](https://reader035.vdocuments.net/reader035/viewer/2022070302/5470887bb4af9fae0a8b4786/html5/thumbnails/46.jpg)
1. Convention
2. Composition
<div data-bind=“compose: ‘viewmodels/vehicle’></div><!-- ko compose: ‘viewmodels/vehicle’ --><!-- /ko -->
3. Routing
![Page 47: Real World Single Page App - A Knockout Case Study](https://reader035.vdocuments.net/reader035/viewer/2022070302/5470887bb4af9fae0a8b4786/html5/thumbnails/47.jpg)
A Torrid Love Affair…
![Page 48: Real World Single Page App - A Knockout Case Study](https://reader035.vdocuments.net/reader035/viewer/2022070302/5470887bb4af9fae0a8b4786/html5/thumbnails/48.jpg)
![Page 49: Real World Single Page App - A Knockout Case Study](https://reader035.vdocuments.net/reader035/viewer/2022070302/5470887bb4af9fae0a8b4786/html5/thumbnails/49.jpg)
![Page 50: Real World Single Page App - A Knockout Case Study](https://reader035.vdocuments.net/reader035/viewer/2022070302/5470887bb4af9fae0a8b4786/html5/thumbnails/50.jpg)
![Page 51: Real World Single Page App - A Knockout Case Study](https://reader035.vdocuments.net/reader035/viewer/2022070302/5470887bb4af9fae0a8b4786/html5/thumbnails/51.jpg)
WebAPIORMLiteMSTest
KnockoutJS
Durandal
RequireJS
KendoUIKnockout.Mapping & Knockout-
KendoToastr
jQuery Q.js QUnit
Our Stack
![Page 52: Real World Single Page App - A Knockout Case Study](https://reader035.vdocuments.net/reader035/viewer/2022070302/5470887bb4af9fae0a8b4786/html5/thumbnails/52.jpg)
WebAPIORMLiteMSTest
AngularJS
KendoUI
If We Used AngularJS instead…
![Page 53: Real World Single Page App - A Knockout Case Study](https://reader035.vdocuments.net/reader035/viewer/2022070302/5470887bb4af9fae0a8b4786/html5/thumbnails/53.jpg)
7TypeScript or TestOr refactor at your own risk
![Page 54: Real World Single Page App - A Knockout Case Study](https://reader035.vdocuments.net/reader035/viewer/2022070302/5470887bb4af9fae0a8b4786/html5/thumbnails/54.jpg)
My Awesome JS Refactoring Tool
![Page 55: Real World Single Page App - A Knockout Case Study](https://reader035.vdocuments.net/reader035/viewer/2022070302/5470887bb4af9fae0a8b4786/html5/thumbnails/55.jpg)
And a Testing Framework…
![Page 56: Real World Single Page App - A Knockout Case Study](https://reader035.vdocuments.net/reader035/viewer/2022070302/5470887bb4af9fae0a8b4786/html5/thumbnails/56.jpg)
What I’m testing:Service endpointsBusiness logicThat the data displays (implied)
![Page 57: Real World Single Page App - A Knockout Case Study](https://reader035.vdocuments.net/reader035/viewer/2022070302/5470887bb4af9fae0a8b4786/html5/thumbnails/57.jpg)
8Architect Your JS like C#.DAL, BLL, Presentation…
![Page 58: Real World Single Page App - A Knockout Case Study](https://reader035.vdocuments.net/reader035/viewer/2022070302/5470887bb4af9fae0a8b4786/html5/thumbnails/58.jpg)
Create a Client-Side “DAL”
JSON.stringify
Centralized service layer
Single wrapper around $.ajax
View
ViewModel
Service
AJAX service
![Page 59: Real World Single Page App - A Knockout Case Study](https://reader035.vdocuments.net/reader035/viewer/2022070302/5470887bb4af9fae0a8b4786/html5/thumbnails/59.jpg)
Keep Your Viewmodels Thin
Create Business objects!
Instantiate them in your viewmodels
A 1,000+ line viewmodel is as smelly as a 1,000 class.
![Page 60: Real World Single Page App - A Knockout Case Study](https://reader035.vdocuments.net/reader035/viewer/2022070302/5470887bb4af9fae0a8b4786/html5/thumbnails/60.jpg)
Avoid here.
Where Should I Put the Business Logic?
Prefer Here
![Page 61: Real World Single Page App - A Knockout Case Study](https://reader035.vdocuments.net/reader035/viewer/2022070302/5470887bb4af9fae0a8b4786/html5/thumbnails/61.jpg)
9Config Object PatternDynamism belongs in JSON
![Page 62: Real World Single Page App - A Knockout Case Study](https://reader035.vdocuments.net/reader035/viewer/2022070302/5470887bb4af9fae0a8b4786/html5/thumbnails/62.jpg)
JavaScript Configuration Object PatternJavaScript belongs in static .js files
Not strings in C#, Java, etc.
1 language per file
Inject dynamism via JSON from the server.
![Page 63: Real World Single Page App - A Knockout Case Study](https://reader035.vdocuments.net/reader035/viewer/2022070302/5470887bb4af9fae0a8b4786/html5/thumbnails/63.jpg)
JavaScript Configuration Object Pattern
![Page 64: Real World Single Page App - A Knockout Case Study](https://reader035.vdocuments.net/reader035/viewer/2022070302/5470887bb4af9fae0a8b4786/html5/thumbnails/64.jpg)
Config Object Pattern: A JustificationSeparation of concerns
Caching
Minimizes string parsing overhead
Code coloring
Syntax checking
Reusable
Reduced payload
Less abstraction
bitnative.com/2013/10/06/javascript-configuration-object-pattern/
![Page 65: Real World Single Page App - A Knockout Case Study](https://reader035.vdocuments.net/reader035/viewer/2022070302/5470887bb4af9fae0a8b4786/html5/thumbnails/65.jpg)
1 Manage DependenciesKeep the global namespace clear.0
![Page 66: Real World Single Page App - A Knockout Case Study](https://reader035.vdocuments.net/reader035/viewer/2022070302/5470887bb4af9fae0a8b4786/html5/thumbnails/66.jpg)
RequireJS
Utilizes AMD pattern
Dynamically load JS
Inject dependencies
Watch for circular dependencies
![Page 67: Real World Single Page App - A Knockout Case Study](https://reader035.vdocuments.net/reader035/viewer/2022070302/5470887bb4af9fae0a8b4786/html5/thumbnails/67.jpg)
1Stay DRYDon’t repeat viewmodels on server & client1
![Page 68: Real World Single Page App - A Knockout Case Study](https://reader035.vdocuments.net/reader035/viewer/2022070302/5470887bb4af9fae0a8b4786/html5/thumbnails/68.jpg)
var firstName = ko.observable(user.firstName);
var middleName = ko.observable(user.middleName);
var lastName = ko.observable(user.lastName);
…
Instead:
var user = ko.mapping.fromJS(user);
![Page 69: Real World Single Page App - A Knockout Case Study](https://reader035.vdocuments.net/reader035/viewer/2022070302/5470887bb4af9fae0a8b4786/html5/thumbnails/69.jpg)
How Do I Stay DRY?
Use KO mapping plugin
Inject nullos via the Configuration Object Pattern
Ko.utils.
![Page 70: Real World Single Page App - A Knockout Case Study](https://reader035.vdocuments.net/reader035/viewer/2022070302/5470887bb4af9fae0a8b4786/html5/thumbnails/70.jpg)
Does This Even Make Sense?
![Page 71: Real World Single Page App - A Knockout Case Study](https://reader035.vdocuments.net/reader035/viewer/2022070302/5470887bb4af9fae0a8b4786/html5/thumbnails/71.jpg)
Why not?
Proprietary business logic
Low interactivity
Slower page load
Page is rarely called
Complex – Too many choices!
Debugging pain Runtime errors Cryptic One mistake and nothing loads
![Page 72: Real World Single Page App - A Knockout Case Study](https://reader035.vdocuments.net/reader035/viewer/2022070302/5470887bb4af9fae0a8b4786/html5/thumbnails/72.jpg)
Why?
Responsive
Rich Interactivity
Separation of concerns
Efficient
Simple - Less abstraction Debugging No compile wait
Faster page load
![Page 73: Real World Single Page App - A Knockout Case Study](https://reader035.vdocuments.net/reader035/viewer/2022070302/5470887bb4af9fae0a8b4786/html5/thumbnails/73.jpg)
![Page 74: Real World Single Page App - A Knockout Case Study](https://reader035.vdocuments.net/reader035/viewer/2022070302/5470887bb4af9fae0a8b4786/html5/thumbnails/74.jpg)
SPA Experience Complete
Cory House
bitnative.com
@housecor
spkr8.com/t/35431