Real World Single Page Apps: A Knockout Case Study
CC Attribution - NonCommercial - ShareAlike 3.0 Unported:
You are free to use, adapt and copy, distribute and transmit the work or content in adapted or unchanged form for any legal and non-commercial purpose as long as the work is attributed to the author in the manner specified by the author or licensor and the work or content is shared also in adapted form only under the conditions of this
House, Cory
Typical technology sessions walk through a trivial example application to give you a taste of the technology. So hey, let’s do the opposite! In this session we’ll dissect a highly complex single page application that's soon to be used by over 1,000 automotive dealerships to finance and sell cars. This is an HTML5 application that our Silverlight guys said couldn’t be built. 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. And we’ll close out by comparing the performance of complex web apps in modern browsers to older versions of Internet Explorer. This session will give you an appreciation for how far you can push ultra-responsive client-side rendering in the real-world.
 We're good? Excellent. Let me hit play here. Good afternoon. This is real-world spa, a knockout case study. This session really shouldn't have the word knockout anymore in it, because we're going to talk about a lot of things outside of knockout. So if you're coming in here expecting an introduction to knockout, that's not my focus here. What we're going to do is talk about a lot of lessons learned from the biggest single-page application that I've ever built. This is about eight months to a year worth of work that we launched just a few months ago. A lot of the lessons learned will hopefully be useful for you too. I'm using what we're talking about here is really the foundation for my next course, just thinking about patterns, practices, and principles for single-page app development. My clicker will work better if I plug it in. Let's try that. All right. So I want to get to know you and make sure that I'm delivering what's most useful for everybody. How many people in here have already built a single-page app? Okay. So we got about half the room of built a single-page app. How many people have done significant work in JavaScript to build web applications? So quite a few more hands there. That's the vast majority of the room. Cool. How many know Ember right now? Very few. Okay. Gil got it covered. How about Angular? A lot of hands there. Backbone? Okay. Just a few. How about knockout? Okay. So good. You weren't coming in here wanting an introduction anyway. You've already familiar with knockout. Great. Anyone worked with Durandal? Just a few hands. Okay. Required JS? Okay. Probably few enough. We may talk a little bit about that too. Anybody ever heard of Ajax before? You don't even bother raising your hands. Yes. Okay. Good deal. So here's the things that we can focus on and we're going to get through as much of this as we can. There is a sea of decisions in making a single-page application and that's maybe the hardest part is making those decisions. I spent weeks and weeks and lots of reading and ultimately even made maybe the wrong decision. We'll get to that in a minute. I want to demo the application that we built and I want to show you the code so you can tell me that it's rubbish and why and that'll be just fine. But we'll all get better along the way. I want to discuss the tech stack that we picked and the performance implications of that stack and if you're interested I can also show you the stack and how it runs in older browsers like IE8 because it's interesting comparing that to Chrome. You can literally feel the difference of an older browser. It still works but it does not feel as snappy. And then I want to close with two things. I want to close with talking about principles for writing single-page apps. A lot of lessons learned from building something this big. And then finally talking about whether building a spa even makes sense because there are places where it does and doesn't. So let's dive in. I want to talk first about the sea of decisions because this is maybe the hardest part about it. Now I love jQuery and how many people in here coded in jQuery? A whole lot of handy. There we go. Hello, Room. Great. jQuery is really useful and has helped move us forward in a lot of ways. Thank you, John Rezeg, for making that happen. Now the problem with jQuery is it really is only solving a piece of the puzzle. Manipulating the DOM is really useful. Making Ajax calls easier is useful but there's a lot more that we need to get done for single-page apps and that's what these sorts of options try to solve for you. In this course or in this session today we're going to talk about knockout and derandal, the one at the top here. But these are your other logical options and these days more and more we're seeing anglers sneaking closer and closer to becoming just the de facto standard here. It's ridiculous how much power that it has here recently in inertia along the way. Ultimately these are all great options but I'll get into maybe some specific reasons that I feel like anglers getting so much traction in this. But the app that we're going to look at is built with these technologies at the top. Of course you have to pick a language which is strange. You'd think by default it's JavaScript but if you're somebody that's into C sharp or VB.net then maybe TypeScript sounds interesting. Or if you're a Ruby developer then you probably like CoffeeScript. Or if you're someone I've never met then you probably like Dart. Is anyone using Dart? It's silence. Yeah, I don't know. Google, this is something that Google tried that just doesn't seem to be catching on. You have to choose how you're going to return all that JSON to your application. We went with just good old web API. It's nice and simple. So we're writing C sharp on the server and just returning JSON over web API. Node.js is another popular way to do this and I could list on and on here. But this was another decision we had to make. We had to pick a promise library because if you're using knockout and derandal that doesn't come out of the box. We could have used jQuery. I don't recommend using jQuery because jQuery does not honor the promises spec. And because of that there's some weirdness in there. You're really better off choosing one of these other three. We went with Q and have been quite happy with it. If you want to do testing you're going to need a framework for that too. And GIL did a talk about Jasmine. Just anybody go to GIL's talk on Jasmine? So quite a few hands. Okay, I figured that would be the case. So I happened to choose Q unit. I've been pretty happy with it. From all that I've read though, Jasmine is probably a better choice. Q unit, the advantages. The learning curve is really low. It was actually created by John Rezeg to test jQuery. Hence the name Q unit. But it's really easy to pick up and it's a good start. You'll probably want some kind of a utility library to make JavaScript feel a little bit more like a big grown up server side language. And that's what these seek to do. You can, if you're familiar with C sharp, you can do things that feel a bit like link statements within the realm of these utility libraries. Hi, Steve. I just saw you over there and now I'm all excited. Sorry, I got Steve wrote a knockout. Am I right? Started the project. Okay, yeah. So smart guy over there. I've just got to say hi. He made a lot of this possible. Data access. We've got another decision to make. Amplify, breeze. These are two ways to do it. I didn't end up getting this sold to my manager because if I were to describe breeze to you right now, I would say breeze is a way to basically expose your database over a RESTful API. Boy, that sounds convenient and it doesn't sound very secure, does it? So I can't really figure out by the time you've done the work to secure all the edge cases that would happen from effectively just making a RESTful API call to your database. I don't understand. Anybody in here worked with breeze? Is my description accurate? No opinions. Okay, we'll move on. Network transport. Another decision that you have to make. We're using plain old Ajax calls because ultimately there's very little that we need to do that is truly real time. We didn't need server side push than anything that I'm doing. But if you're going that route, then of course you can just Ajax long polling is a really simple way to go or just making call every so often. Basically down here at the bottom of the screen, these are options that abstract away all of this confusion. If you choose to use signal R, then signal R is ultimately using one of these things up here for you and you don't know that it's doing it. You just trust it and it works, which is pretty cool. So a lot of ways that you don't have to deal with that complexity. Of course you need to persist your data somewhere. We didn't do anything flashy. We went with SQL server and we have a pretty complex data model. We're doing a lot of joins. We're using caching so that it's not a big deal to pull all this back and spit it out in this right shape for our JSON. So that's been working out well. Then of course you need to do cross browser testing. I'm going to look at browser stack and show you guys how we're doing cross browser testing with it. Browser stack is really cool and it saved us a lot of time from dealing with virtual machines. If you aren't familiar with it, this modern IE, this link here, which I guess you'll have to download the slides to see the link. Modern IE is a Microsoft initiative that has old versions of IE, virtual machines that you can download and they'll work in a number of different VM platforms. All right, so that's the introduction. Let's get a little bit geekier and talk about an app demo. Here was the situation. I work in automotive software and we had a Silverlight application that car salesmen were using and it was getting a little long in the tooth for a number of reasons. For one thing, people are now wanting to be out at car dealerships with tablets, with iPhones and be able to do their work and Silverlight is a non-starter on those platforms. Now I don't know much about the automotive industry around here. Do you still have dealerships that hold inventory of cars? Is that an idea here? Okay, because I know that's not worldwide. The reason I ask that too is the big idea of our application is this. So here's Vinny, my friend, the car salesman. He's a nice guy, questionable taste in clothes, but otherwise, nice guy. Vinny, you sit down at his desk and you're going to talk about buying a car. Maybe you found this Ford Focus and it's just really exciting. When you sit down at his desk, that is called desking. That's salesman jargon and what you're doing there is talking about the bottom line. How much are you going to pay for that car? What payments will you make? What's your interest rate? What bank will you go through? How can I upsell you on a bunch of different options? Car salesman need a piece of software to make this happen. That piece of software is called desking and that's what I'm going to show you. We built a single-page application to help make Vinny be more successful. So I'm going to jump over here to the app itself and make sure I'm logged in. I'll jump back in here. One thing that you do see is the rest of this application is not a single-page app. What I'm showing you here is one of the few places in the entire application that is a spa. You're also going to notice that because of our Wi-Fi, it's going to be pretty painfully slow to load. I'll get into also some reasons why. This app has almost 100 JavaScript files, separate files that contain the logic to perform what's going on on the screen. It has about 95 different HTML files. Has a huge portion of CSS to make it all happen too. So let's do this. Imagine you're coming in and you're going to buy a new car and I'm going to name this deal. Maybe I'm trying to sell you a Ford Focus. I'll just name it that. That's fine. And you're considering purchasing it new. So that's the template. I'm not even going to add a vehicle, but I could go in and search inventory if I wanted to. So I'll go ahead and just create the deal. And you're going to see this all pop up. Now we designed this to fit on 1024-Wide. You can see it just squeezes in at the current res here. So now we're seeing a deal and you can see I'm trying to decide between doing a purchase, that's the P, and a lease here. So let's say for instance that I'm trying to decide on a down payment. Well, I tell you what, I'm going to add a car in. Well I'll do this instead. I'm going to pull up a previous deal so that you don't have to wait for me to do all this stuff. Just show you how it is all together. All right. So this person is thinking about buying a 2006 Mercury Milan right here. And there's the picture of it. We can see it has 65,000 miles and it's selling for $9,900. And they're considering a cash deal in this case, but most people these days end up purchasing a car and making payments on it. And they're considering maybe a $1,000 down payment or a $2,000 down payment or $3,000 down payment. Notice how as I'm typing these things in, it's making Ajax calls to the server and you're seeing payments calculate immediately. Maybe I can get him a 4.5% interest rate at 60 months. Now I'm going to tab out. And again, you just see little toast pop up on the right hand side of the screen that's showing things that have changed. And now we have down payments of $1,000, $2,000, or $3,000. And these are the monthly payments that someone would make based on that. Now imagine you're sitting there and we're having a conversation and you go, I can't afford $173 a month. And I go, OK, well that's fine. What can you afford? Let me click this roll button here. Well I could afford $125 a month. That I can do. So I'll go ahead and click roll. And what it's doing is making calculations and figuring out what numbers could I change to get you to that down payment because we want to pay $125 a month. Well I could lower the selling price. I could increase my down payment. I could get more for my trade in. Or I could pay for 88 months instead of for 60 months. Well, like most Americans, I just want to pay longer. So that's what I'm going to do. We're fine with going into debt, into perpetuity here. So I clicked that and now what happened was, note my payment right here. Now it's $124. So it changed the payment accordingly. It came down here and set the monthly term just like we'd like. Now I could go into a whole lot more that this thing does and I could open up all sorts of dialogues and open other things, lots of jargon, but I don't want to bore you with the application. I want to show you this enough so that you can understand some of the things that we ran up against. The first takeaway that you have here is when I change one value here, if I change this to 5.9%, pay attention to the math on the left hand side of the screen in this gray box here. I'm going to tab out and you'll notice that the balance due will change. Well I'm sorry, no, that's not a good example. I'm going to change this, change my purchase price, $12,000. Now when I do, all this math down here changes. All the payments over here change. So at any given time, there are 10, 20, 30 different DOM elements that have to change when one thing changes. So this is when I had the epiphany that the old school model of using jQuery to manipulate DOM elements really falls apart. Because if you're using jQuery to say, okay, when that cell changes, change this cell, this cell, this cell, this cell, this cell, I can't do it, it falls apart. Imagine maintaining that thing because when I change that cell, these 14 things change. When I change this cell in a different way, these 22 other things change. So what you need to be able to declare is say, I want this value right here bound to a certain piece of data back in the JavaScript. And that's exactly what's going on here. If I scroll this down some, you can see that I'm using knockout. And it's just a data bind formatted text to payment. In this case, it's called matrix payment because this is called a payment matrix over here. So this data dash bind is just saying, go get the JavaScript variable called matrix payment and put it in here. And formatted text is a custom binding that I wrote that formats the text the way that we would like it for this application. I can go in and do other things like copy this scenario over. I could create a new deal and maybe put that in for a different car or for the same car. I could go in and edit the vehicle. I can search for deals. All sorts of things going on. And again, I don't really want to focus too much on the app, but I want to show you enough that we can use it for a bit of conversation later. Does anybody want to look at code? Okay. Well, good. I was hoping I'd get a yes there. Otherwise, I was going to have a hole in my schedule. Yeah. All right. So let's talk about code. This is the folder structure. Is that big enough that you guys can see it on the TVs over there? Cool. This is the folder structure for it. I have left out the rest of the big huge app. This is just the single page app that we've built. The way I have this structured is we have custom bindings in a folder. Keep our CSS there. Our images is all self-explanatory. These are all the JavaScript libraries that we're using. As you can see, jQuery, we're using Kendo for a little bit of our UI. Of course, Knockout. We're using a few different Knockout plugins, and in particular, Knockout Mapping, which has been really helpful. I'll get to that. Of course, Q. And then Toaster. Toaster is a project by John Papa that is doing those little nice green confirmations that pop up in the corner and then fade out. That's a handy little add-in. That said, I could have used Durandal for that too, but I liked how Toaster did it. And then our services. You could think about the services section as really this is where all our Ajax calls sit. They're in one folder called services. So anytime I'm going to make a call to the server so that I can ultimately hit the database, make changes, get back to JSON, it's going to happen through JavaScript within this folder. You could see that we've broken it down. I say that, but there's a few things in here that aren't dealing directly with any kind of Ajax call type work. Like cookies is just a service that I wrote that abstracts away the browser cookies and gives us a little cleaner API to work with. And then local storage, the same thing. It's a little service that lets me work with local storage in a way that's useful for us and then a little math library, those sorts of things. So down here is the real meat and potatoes, the views and the view models. Oh, and I skipped over tests, this single file has our test. These are Q unit tests. I'll get into Q unit if we have time. I don't know if we will, but all of our tests currently just sit in this one file. So let's look at views and view models. Who here is familiar with MVC? Probably a lot of hands. Okay, so in MVC we have, especially in ASP.NET MVC, there's this idea of convention over configuration and we're saying by convention I have this view called user.html and then we have this corresponding view model sitting over here and those two get bound together because they have the same name. They sit in the same corresponding directory structure. That's the way Durandal works. It's the same thing. Durandal gives you conventions on top of knockout, which is pretty cool. That's both the benefit and the downside of knockout. The beauty of knockout is that it is just a library that solves a really particular problem and as someone who spent a lot of time in Unix, I get it. The power of Unix is being able to pipe all these commands together and I'll pipe this cat this file and pipe this to said, pipe that to awk and then grep for such and such and you get all this power by taking little tiny pieces, little tiny applications and using them together. That's what knockout allowed us to do because knockout solved the problem of binding and it does that really well. The thing that it doesn't do though is tell you where to structure your files and how to do so. That's what Durandal does for us. Let's jump into the heart of the application. I'm going to collapse this down. This is default.aspx. This is what loads initially. The first thing that's interesting about this is that this file is only 46 lines long. There's not much here to consume. I have, at the top, we'll just run through it. I have some references to CSS, not much to see here. Then we come down to the body and there's this. This piece is of interest. This is the wrapper that gets changed. You know how when I first loaded it, it said loading and you waited for it to load and then it went away? This is what Durandal replaces after it's pulled down all of your content. It ends up slapping all your content into the loading wrapper. It basically looks for an element with an ID loading wrapper that's sitting within application host which sits right up above. If you do Angular, Angular has a similar idea but you would say ngapp to be able to reference the app and then things within that get handled by Angular. Then we jump down to the bottom and you'll see all the scripts. You can see there's quite a few. Just probably nothing too surprising here. We have a tracker. We're using track.js which, by the way, if you're wanting to track JavaScript errors, track.js is a great service. A friend of mine, Todd, runs it. He's speaking here too. He's already spoken though so you missed it if hopefully you got to see him. Then ultimately down here at the bottom we have what? Knockout, queue and some simple libraries for handling dates and whatnot. The interesting thing is you're going, wait, that can't be all the JavaScript because I said there were 90-something files with a JavaScript that ultimately get used here and that's true. The real story is what's going on here on 44. We're using Require.js and a lot of people weren't familiar with it so let me go into that. The story with Require.js is you can download your JavaScript files on demand and you follow what's called the asynchronous module definition pattern which basically lets you say at the top of your file the other dependencies that your file has. A lot like a using statement. In C-sharp you'll say using this, using this, that's you saying, hey, go get these other resources and pull those in for me. Let's look at one example of a view model. Let me try to pick, okay, this one's massive. Let me pick one that's a little easier to digest. Okay, yeah, this one's pretty easy. This is the view model that is used for handling templates. If I jump over here to the UI so you know what templates are, it's over here in this accordion under Manage Templates. You can open up different templates and manage them. These are just quick ways to get started on a desk and people can set up a desk in different ways. This little area right here has its own view model. Ultimately, this has a view model, this has a view model, this has a view model, this has a view model. The big app and all the complexity, every single dialog box has its own view model. We've eaten the elephant a bite at a time. Back to RequireJS. This is an asynchronous module definition pattern. What RequireJS is saying is right here, I'm saying, okay, here are three. Three dependencies. These are three other files that this file needs to load. What RequireJS would do is when I made a call to this file, it would say, okay, go get these other dependencies and bring them into scope. I define what variables are used for these over here on the right. You'll notice, and if I formatted this better, you could read it better. This corresponds to this, the second, to the second, and the third to the third. I'm saying this is the variable name that you will use down below to reference those. The cool thing about RequireJS is on page load, I'm not having to pull in those 95 files. I pull in the JavaScript files that are necessary, and then as they're needed, RequireJS goes out and it makes the calls to get the others. That keeps your initial HTTP call as lightweight as possible. Let's go back to default. The way that all works is by convention, it takes a HTML5 data attribute called main, and then that forces it to come out here and look for a JavaScript file called main. In here, that's where I configure RequireJS. This is some stuff specific to Durandal, so I won't bore you with those details. The largest view model in this application is desk.js, probably not surprising. This is where the core of the logic sits. If you look at the number of dependencies on this one, it's high enough to be a little bit embarrassing for me. These are, as you can see, there are a lot of dialogue boxes in this application. We put all of those under slash windows. Then, of course, these are all the variable names that associate those things up above. The one thing I am proud of is this file is huge, but if I scroll down through it, what you see is there's a lot of, let me just do this. I'll collapse it all down. If I collapse down to just function names, you at least see that these are a lot of small, well-named methods because watch the line numbers on the left. This is something I do a lot when I open any kind of file. I like to collapse it down to definitions and then scroll through and just get a feel of the high level of what it does because you can read the function names and you can look at line numbers and go, I shouldn't see any huge jumps in line numbers. If I see a jump from line 1,000 to line 2,000, that's a bad sign because that means there's a thousand line method sitting there and there's a lot going on that I need to go understand and there's no good function name that's going to declare all that's going on inside. All right, so how big is this? These are the stats. It's a very heavy load. 93 JavaScript files, 19 separate HTML files, five CSS files and 11 images because we're using sprites, a spritesheet that really greatly reduces the number of images that we have to require for this. So that's 132 HTTP requests. That's pretty absurd. Is this malpractice? Is that too many? I feel like that's just silly. So for those that think it's silly, what is your recommendation to me to reduce this number? Bundling and minification, yes, and that's the very common answer. Now I am not bundling or minifying in this case and can anyone think of a reason why I shouldn't bother? Yes? Did you call me lazy? Because I'm lazy loading? That sounds much better. Thank you. We're going to go with the second hand. Yes, because I'm lazy loading and that is part of it. With RequireJS, if I bundle everything, RequireJS can't do its thing anymore and request them on demand. So that's one reason. Now the bigger reason is this. Remember, this whole app sits behind a login. The situation is a salesman comes in in the morning, grabs their coffee and they load this application and this will be the only application that they use all day. So whether this takes one second or three seconds, and by the way that's about the difference between these two in our case, doesn't matter because it's a couple seconds once a day. It's really small beans. So there's some other things that are really a downside to bundling and minification. Once you go to production, then all of a sudden your code in production doesn't mirror what you have on your local machine. There's ways to get around that, but it does add complexity. And I am all for keeping it simple if I can. And in our case, we can keep it simple and live with the fact that it doesn't exactly load like blue blazes. That said, this, let me, let's just see how fast it loads. 132 HTTP requests on conference Wi-Fi, hitting servers and, oh, we're done. So I wasn't done doing the description. We're hitting servers in the United States from the other side of the world. I can tell you this, when I demo it in the States, it is quite a bit faster. This, also, I think the Wi-Fi just seems a little slow today. So let's do it one, two, three, four, five. Yeah, that's pretty painful. This is a Republic app. I'd give it an F. But given our user base, this works okay. Now if I cleared cache and did this again, you'd see that number go way up. Because if I open up Fiddler, of course, and look at what's going on here and see all the requests come down, let's do that. So here it is spitting through them all. One by one. Got them all in. And, well, no. It's still working on it. In fact, it looks like we're getting... Oh, no, I guess it did all come down. Okay. Just a lot of things didn't have to get loaded because it was all cached. Okay. So let's jump back over here. The full single-page application, 53 view models, nine libraries, 39 pop-up windows, 56 HTML files, and 94 RESTful endpoints. There are a lot of service calls. And also, I should get into the REST side of things here. And let's see. I'll do that a little bit later. I want to save that some. One of the reasons that we had to choose a knockout with the Randall was because the great thing about knockout is you can use it all the way back to IE6. And for now, I haven't heard any changes on that front. I think that's staying for the foreseeable future at the moment. There's this real trend right now toward evergreen browsers. And this idea that we're only going to support browsers that auto-update. Now, the definition of auto-updating is a bit interesting, though, because IE10 auto-updates. But as far as I know, IE10 will not auto-update to 11. Is that true? Can anybody confirm that? I have not heard any confirmation that IE10 will ever move to 11. So IE10 is not an evergreen browser. And I don't know of any plans for IE11 to auto-rev to 12. Maybe that will be the first one that's truly evergreen. But that's what we need is this idea of people that are on the browser today will get the new version as soon as possible. That helps us really move this story of single-page applications forward. And that's important because IE8 is 10 times slower than modern browsers. And you can feel this. Does anybody want to see how this runs in IE8? Okay, I figured some people would be curious. This is a good time for me to show you BrowserStack. We're using BrowserStack to do cross-browser testing. Beauty of BrowserStack is you pay them a little bit of money, and then all of a sudden you have huge convenience. Let me show you what you get here. These are all the operating systems that I can test in. And even some mobile emulators. This for Windows XP, just Windows XP. Look at all the browsers I have to choose from. I can go all the way back to IE6. And then, of course, I get to select my resolution. Now I tend to spend most of my time testing in IE8 on Windows XP because sadly, 14% of our customers are still on IE8. 14% of them are still on 7, but I was at least able to sell management. The 14% on 7 cannot use this new app. I just did not want to go down that road of trying to support 7, too. There's a lot more pain going back to IE7. So this is firing up a virtual machine. And oh, I just remembered, I can't do that this way. Wait, wait, where did I go to? I think I pointed to the wrong... Give me just one second. I'm going to load back up. I think what I did was I pointed to... Yes, I did. I'm going to the wrong URL. That makes all the difference I found. It's getting the right URL for demos. There's a pro tip next time you speak. All right, so we're going to hit the proper prod URL here. And it does rely on Flash. It's a little bit slow because remember, it's spinning up a virtual machine just for you. And now... And so here's the mind bender is I'm hitting some machine somewhere in the world and the browser is showing all this to me basically using Flash. And it is very slow, especially on slow Wi-Fi like this. It's pretty painful to use. You really want a fast network to be able to use BrowserStack. And it feels especially slow when you're trying to demo for people. But you can automate tests with BrowserStack. So you want to write a bunch of tests and then integrate and make sure that your app runs properly in older browsers. Then you can write automated tests and just ship them all off and they'll run up. And you don't have to worry about exactly how long they take because it's all just automated and you're not standing around waiting. All right, so you're going to have to bear with me on the fact that... Let me try full screening here to get us a little more space. And it is loading right now. It's going to be... There we go. Okay, so we are in. By the way, there's a bug in their virtual machine. I should have pulled up the IE7 version instead, but this is a display issue that only happens in their virtual machine. It doesn't happen on real native items. And boy, does this look as awful to you as it does to me? Yeah, I think they're... And that's the thing. They will throttle down display quality as much as they have to based on your connection to get you something viewable. They can see that the Wi-Fi here is painfully slow. So let's do this. How long does it take to load a desk within this app? I will click this and one, two... So you can see... I'm going to tell you when I click. Click. Now in Chrome, it was instant. One, two... It was about two and a half seconds. Let's go over to Chrome and see how fast this is. One... One... Yes. One... I mean, so you can see Chrome is more or less instant. Even on slow connection as I load these. But over here on this VM, it's pretty painful. One, two... And a given, this is the combination of a slow VM and also running IE8, which has a much slower JavaScript rendering engine. Let's do something that ends up exercising the engine a bit more. This changes a whole bunch of DOM elements. So I'm going to say I want to roll to 225 and I'll end up setting the price here. So this is going to change all sorts of elements behind the scenes. And we'll go one, two... About two, two and a quarter seconds. So if you were using this all day, you'd probably go, oh, this is a little painful. So I'm hoping that the people that use it on IE8 complain about the speed and then I can say, well, hey, you have a free solution. Just go upgrade your browser, you know, or go download Chrome for free. Even if you have to have IE8, you could always have Chrome alongside it. There's nothing we can do about the fact that it is 10 times slower. So things that are instant in Chrome show up here. And this is, by the way, after doing a lot of work to improve the performance. But there's just a lot of bindings going on here. There's a lot of people know what computed observables are, knock out those, help you basically run computations on certain fields so that you can imagine that some of these are derived from calculations from other fields. And that is one interesting question. So you guys are seeing all this math happening, right? Where do you think I'm doing the math? Client or server? How many people think client? How many people? So how many server? A lot more hands than I assume. Okay, so the room thinks I'm doing it on the server and the room's right. At first I wanted to do it on the client because the client would avoid making an Ajax call to go calculate all this stuff. There's some problems with that because the math here is not trivial, not trivial at all. There's a lot of business logic involved. There's taxes for every single state in America and that all differs even based on localities, different cities. So we need to make calls to the server to run all of that calculation. So there's also some pretty complicated really algebra and advanced math to be able to pull off things like rolling a deal and figuring out how changing one number impacts all these other numbers. There's a ripple effect that happens there. So the server made sense there. We make a call to the server, it calculates it, it sends it back. I want to show you how big this data model is. I say recent deal, so I'm going to go over here to Fiddler and remove everything. Now I'm going to just load this one deal for Robert Taylor. We just loaded it. Let's go see what Robert Taylor's deal looks like. Here it is. Here's our service call. I'm going to pull it over and we'll look at the JSON that came back. I'll go over here to JSON. So one thing for starters, the size of the JSON was 4k, little over 4k worth of JSON. Which I just went to Douglas Crockford's talk. He said when he designed JSON, he was imagining people would send 2 or 3k with it and he's had bugs open for people trying to process gigabytes worth of JSON. And he had an integer overflow from somebody trying to do so, which is really interesting. Page cases, we keep using this. So what I want to do is just scroll down to give you an idea of how complex the data model is because I don't have time to take you through the whole app. But I'm going to scroll slowly so that you can see all the properties that are getting sent down to make this application happen. There's accessories, there's add-ons for the cars, there's service payments, there's different flex payments, monthly taxes, gap. I'm trying to scroll slow, but there's a lot there. Hundreds and hundreds and hundreds of properties. Old school jQuery, imagine if I was going in and I said, all right, let me go through this. First element, I will tie to this DOM element. The second property to this DOM element. Does that work? With that much JSON, could I do it? And would I go insane before I got to the end of it? It just doesn't work, right? And that's the beauty of using knockout combined with the mapping plugin. Because what the mapping plugin does is, so people said they were familiar with knockout. In knockout, you need to declare something observable so that knockout will keep track of that value. And you will get a two-way binding. I don't want to take all of these properties and have to say one by one, set a variable within JavaScript and set it observable to this property. Because I would be repeating myself, right? And with the mapping plugin, I don't have to repeat myself. Let me show you how this works. So for instance, within, here we go. So I take all the deals and I bind them using ko.mapping from JS. And that's saying, go take all this JavaScript that you just received and make everything in it observable. And now anything within that view model is observable by knockout. And anything that changes in the JavaScript will change the corresponding HTML element, DOM element. And anytime the DOM element changes, the JavaScript value corresponding will change. And this is a good segue for that. I think I've got it in there now. I'll bounce back for a second to that. I wanted to show you this quickly. I forgot to wrap up the performance. So this is how it depends on performance. You can see that with an empty cache, I was back in the states getting about a 13-second load time on IE8 initial. That's painful. That's pretty hard to justify. But they only have to pay it once the first time they load it. Then it's all cached up. And you can see that with a warm cache, three seconds really isn't too bad. So this is where you just have to decide whether minifying the JavaScript and unifying the files would be worth it. This is the tech stack that we've been looking at. And when you look at all these boxes, it's pretty intimidating. Now the server side is pretty simple. We're using Web API or Mlight for data access layer and then MS test for automated unit testing. But how many people feel like that client side story, these nine boxes on the right, is too much? That's too complicated. And that's a common feeling. And my concern is this, that if I am an employer out there looking for a developer, it's really hard to find somebody that knows all of this. And it's hard to convey it. If I tell people that I could look for somebody that knows knockout, but the chance of finding somebody that knows knockout and Durandal, it gets lower. And then somebody that knows knockout and Durandal and understands required JS and understands these other conventions that we're using, it starts to become a much smaller and smaller pot. And this is part of the reason that I think Angular is becoming a lot more popular because Angular tells a story that is far, far simpler. We'll get to that in a minute. Now it's, I say it's simpler, but it's simpler because it is extremely opinionated. And if you don't like it, tough luck, right? It is a very, very different view of the world. We use knockout and Durandal because 14% of our customers are on IEA. And here's the three big reasons that Durandal is really useful. It is convention-based. So just like ASP.NET MVC, your models and your views, it defines where they go. You can set up routing. This all feels really familiar if you've ever worked in that space. It allows you to compose things together. And this is really cool. So see how I'm saying div, data buying, compose. This goes out and it gets the view model called vehicle. And then it just splats it right into the page, right within this div. So whatever is within that view model, it goes get to the view, the corresponding view model, glues them together, and then puts them there on the page. Really easy to understand. So if you're familiar with ASP.NET web forms, for instance, then you could think of this like a reference to a user control. It's just a user control sitting right here. It's a little reusable piece that you can plug in. And I already mentioned routing. But Durandal and I have had a bit of a torrid love affair of recent. This was hard for me because remember, I said we were replacing Silverlight with this new HTML5 JavaScript CSS app, right? And I made the call and said we should use knockout with Durandal. And we launched just a couple months ago and then the bomb drops. Here we go. In case you haven't, how many already heard that Durandal is basically dead? Rob isn't using those words, but more or less, Rob, who started the Durandal project, has moved over to join the Angular team. He did a Kickstarter and the Kickstarter just didn't quite play out for Durandal. So I think he decided it made the most sense if you can't beat him, join him. And he has some really cool ideas that I'm hoping come over into Angular. Because as somebody that's worked in both Durandal and Angular, there are some things that Durandal does that I really like that isn't yet in Angular. And I think we'll start to see some of those. This is an interesting read, though. Nonetheless, so there's the tombstone, sad moment. And this is the way I felt when I read it. It was a punch in the face. Having to tell my boss that we might as well be on Silverlight or on Dead Tech again. Now that said, this is very, very different because someone may pick up Durandal and keep rolling with it. And even if they don't, moving from Durandal over to Angular isn't near as painful as moving from Silverlight to where we are now. Almost everything that we have can be reused. Most of the HTML won't have to change drastically. We'll start typing in G a whole lot more if we move to Angular sometime here soon, which is likely going to happen. So again, then this is our stack and a whole lot of boxes here. And this is why I believe Angular is getting a lot of attention. It is easier to grok this than this. And ultimately, you're going to need a lot of these other things up here if you want to build a full application. And this is a lot the same situation that you could argue that this is sort of Windows and this is, you could argue that this is Unix and this is Windows. People like Windows because it's opinion it just says, hey, do all these things. Whereas Unix is cool because it's a whole lot of small things and I'll pick the best of breed of everything. If you want the best of breed, you can still play in this space. Now Durandal's MIA, but the fact is everything that Durandal does, you could go ahead and do yourself. Durandal's just a set of conventions for working with knockout. Knockout isn't going anywhere. So you just have to make those decisions on your own instead. I've already talked about required JS, so I don't think I'll do a deep dive on any of that. We do have automated tests, but I don't know that I'll have time to get into it too. Ultimately the way we're doing testing is really automated integration testing. And the cool thing about having the separation of concerns is that I can test the view models and I can trust that when the view model is in a certain state, the right things are happening. I'm not testing whether a certain DOM element exists by doing something like you might do with Selenium, for instance. I'm not testing the UI. I don't have to fire up IE or use PhantomJS or anything like that. It's just I'm testing logic by testing the view model and saying, if the data is in this state, then the right things have happened. So it's not as fast as unit tests and it's a little more brittle than that, but it is pretty quick to get set up. And what this does is you just fire it up in your browser or you can use, has anybody used Chetzpa? A few hands. Okay. You can use Chetzpa, which will integrate, and I'm sorry, I'm speaking to Visual Studio, anybody that works in Visual Studio could use Chetzpa to integrate QUnit with Visual Studio and then your tests will run in the test runner and they'll feel totally native even though it's a JavaScript. I'm not going to read you this slide, but if you download the slides, this is just a reference for everybody. So I want to close with some principles. These are some lessons learned from the last year of this work. First question, how do I keep the DOM and the JavaScript in sync? Who can answer that? Binding. There we go. Yes. So what are the two-way bindings and what is giving us the two-way bindings? Knockout. Knockout is doing that. There are other ways to do that. Angular does it in a similar way. Backbone has their own ways of solving this. But ultimately, this idea of having the two bound together is really powerful. Knockout, you have to define it as an observable to get this goodness. That's one other benefit of Angular is you can use Pojo's, plain old JavaScript objects. You don't have to declare anything observable. It's just Angular is out there constantly looking for any changes in your JavaScript and saying, oh, that changed. Then let me go find the corresponding DOM elements. That sounds really inefficient, but it works pretty well. Unless you write something ridiculously complicated, there's been very few people that have been complaining about performance with Angular using this. How do I update many DOM elements when one changes? Computers can do that. Again, you could just say bindings again. That's what the bindings are doing. If I have three different DOM elements bound to the same value, then what's going to happen is when that value changes, all three of those DOM elements are going to change at the same time. Yes, computed observables. That was the other one that people were saying. So far, you're getting an A. Good deal. How should I move data between the client and the server? This is where there's a couple things going on. You need to be able to take all your JSON and turn it into a string. You can use JSON.stringify to do that. That works in all modern browsers. You can shim it in with JSON2.js, which I believe Douglas Crockford wrote. Thank you, Douglas, again. That's really useful so that you can get that data back to the server without having to explicitly convert it over to JSON. We centralized our service layer. I want to show you quickly how that works. One thing that I didn't mention is we're referencing jQuery in our app, but the amount of jQuery that is written in this app is hilariously small to the point that really the only reason it's in here is because I use Kendo UI for some of the UI, and Kendo has a dependency on jQuery. The only real jQuery that's in our app is this little fun right here. You probably recognize the jQuery$.ajax call. What I've done here is wrapped it all in a promise because we didn't want to use jQuery's promises, because, again, jQuery promises don't follow the promises spec. We're using Q instead, and we're coming in here and making all of our requests through this one line. If you look at anything else, so this is the library that makes the call, but by having every single aJax call run through this one method right here, then I have a lot of power because I can do things like this. I have a preloader that shows up. Remember how you were seeing from time to time whenever I was changing things? That preloader would show up. This is the place to do it because this is where I know that it's happening. You could say this is a bit ugly because it means that this service library knows a little bit about the UI. I don't have a real good solution for this offhand. You could use something like, I believe, postal, is it, where it could subscribe to these events that are happening, but I haven't gone down that road. Anybody use postal? I never see many hands on that. Congratulations, Gil. You're the only one. What's that? I haven't heard of postbox. Okay. Postbox is apparently similar. Nonetheless, what you see up here is if I look at any one of these files that are making the Ajax calls, for instance, Ajax calls for the deal. Here we go. What you find are one-liners because all I really need to define is the endpoint and pass the data in. Then I delegate everything to that Ajax service that I've set up. By the way, all that I'm showing you here, this is, again, this is something that isn't provided by Knockout. It's not provided by Durandal. This is my own creation here. If I were using Angular, Angular has their own opinions on how to do this. You can use their resource service, for instance, to just go in and say, all right, by convention, I created a RESTful API. If I followed the general pragmatic REST principles, then my URIs are going to be set up in a way that Angular makes it super easy to be able to do all of this. I spent a lot of time designing this. I'm really happy with how it worked out because, as you can see, every time we stand up a new Ajax call, all I have to do is define a get or a put, put in the URI and pass in the data, and it just works. The promises happen, and the UI does what it should, and I get the data back serialized like I'd like it to. That's pretty handy. Put the business logic on the server rather than the client. This is one of the other reasons that we aren't doing all our math on the client, was even if I minify and obfuscate it, somebody could go back and put all those little shredded pieces of paper back together, and effectively they have our application. Or maybe they don't even want to understand it. They can just copy and paste the whole thing and go host it elsewhere, and now they have a working solution because all they really need is a server on one side to provide some data. So we put everything we can over on the server in our spa, and making Ajax calls is not particularly expensive, so err on that side. Another thing to consider, how do I inject data from the server into my JavaScript on page load? And what I'm highlighting there is what I call the JavaScript configuration object pattern, and I don't have a slide on it, but if I pull up, let me do this. I'd help if I could type it. There I am. I've got a blog post on this that really sums it up. And the idea of the configuration object pattern is to take any data that the server knows that's needed on the client, send that data down on page load. If you know the client is going to need it, get it down there fast. And so let's go down here, and here's the example. Imagine that I have a single code base that's used by a bunch of different customers, and I have Google Analytics within there. I need to inject a different key for every single one of those customers. So I have all this static JavaScript sitting right here, and then this is the only thing that changes this one line right here, the Google Analytics key. Now the way that some people would want to solve this is go onto the server and then write all your JavaScript in one big string and then inject that variable from the database, right? And how many people have done that? That's a pretty common pattern. And it's problematic for a number of reasons. Now let me get to the solution first because we're pretty tight on time. Ultimately if you go into here instead and write all your JavaScript is just plain old JavaScript, put it in a JS file, then you can inject JSON into your page by using a JavaScript serializer in your language of choice. And C-sharp, I use the JavaScript serializer, there's JSON.net, whatever you want to use. Ultimately you want to take an object on your server, serialize it to JSON, spit it into the header of your page. And this is a pattern that's used all over the web. For instance, if I go to Google right now, you'll find, boy they have a lot going on, I think an easier example is if I go to Stack Overflow and look at their source, what you'll find is they do the same thing. If I go into here, you'll see stackexchange.net. So they're using what I call the JavaScript configuration object pattern to set all these things that are specific to me. The locale, off URL, all that is used by their JavaScript to make the application work. So have your server send down the knowledge that it knows right up front. And these are all the benefits of it. You separate your concerns, you get caching, you're minimizing your string parsing overhead. It is really painful trying to read JavaScript that isn't code colored and syntax checked when you make those typos. You're forcing somebody, if you write it on the server in a big string, then you're forcing somebody to think in terms of, okay, well, let's see, you're writing in Java or you're writing in C sharp, but this is a string that's ultimately going to be JavaScript. So these escape characters won't get sent down. And yeah, I don't have coloring, but I can see what you're doing. It becomes really hard to maintain and understand. So how do we organize all this JavaScript and HTML? Well compose small views and models. And that's what we saw. That's why we broke it down to almost 100 different files. Other than that one really large view model, most of our view models are 50-ish lines of code and most of our views are 50, 100 lines of HTML. They're solving small problems well. And the beauty of that is when I come over here and look at the app and we say, okay, there's, where's the app go? There's a bug right here under recent deals. Then I know what I need to do is come back over here and open recent deals or recent desks.html, the fact that it's named wrong is a separate political argument that I lost, but we won't get into that. And so you notice how small this is because this view is just handling that little tiny section right there that was listing the recent deals. So it gets really easy to quickly come in and I go, okay, well there's something wrong with the JavaScript. Well I know that's going to be in recent desks.js because that's the corresponding view model for this view. So here's the little bit of view model. And as you can see, it's a really small view model because there's not much logic here. You can load a desk, you can toggle whether it's showing, and you can determine whether the heading's visible. So, it's pretty simple stuff going on there. Durandal lets you compose views within other views. This is one of the really cool, powerful pieces of Durandal. And it's something that it does, I feel like, better than Angular right now. But Angular has some interesting things that it only does right now too. Angular's directives are really cool. And if you're anybody familiar with web components, next year a lot more people will be raising their hands. That's the direction that things are going. Web components are something that Angular's basically shimming in right now with their idea of directives. So it's a really powerful way to be able to remove the cruft in your code and think at a higher level of abstraction. So instead of having div, div, div, div, and then ul and all this, I can define that top level item with a tag name. For instance, if all those divs ultimately came together to be a voting button, then I could put the tag in as voting button. And all that stuff inside would just get thrown in. So pretty powerful idea. How do I avoid repeating myself? Have your server send everything down and then just use what your server did because your server can handle all this stuff. Don't go defining empty objects for your spa on the client. Have your server send down what's called a null object and empty object and then you can use that empty object throughout your application if you, for instance, need to add another row, that sort of thing. We want to have time to get to this movement. This is a really interesting conversation, though, about the style of JavaScript development over time. Ultimately, we are in a new era, though, and this era is data binding. This old idea of unattrusive JavaScript. It ended up there were some real problems with it. If I was using unattrusive JavaScript, I could not have built this application. It would have fallen down on itself and it would not have been maintainable. So data binding is, at the moment, the most promising future that we have. And it's definitely made things easier. And I won't go into this, but download the slides. You can see the difference here, though, that really the three different eras here. Dating, data binding is the way that we are writing JavaScript. Now I'm going to skip to the end here. Does building a spa even make sense? Well, not if you have proprietary business logic that you have to put down on the client or very little interactivity, slow page load. Ultimately, if the page is really called, then it's probably the wrong approach. It can also be a real pain to debug. There's a lot of downsides to doing single-page development. So if you don't need to, then I don't recommend doing it. You really need to be able to justify that a spa is the right approach. Now there are some good reasons why, though. It's very responsive. You can really get awesome interactivity. You can separate your concerns. And it's very, very simple. There are less abstractions in some ways over the code because you're sending down the real deal HTML. And you don't have to worry about debugging, too. That's one really nice thing. If you have an application with a really slow build time, I didn't have to pay any of that price because I was just playing in JavaScript plan. It's just save and load, save and load. So we built this very, very quickly. And ultimately, don't single-page all the things. This is the wrong mindset, right? What we need to think about is pockets of single-page applications. Look at your whole app and go, is there a place within this app where a single-page app makes sense? And our application is almost exclusively plain old web forms from way back when. But this is a pocket of single-page applications where we really thought it made sense. That's it. I'll be glad to take questions. Just come on up and visit. There's a few Pluralsight cards left. Thanks for listening. Thank you. Thank you.
 We're good? Excellent.  Let me hit play here.  Good afternoon.  This is real-world spa, a knockout case study.  This session really shouldn't have the word knockout anymore in it,  because we're going to talk about a lot of things outside of knockout.  So if you're coming in here expecting an introduction to knockout,  that's not my focus here.  What we're going to do is talk about a lot of lessons learned  from the biggest single-page application that I've ever built.  This is about eight months to a year worth of work  that we launched just a few months ago.  A lot of the lessons learned will hopefully be useful for you too.  I'm using what we're talking about here is really the foundation for my next course,  just thinking about patterns,  practices, and principles for single-page app development.  My clicker will work better if I plug it in.  Let's try that.  All right. So I want to get to know you and make sure that I'm  delivering what's most useful for everybody.  How many people in here have already built a single-page app?  Okay. So we got about half the room of built a single-page app.  How many people have done significant work in JavaScript to build web applications?  So quite a few more hands there.  That's the vast majority of the room. Cool.  How many know Ember right now?  Very few. Okay.  Gil got it covered.  How about Angular?  A lot of hands there. Backbone?  Okay. Just a few.  How about knockout?  Okay. So good. You weren't coming in here wanting an introduction anyway.  You've already familiar with knockout. Great.  Anyone worked with Durandal?  Just a few hands. Okay.  Required JS? Okay.  Probably few enough. We may talk a little bit about that too.  Anybody ever heard of Ajax before?  You don't even bother raising your hands.  Yes. Okay. Good deal.  So here's the things that we can focus on and we're going to get through as much of this as we can.  There is a sea of decisions in making a single-page application and that's maybe the hardest part  is making those decisions.  I spent weeks and weeks and lots of reading and ultimately even made maybe the wrong decision.  We'll get to that in a minute.  I want to demo the application that we built and I want to show you the code so you can tell me  that it's rubbish and why and that'll be just fine.  But we'll all get better along the way.  I want to discuss the tech stack that we picked and the performance implications of that stack  and if you're interested I can also show you the stack and how it runs in older browsers like IE8  because it's interesting comparing that to Chrome.  You can literally feel the difference of an older browser.  It still works but it does not feel as snappy.  And then I want to close with two things.  I want to close with talking about principles for writing single-page apps.  A lot of lessons learned from building something this big.  And then finally talking about whether building a spa even makes sense  because there are places where it does and doesn't.  So let's dive in.  I want to talk first about the sea of decisions because this is maybe the hardest part about it.  Now I love jQuery and how many people in here coded in jQuery?  A whole lot of handy.  There we go.  Hello, Room.  Great.  jQuery is really useful and has helped move us forward in a lot of ways.  Thank you, John Rezeg, for making that happen.  Now the problem with jQuery is it really is only solving a piece of the puzzle.  Manipulating the DOM is really useful.  Making Ajax calls easier is useful but there's a lot more that we need to get done for single-page apps  and that's what these sorts of options try to solve for you.  In this course or in this session today we're going to talk about knockout and derandal,  the one at the top here.  But these are your other logical options and these days more and more we're seeing anglers  sneaking closer and closer to becoming just the de facto standard here.  It's ridiculous how much power that it has here recently in inertia along the way.  Ultimately these are all great options but I'll get into maybe some specific reasons  that I feel like anglers getting so much traction in this.  But the app that we're going to look at is built with these technologies at the top.  Of course you have to pick a language which is strange.  You'd think by default it's JavaScript but if you're somebody that's into C sharp or  VB.net then maybe TypeScript sounds interesting.  Or if you're a Ruby developer then you probably like CoffeeScript.  Or if you're someone I've never met then you probably like Dart.  Is anyone using Dart?  It's silence.  Yeah, I don't know.  Google, this is something that Google tried that just doesn't seem to be catching on.  You have to choose how you're going to return all that JSON to your application.  We went with just good old web API.  It's nice and simple.  So we're writing C sharp on the server and just returning JSON over web API.  Node.js is another popular way to do this and I could list on and on here.  But this was another decision we had to make.  We had to pick a promise library because if you're using knockout and derandal that doesn't  come out of the box.  We could have used jQuery.  I don't recommend using jQuery because jQuery does not honor the promises spec.  And because of that there's some weirdness in there.  You're really better off choosing one of these other three.  We went with Q and have been quite happy with it.  If you want to do testing you're going to need a framework for that too.  And GIL did a talk about Jasmine.  Just anybody go to GIL's talk on Jasmine?  So quite a few hands.  Okay, I figured that would be the case.  So I happened to choose Q unit.  I've been pretty happy with it.  From all that I've read though, Jasmine is probably a better choice.  Q unit, the advantages.  The learning curve is really low.  It was actually created by John Rezeg to test jQuery.  Hence the name Q unit.  But it's really easy to pick up and it's a good start.  You'll probably want some kind of a utility library to make JavaScript feel a little bit  more like a big grown up server side language.  And that's what these seek to do.  You can, if you're familiar with C sharp, you can do things that feel a bit like link  statements within the realm of these utility libraries.  Hi, Steve.  I just saw you over there and now I'm all excited.  Sorry, I got Steve wrote a knockout.  Am I right?  Started the project.  Okay, yeah.  So smart guy over there.  I've just got to say hi.  He made a lot of this possible.  Data access.  We've got another decision to make.  Amplify, breeze.  These are two ways to do it.  I didn't end up getting this sold to my manager because if I were to describe breeze to you  right now, I would say breeze is a way to basically expose your database over a RESTful  API.  Boy, that sounds convenient and it doesn't sound very secure, does it?  So I can't really figure out by the time you've done the work to secure all the edge cases  that would happen from effectively just making a RESTful API call to your database.  I don't understand.  Anybody in here worked with breeze?  Is my description accurate?  No opinions.  Okay, we'll move on.  Network transport.  Another decision that you have to make.  We're using plain old Ajax calls because ultimately there's very little that we need to do that  is truly real time.  We didn't need server side push than anything that I'm doing.  But if you're going that route, then of course you can just Ajax long polling is a really  simple way to go or just making call every so often.  Basically down here at the bottom of the screen, these are options that abstract away all of  this confusion.  If you choose to use signal R, then signal R is ultimately using one of these things  up here for you and you don't know that it's doing it.  You just trust it and it works, which is pretty cool.  So a lot of ways that you don't have to deal with that complexity.  Of course you need to persist your data somewhere.  We didn't do anything flashy.  We went with SQL server and we have a pretty complex data model.  We're doing a lot of joins.  We're using caching so that it's not a big deal to pull all this back and spit it out  in this right shape for our JSON.  So that's been working out well.  Then of course you need to do cross browser testing.  I'm going to look at browser stack and show you guys how we're doing cross browser testing  with it.  Browser stack is really cool and it saved us a lot of time from dealing with virtual  machines.  If you aren't familiar with it, this modern IE, this link here, which I guess you'll  have to download the slides to see the link.  Modern IE is a Microsoft initiative that has old versions of IE, virtual machines that  you can download and they'll work in a number of different VM platforms.  All right, so that's the introduction.  Let's get a little bit geekier and talk about an app demo.  Here was the situation.  I work in automotive software and we had a Silverlight application that car salesmen  were using and it was getting a little long in the tooth for a number of reasons.  For one thing, people are now wanting to be out at car dealerships with tablets, with  iPhones and be able to do their work and Silverlight is a non-starter on those platforms.  Now I don't know much about the automotive industry around here.  Do you still have dealerships that hold inventory of cars?  Is that an idea here?  Okay, because I know that's not worldwide.  The reason I ask that too is the big idea of our application is this.  So here's Vinny, my friend, the car salesman.  He's a nice guy, questionable taste in clothes, but otherwise, nice guy.  Vinny, you sit down at his desk and you're going to talk about buying a car.  Maybe you found this Ford Focus and it's just really exciting.  When you sit down at his desk, that is called desking.  That's salesman jargon and what you're doing there is talking about the bottom line.  How much are you going to pay for that car?  What payments will you make?  What's your interest rate?  What bank will you go through?  How can I upsell you on a bunch of different options?  Car salesman need a piece of software to make this happen.  That piece of software is called desking and that's what I'm going to show you.  We built a single-page application to help make Vinny be more successful.  So I'm going to jump over here to the app itself and make sure I'm logged in.  I'll jump back in here.  One thing that you do see is the rest of this application is not a single-page app.  What I'm showing you here is one of the few places in the entire application that is a  spa.  You're also going to notice that because of our Wi-Fi, it's going to be pretty painfully  slow to load.  I'll get into also some reasons why.  This app has almost 100 JavaScript files, separate files that contain the logic to perform what's  going on on the screen.  It has about 95 different HTML files.  Has a huge portion of CSS to make it all happen too.  So let's do this.  Imagine you're coming in and you're going to buy a new car and I'm going to name this  deal.  Maybe I'm trying to sell you a Ford Focus.  I'll just name it that.  That's fine.  And you're considering purchasing it new.  So that's the template.  I'm not even going to add a vehicle, but I could go in and search inventory if I wanted  to.  So I'll go ahead and just create the deal.  And you're going to see this all pop up.  Now we designed this to fit on 1024-Wide.  You can see it just squeezes in at the current res here.  So now we're seeing a deal and you can see I'm trying to decide between doing a purchase,  that's the P, and a lease here.  So let's say for instance that I'm trying to decide on a down payment.  Well, I tell you what, I'm going to add a car in.  Well I'll do this instead.  I'm going to pull up a previous deal so that you don't have to wait for me to do all this  stuff.  Just show you how it is all together.  All right.  So this person is thinking about buying a 2006 Mercury Milan right here.  And there's the picture of it.  We can see it has 65,000 miles and it's selling for $9,900.  And they're considering a cash deal in this case, but most people these days end up purchasing  a car and making payments on it.  And they're considering maybe a $1,000 down payment or a $2,000 down payment or $3,000  down payment.  Notice how as I'm typing these things in, it's making Ajax calls to the server and you're  seeing payments calculate immediately.  Maybe I can get him a 4.5% interest rate at 60 months.  Now I'm going to tab out.  And again, you just see little toast pop up on the right hand side of the screen that's  showing things that have changed.  And now we have down payments of $1,000, $2,000, or $3,000.  And these are the monthly payments that someone would make based on that.  Now imagine you're sitting there and we're having a conversation and you go, I can't  afford $173 a month.  And I go, OK, well that's fine.  What can you afford?  Let me click this roll button here.  Well I could afford $125 a month.  That I can do.  So I'll go ahead and click roll.  And what it's doing is making calculations and figuring out what numbers could I change  to get you to that down payment because we want to pay $125 a month.  Well I could lower the selling price.  I could increase my down payment.  I could get more for my trade in.  Or I could pay for 88 months instead of for 60 months.  Well, like most Americans, I just want to pay longer.  So that's what I'm going to do.  We're fine with going into debt, into perpetuity here.  So I clicked that and now what happened was, note my payment right here.  Now it's $124.  So it changed the payment accordingly.  It came down here and set the monthly term just like we'd like.  Now I could go into a whole lot more that this thing does and I could open up all sorts  of dialogues and open other things, lots of jargon, but I don't want to bore you with  the application.  I want to show you this enough so that you can understand some of the things that we  ran up against.  The first takeaway that you have here is when I change one value here, if I change this  to 5.9%, pay attention to the math on the left hand side of the screen in this gray  box here.  I'm going to tab out and you'll notice that the balance due will change.  Well I'm sorry, no, that's not a good example.  I'm going to change this, change my purchase price, $12,000.  Now when I do, all this math down here changes.  All the payments over here change.  So at any given time, there are 10, 20, 30 different DOM elements that have to change  when one thing changes.  So this is when I had the epiphany that the old school model of using jQuery to manipulate  DOM elements really falls apart.  Because if you're using jQuery to say, okay, when that cell changes, change this cell,  this cell, this cell, this cell, this cell, I can't do it, it falls apart.  Imagine maintaining that thing because when I change that cell, these 14 things change.  When I change this cell in a different way, these 22 other things change.  So what you need to be able to declare is say, I want this value right here bound to  a certain piece of data back in the JavaScript.  And that's exactly what's going on here.  If I scroll this down some, you can see that I'm using knockout.  And it's just a data bind formatted text to payment.  In this case, it's called matrix payment because this is called a payment matrix over here.  So this data dash bind is just saying, go get the JavaScript variable called matrix payment  and put it in here.  And formatted text is a custom binding that I wrote that formats the text the way that  we would like it for this application.  I can go in and do other things like copy this scenario over.  I could create a new deal and maybe put that in for a different car or for the same car.  I could go in and edit the vehicle.  I can search for deals.  All sorts of things going on.  And again, I don't really want to focus too much on the app, but I want to show you enough  that we can use it for a bit of conversation later.  Does anybody want to look at code?  Okay.  Well, good.  I was hoping I'd get a yes there.  Otherwise, I was going to have a hole in my schedule.  Yeah.  All right.  So let's talk about code.  This is the folder structure.  Is that big enough that you guys can see it on the TVs over there?  Cool.  This is the folder structure for it.  I have left out the rest of the big huge app.  This is just the single page app that we've built.  The way I have this structured is we have custom bindings in a folder.  Keep our CSS there.  Our images is all self-explanatory.  These are all the JavaScript libraries that we're using.  As you can see, jQuery, we're using Kendo for a little bit of our UI.  Of course, Knockout.  We're using a few different Knockout plugins, and in particular, Knockout Mapping, which  has been really helpful.  I'll get to that.  Of course, Q. And then Toaster.  Toaster is a project by John Papa that is doing those little nice green confirmations  that pop up in the corner and then fade out.  That's a handy little add-in.  That said, I could have used Durandal for that too, but I liked how Toaster did it.  And then our services.  You could think about the services section as really this is where all our Ajax calls  sit.  They're in one folder called services.  So anytime I'm going to make a call to the server so that I can ultimately hit the database,  make changes, get back to JSON, it's going to happen through JavaScript within this folder.  You could see that we've broken it down.  I say that, but there's a few things in here that aren't dealing directly with any kind  of Ajax call type work.  Like cookies is just a service that I wrote that abstracts away the browser cookies and  gives us a little cleaner API to work with.  And then local storage, the same thing.  It's a little service that lets me work with local storage in a way that's useful for us  and then a little math library, those sorts of things.  So down here is the real meat and potatoes, the views and the view models.  Oh, and I skipped over tests, this single file has our test.  These are Q unit tests.  I'll get into Q unit if we have time.  I don't know if we will, but all of our tests currently just sit in this one file.  So let's look at views and view models.  Who here is familiar with MVC?  Probably a lot of hands.  Okay, so in MVC we have, especially in ASP.NET MVC, there's this idea of convention over  configuration and we're saying by convention I have this view called user.html and then  we have this corresponding view model sitting over here and those two get bound together  because they have the same name.  They sit in the same corresponding directory structure.  That's the way Durandal works.  It's the same thing.  Durandal gives you conventions on top of knockout, which is pretty cool.  That's both the benefit and the downside of knockout.  The beauty of knockout is that it is just a library that solves a really particular  problem and as someone who spent a lot of time in Unix, I get it.  The power of Unix is being able to pipe all these commands together and I'll pipe this  cat this file and pipe this to said, pipe that to awk and then grep for such and such  and you get all this power by taking little tiny pieces, little tiny applications and using  them together.  That's what knockout allowed us to do because knockout solved the problem of binding and  it does that really well.  The thing that it doesn't do though is tell you where to structure your files and how  to do so.  That's what Durandal does for us.  Let's jump into the heart of the application.  I'm going to collapse this down.  This is default.aspx.  This is what loads initially.  The first thing that's interesting about this is that this file is only 46 lines long.  There's not much here to consume.  I have, at the top, we'll just run through it.  I have some references to CSS, not much to see here.  Then we come down to the body and there's this.  This piece is of interest.  This is the wrapper that gets changed.  You know how when I first loaded it, it said loading and you waited for it to load and then  it went away?  This is what Durandal replaces after it's pulled down all of your content.  It ends up slapping all your content into the loading wrapper.  It basically looks for an element with an ID loading wrapper that's sitting within application  host which sits right up above.  If you do Angular, Angular has a similar idea but you would say ngapp to be able to reference  the app and then things within that get handled by Angular.  Then we jump down to the bottom and you'll see all the scripts.  You can see there's quite a few.  Just probably nothing too surprising here.  We have a tracker.  We're using track.js which, by the way, if you're wanting to track JavaScript errors,  track.js is a great service.  A friend of mine, Todd, runs it.  He's speaking here too.  He's already spoken though so you missed it if hopefully you got to see him.  Then ultimately down here at the bottom we have what?  Knockout, queue and some simple libraries for handling dates and whatnot.  The interesting thing is you're going, wait, that can't be all the JavaScript because I  said there were 90-something files with a JavaScript that ultimately get used here and  that's true.  The real story is what's going on here on 44.  We're using Require.js and a lot of people weren't familiar with it so let me go into  that.  The story with Require.js is you can download your JavaScript files on demand and you follow  what's called the asynchronous module definition pattern which basically lets you say at the  top of your file the other dependencies that your file has.  A lot like a using statement.  In C-sharp you'll say using this, using this, that's you saying, hey, go get these other  resources and pull those in for me.  Let's look at one example of a view model.  Let me try to pick, okay, this one's massive.  Let me pick one that's a little easier to digest.  Okay, yeah, this one's pretty easy.  This is the view model that is used for handling templates.  If I jump over here to the UI so you know what templates are, it's over here in this  accordion under Manage Templates.  You can open up different templates and manage them.  These are just quick ways to get started on a desk and people can set up a desk in different  ways.  This little area right here has its own view model.  Ultimately, this has a view model, this has a view model, this has a view model, this  has a view model.  The big app and all the complexity, every single dialog box has its own view model.  We've eaten the elephant a bite at a time.  Back to RequireJS.  This is an asynchronous module definition pattern.  What RequireJS is saying is right here, I'm saying, okay, here are three.  Three dependencies.  These are three other files that this file needs to load.  What RequireJS would do is when I made a call to this file, it would say, okay, go  get these other dependencies and bring them into scope.  I define what variables are used for these over here on the right.  You'll notice, and if I formatted this better, you could read it better.  This corresponds to this, the second, to the second, and the third to the third.  I'm saying this is the variable name that you will use down below to reference those.  The cool thing about RequireJS is on page load, I'm not having to pull in those 95  files.  I pull in the JavaScript files that are necessary, and then as they're needed, RequireJS goes  out and it makes the calls to get the others.  That keeps your initial HTTP call as lightweight as possible.  Let's go back to default.  The way that all works is by convention, it takes a HTML5 data attribute called main,  and then that forces it to come out here and look for a JavaScript file called main.  In here, that's where I configure RequireJS.  This is some stuff specific to Durandal, so I won't bore you with those details.  The largest view model in this application is desk.js, probably not surprising.  This is where the core of the logic sits.  If you look at the number of dependencies on this one, it's high enough to be a little  bit embarrassing for me.  These are, as you can see, there are a lot of dialogue boxes in this application.  We put all of those under slash windows.  Then, of course, these are all the variable names that associate those things up above.  The one thing I am proud of is this file is huge, but if I scroll down through it, what  you see is there's a lot of, let me just do this.  I'll collapse it all down.  If I collapse down to just function names, you at least see that these are a lot of small,  well-named methods because watch the line numbers on the left.  This is something I do a lot when I open any kind of file.  I like to collapse it down to definitions and then scroll through and just get a feel  of the high level of what it does because you can read the function names and you can  look at line numbers and go, I shouldn't see any huge jumps in line numbers.  If I see a jump from line 1,000 to line 2,000, that's a bad sign because that means there's  a thousand line method sitting there and there's a lot going on that I need to go understand  and there's no good function name that's going to declare all that's going on inside.  All right, so how big is this?  These are the stats.  It's a very heavy load.  93 JavaScript files, 19 separate HTML files, five CSS files and 11 images because we're  using sprites, a spritesheet that really greatly reduces the number of images that we have  to require for this.  So that's 132 HTTP requests.  That's pretty absurd.  Is this malpractice?  Is that too many?  I feel like that's just silly.  So for those that think it's silly, what is your recommendation to me to reduce this  number?  Bundling and minification, yes, and that's the very common answer.  Now I am not bundling or minifying in this case and can anyone think of a reason why  I shouldn't bother?  Yes?  Did you call me lazy?  Because I'm lazy loading?  That sounds much better.  Thank you.  We're going to go with the second hand.  Yes, because I'm lazy loading and that is part of it.  With RequireJS, if I bundle everything, RequireJS can't do its thing anymore and request them  on demand.  So that's one reason.  Now the bigger reason is this.  Remember, this whole app sits behind a login.  The situation is a salesman comes in in the morning, grabs their coffee and they load  this application and this will be the only application that they use all day.  So whether this takes one second or three seconds, and by the way that's about the difference  between these two in our case, doesn't matter because it's a couple seconds once a day.  It's really small beans.  So there's some other things that are really a downside to bundling and minification.  Once you go to production, then all of a sudden your code in production doesn't mirror what  you have on your local machine.  There's ways to get around that, but it does add complexity.  And I am all for keeping it simple if I can.  And in our case, we can keep it simple and live with the fact that it doesn't exactly  load like blue blazes.  That said, this, let me, let's just see how fast it loads.  132 HTTP requests on conference Wi-Fi, hitting servers and, oh, we're done.  So I wasn't done doing the description.  We're hitting servers in the United States from the other side of the world.  I can tell you this, when I demo it in the States, it is quite a bit faster.  This, also, I think the Wi-Fi just seems a little slow today.  So let's do it one, two, three, four, five.  Yeah, that's pretty painful.  This is a Republic app.  I'd give it an F. But given our user base, this works okay.  Now if I cleared cache and did this again, you'd see that number go way up.  Because if I open up Fiddler, of course, and look at what's going on here and see all the  requests come down, let's do that.  So here it is spitting through them all.  One by one.  Got them all in.  And, well, no.  It's still working on it.  In fact, it looks like we're getting...  Oh, no, I guess it did all come down.  Okay.  Just a lot of things didn't have to get loaded because it was all cached.  Okay.  So let's jump back over here.  The full single-page application, 53 view models, nine libraries, 39 pop-up windows,  56 HTML files, and 94 RESTful endpoints.  There are a lot of service calls.  And also, I should get into the REST side of things here.  And let's see.  I'll do that a little bit later.  I want to save that some.  One of the reasons that we had to choose a knockout with the Randall was because the great  thing about knockout is you can use it all the way back to IE6.  And for now, I haven't heard any changes on that front.  I think that's staying for the foreseeable future at the moment.  There's this real trend right now toward evergreen browsers.  And this idea that we're only going to support browsers that auto-update.  Now, the definition of auto-updating is a bit interesting, though, because IE10 auto-updates.  But as far as I know, IE10 will not auto-update to 11.  Is that true?  Can anybody confirm that?  I have not heard any confirmation that IE10 will ever move to 11.  So IE10 is not an evergreen browser.  And I don't know of any plans for IE11 to auto-rev to 12.  Maybe that will be the first one that's truly evergreen.  But that's what we need is this idea of people that are on the browser today will get the  new version as soon as possible.  That helps us really move this story of single-page applications forward.  And that's important because IE8 is 10 times slower than modern browsers.  And you can feel this.  Does anybody want to see how this runs in IE8?  Okay, I figured some people would be curious.  This is a good time for me to show you BrowserStack.  We're using BrowserStack to do cross-browser testing.  Beauty of BrowserStack is you pay them a little bit of money, and then all of a sudden you  have huge convenience.  Let me show you what you get here.  These are all the operating systems that I can test in.  And even some mobile emulators.  This for Windows XP, just Windows XP.  Look at all the browsers I have to choose from.  I can go all the way back to IE6.  And then, of course, I get to select my resolution.  Now I tend to spend most of my time testing in IE8 on Windows XP because sadly, 14% of  our customers are still on IE8.  14% of them are still on 7, but I was at least able to sell management.  The 14% on 7 cannot use this new app.  I just did not want to go down that road of trying to support 7, too.  There's a lot more pain going back to IE7.  So this is firing up a virtual machine.  And oh, I just remembered, I can't do that this way.  Wait, wait, where did I go to?  I think I pointed to the wrong...  Give me just one second.  I'm going to load back up.  I think what I did was I pointed to...  Yes, I did.  I'm going to the wrong URL.  That makes all the difference I found.  It's getting the right URL for demos.  There's a pro tip next time you speak.  All right, so we're going to hit the proper prod URL here.  And it does rely on Flash.  It's a little bit slow because remember, it's spinning up a virtual machine just for you.  And now...  And so here's the mind bender is I'm hitting some machine somewhere in the world and the  browser is showing all this to me basically using Flash.  And it is very slow, especially on slow Wi-Fi like this.  It's pretty painful to use.  You really want a fast network to be able to use BrowserStack.  And it feels especially slow when you're trying to demo for people.  But you can automate tests with BrowserStack.  So you want to write a bunch of tests and then integrate and make sure that your app  runs properly in older browsers.  Then you can write automated tests and just ship them all off and they'll run up.  And you don't have to worry about exactly how long they take because it's all just automated  and you're not standing around waiting.  All right, so you're going to have to bear with me on the fact that...  Let me try full screening here to get us a little more space.  And it is loading right now.  It's going to be...  There we go.  Okay, so we are in.  By the way, there's a bug in their virtual machine.  I should have pulled up the IE7 version instead, but this is a display issue that only happens  in their virtual machine.  It doesn't happen on real native items.  And boy, does this look as awful to you as it does to me?  Yeah, I think they're...  And that's the thing.  They will throttle down display quality as much as they have to based on your connection  to get you something viewable.  They can see that the Wi-Fi here is painfully slow.  So let's do this.  How long does it take to load a desk within this app?  I will click this and one, two...  So you can see...  I'm going to tell you when I click.  Click.  Now in Chrome, it was instant.  One, two...  It was about two and a half seconds.  Let's go over to Chrome and see how fast this is.  One...  One...  Yes.  One...  I mean, so you can see Chrome is more or less instant.  Even on slow connection as I load these.  But over here on this VM, it's pretty painful.  One, two...  And a given, this is the combination of a slow VM and also running IE8, which has a much  slower JavaScript rendering engine.  Let's do something that ends up exercising the engine a bit more.  This changes a whole bunch of DOM elements.  So I'm going to say I want to roll to 225 and I'll end up setting the price here.  So this is going to change all sorts of elements behind the scenes.  And we'll go one, two...  About two, two and a quarter seconds.  So if you were using this all day, you'd probably go, oh, this is a little painful.  So I'm hoping that the people that use it on IE8 complain about the speed and then I  can say, well, hey, you have a free solution.  Just go upgrade your browser, you know, or go download Chrome for free.  Even if you have to have IE8, you could always have Chrome alongside it.  There's nothing we can do about the fact that it is 10 times slower.  So things that are instant in Chrome show up here.  And this is, by the way, after doing a lot of work to improve the performance.  But there's just a lot of bindings going on here.  There's a lot of people know what computed observables are, knock out those, help you  basically run computations on certain fields so that you can imagine that some of these  are derived from calculations from other fields.  And that is one interesting question.  So you guys are seeing all this math happening, right?  Where do you think I'm doing the math?  Client or server?  How many people think client?  How many people?  So how many server?  A lot more hands than I assume.  Okay, so the room thinks I'm doing it on the server and the room's right.  At first I wanted to do it on the client because the client would avoid making an Ajax call  to go calculate all this stuff.  There's some problems with that because the math here is not trivial, not trivial at all.  There's a lot of business logic involved.  There's taxes for every single state in America and that all differs even based on localities,  different cities.  So we need to make calls to the server to run all of that calculation.  So there's also some pretty complicated really algebra and advanced math to be able to pull  off things like rolling a deal and figuring out how changing one number impacts all these  other numbers.  There's a ripple effect that happens there.  So the server made sense there.  We make a call to the server, it calculates it, it sends it back.  I want to show you how big this data model is.  I say recent deal, so I'm going to go over here to Fiddler and remove everything.  Now I'm going to just load this one deal for Robert Taylor.  We just loaded it.  Let's go see what Robert Taylor's deal looks like.  Here it is.  Here's our service call.  I'm going to pull it over and we'll look at the JSON that came back.  I'll go over here to JSON.  So one thing for starters, the size of the JSON was 4k, little over 4k worth of JSON.  Which I just went to Douglas Crockford's talk.  He said when he designed JSON, he was imagining people would send 2 or 3k with it and he's  had bugs open for people trying to process gigabytes worth of JSON.  And he had an integer overflow from somebody trying to do so, which is really interesting.  Page cases, we keep using this.  So what I want to do is just scroll down to give you an idea of how complex the data model  is because I don't have time to take you through the whole app.  But I'm going to scroll slowly so that you can see all the properties that are getting  sent down to make this application happen.  There's accessories, there's add-ons for the cars, there's service payments, there's  different flex payments, monthly taxes, gap.  I'm trying to scroll slow, but there's a lot there.  Hundreds and hundreds and hundreds of properties.  Old school jQuery, imagine if I was going in and I said, all right, let me go through  this.  First element, I will tie to this DOM element.  The second property to this DOM element.  Does that work?  With that much JSON, could I do it?  And would I go insane before I got to the end of it?  It just doesn't work, right?  And that's the beauty of using knockout combined with the mapping plugin.  Because what the mapping plugin does is, so people said they were familiar with knockout.  In knockout, you need to declare something observable so that knockout will keep track  of that value.  And you will get a two-way binding.  I don't want to take all of these properties and have to say one by one, set a variable  within JavaScript and set it observable to this property.  Because I would be repeating myself, right?  And with the mapping plugin, I don't have to repeat myself.  Let me show you how this works.  So for instance, within, here we go.  So I take all the deals and I bind them using ko.mapping from JS.  And that's saying, go take all this JavaScript that you just received and make everything  in it observable.  And now anything within that view model is observable by knockout.  And anything that changes in the JavaScript will change the corresponding HTML element,  DOM element.  And anytime the DOM element changes, the JavaScript value corresponding will change.  And this is a good segue for that.  I think I've got it in there now.  I'll bounce back for a second to that.  I wanted to show you this quickly.  I forgot to wrap up the performance.  So this is how it depends on performance.  You can see that with an empty cache, I was back in the states getting about a 13-second  load time on IE8 initial.  That's painful.  That's pretty hard to justify.  But they only have to pay it once the first time they load it.  Then it's all cached up.  And you can see that with a warm cache, three seconds really isn't too bad.  So this is where you just have to decide whether minifying the JavaScript and unifying the  files would be worth it.  This is the tech stack that we've been looking at.  And when you look at all these boxes, it's pretty intimidating.  Now the server side is pretty simple.  We're using Web API or Mlight for data access layer and then MS test for automated unit  testing.  But how many people feel like that client side story, these nine boxes on the right,  is too much?  That's too complicated.  And that's a common feeling.  And my concern is this, that if I am an employer out there looking for a developer, it's really  hard to find somebody that knows all of this.  And it's hard to convey it.  If I tell people that I could look for somebody that knows knockout, but the chance of finding  somebody that knows knockout and Durandal, it gets lower.  And then somebody that knows knockout and Durandal and understands required JS and understands  these other conventions that we're using, it starts to become a much smaller and smaller  pot.  And this is part of the reason that I think Angular is becoming a lot more popular because  Angular tells a story that is far, far simpler.  We'll get to that in a minute.  Now it's, I say it's simpler, but it's simpler because it is extremely opinionated.  And if you don't like it, tough luck, right?  It is a very, very different view of the world.  We use knockout and Durandal because 14% of our customers are on IEA.  And here's the three big reasons that Durandal is really useful.  It is convention-based.  So just like ASP.NET MVC, your models and your views, it defines where they go.  You can set up routing.  This all feels really familiar if you've ever worked in that space.  It allows you to compose things together.  And this is really cool.  So see how I'm saying div, data buying, compose.  This goes out and it gets the view model called vehicle.  And then it just splats it right into the page, right within this div.  So whatever is within that view model, it goes get to the view, the corresponding view  model, glues them together, and then puts them there on the page.  Really easy to understand.  So if you're familiar with ASP.NET web forms, for instance, then you could think of this  like a reference to a user control.  It's just a user control sitting right here.  It's a little reusable piece that you can plug in.  And I already mentioned routing.  But Durandal and I have had a bit of a torrid love affair of recent.  This was hard for me because remember, I said we were replacing Silverlight with this new  HTML5 JavaScript CSS app, right?  And I made the call and said we should use knockout with Durandal.  And we launched just a couple months ago and then the bomb drops.  Here we go.  In case you haven't, how many already heard that Durandal is basically dead?  Rob isn't using those words, but more or less, Rob, who started the Durandal project, has  moved over to join the Angular team.  He did a Kickstarter and the Kickstarter just didn't quite play out for Durandal.  So I think he decided it made the most sense if you can't beat him, join him.  And he has some really cool ideas that I'm hoping come over into Angular.  Because as somebody that's worked in both Durandal and Angular, there are some things  that Durandal does that I really like that isn't yet in Angular.  And I think we'll start to see some of those.  This is an interesting read, though.  Nonetheless, so there's the tombstone, sad moment.  And this is the way I felt when I read it.  It was a punch in the face.  Having to tell my boss that we might as well be on Silverlight or on Dead Tech again.  Now that said, this is very, very different because someone may pick up Durandal and keep  rolling with it.  And even if they don't, moving from Durandal over to Angular isn't near as painful as moving  from Silverlight to where we are now.  Almost everything that we have can be reused.  Most of the HTML won't have to change drastically.  We'll start typing in G a whole lot more if we move to Angular sometime here soon, which  is likely going to happen.  So again, then this is our stack and a whole lot of boxes here.  And this is why I believe Angular is getting a lot of attention.  It is easier to grok this than this.  And ultimately, you're going to need a lot of these other things up here if you want  to build a full application.  And this is a lot the same situation that you could argue that this is sort of Windows  and this is, you could argue that this is Unix and this is Windows.  People like Windows because it's opinion it just says, hey, do all these things.  Whereas Unix is cool because it's a whole lot of small things and I'll pick the best  of breed of everything.  If you want the best of breed, you can still play in this space.  Now Durandal's MIA, but the fact is everything that Durandal does, you could go ahead and  do yourself.  Durandal's just a set of conventions for working with knockout.  Knockout isn't going anywhere.  So you just have to make those decisions on your own instead.  I've already talked about required JS, so I don't think I'll do a deep dive on any of  that.  We do have automated tests, but I don't know that I'll have time to get into it too.  Ultimately the way we're doing testing is really automated integration testing.  And the cool thing about having the separation of concerns is that I can test the view models  and I can trust that when the view model is in a certain state, the right things are happening.  I'm not testing whether a certain DOM element exists by doing something like you might do  with Selenium, for instance.  I'm not testing the UI.  I don't have to fire up IE or use PhantomJS or anything like that.  It's just I'm testing logic by testing the view model and saying, if the data is in this  state, then the right things have happened.  So it's not as fast as unit tests and it's a little more brittle than that, but it is  pretty quick to get set up.  And what this does is you just fire it up in your browser or you can use, has anybody  used Chetzpa?  A few hands.  Okay.  You can use Chetzpa, which will integrate, and I'm sorry, I'm speaking to Visual Studio,  anybody that works in Visual Studio could use Chetzpa to integrate QUnit with Visual Studio  and then your tests will run in the test runner and they'll feel totally native even though  it's a JavaScript.  I'm not going to read you this slide, but if you download the slides, this is just a  reference for everybody.  So I want to close with some principles.  These are some lessons learned from the last year of this work.  First question, how do I keep the DOM and the JavaScript in sync?  Who can answer that?  Binding.  There we go.  Yes.  So what are the two-way bindings and what is giving us the two-way bindings?  Knockout.  Knockout is doing that.  There are other ways to do that.  Angular does it in a similar way.  Backbone has their own ways of solving this.  But ultimately, this idea of having the two bound together is really powerful.  Knockout, you have to define it as an observable to get this goodness.  That's one other benefit of Angular is you can use Pojo's, plain old JavaScript objects.  You don't have to declare anything observable.  It's just Angular is out there constantly looking for any changes in your JavaScript  and saying, oh, that changed.  Then let me go find the corresponding DOM elements.  That sounds really inefficient, but it works pretty well.  Unless you write something ridiculously complicated, there's been very few people that have been  complaining about performance with Angular using this.  How do I update many DOM elements when one changes?  Computers can do that.  Again, you could just say bindings again.  That's what the bindings are doing.  If I have three different DOM elements bound to the same value, then what's going to happen  is when that value changes, all three of those DOM elements are going to change at the same  time.  Yes, computed observables.  That was the other one that people were saying.  So far, you're getting an A. Good deal.  How should I move data between the client and the server?  This is where there's a couple things going on.  You need to be able to take all your JSON and turn it into a string.  You can use JSON.stringify to do that.  That works in all modern browsers.  You can shim it in with JSON2.js, which I believe Douglas Crockford wrote.  Thank you, Douglas, again.  That's really useful so that you can get that data back to the server without having to explicitly  convert it over to JSON.  We centralized our service layer.  I want to show you quickly how that works.  One thing that I didn't mention is we're referencing jQuery in our app, but the amount of jQuery  that is written in this app is hilariously small to the point that really the only reason  it's in here is because I use Kendo UI for some of the UI, and Kendo has a dependency  on jQuery.  The only real jQuery that's in our app is this little fun right here.  You probably recognize the jQuery$.ajax call.  What I've done here is wrapped it all in a promise because we didn't want to use jQuery's  promises, because, again, jQuery promises don't follow the promises spec.  We're using Q instead, and we're coming in here and making all of our requests through  this one line.  If you look at anything else, so this is the library that makes the call, but by having  every single aJax call run through this one method right here, then I have a lot of power  because I can do things like this.  I have a preloader that shows up.  Remember how you were seeing from time to time whenever I was changing things?  That preloader would show up.  This is the place to do it because this is where I know that it's happening.  You could say this is a bit ugly because it means that this service library knows a little  bit about the UI.  I don't have a real good solution for this offhand.  You could use something like, I believe, postal, is it, where it could subscribe to these events  that are happening, but I haven't gone down that road.  Anybody use postal?  I never see many hands on that.  Congratulations, Gil.  You're the only one.  What's that?  I haven't heard of postbox.  Okay.  Postbox is apparently similar.  Nonetheless, what you see up here is if I look at any one of these files that are making  the Ajax calls, for instance, Ajax calls for the deal.  Here we go.  What you find are one-liners because all I really need to define is the endpoint and  pass the data in.  Then I delegate everything to that Ajax service that I've set up.  By the way, all that I'm showing you here, this is, again, this is something that isn't  provided by Knockout.  It's not provided by Durandal.  This is my own creation here.  If I were using Angular, Angular has their own opinions on how to do this.  You can use their resource service, for instance, to just go in and say, all right, by convention,  I created a RESTful API.  If I followed the general pragmatic REST principles, then my URIs are going to be set up in a way  that Angular makes it super easy to be able to do all of this.  I spent a lot of time designing this.  I'm really happy with how it worked out because, as you can see, every time we stand up a new  Ajax call, all I have to do is define a get or a put, put in the URI and pass in the data,  and it just works.  The promises happen, and the UI does what it should, and I get the data back serialized  like I'd like it to.  That's pretty handy.  Put the business logic on the server rather than the client.  This is one of the other reasons that we aren't doing all our math on the client, was even  if I minify and obfuscate it, somebody could go back and put all those little shredded pieces  of paper back together, and effectively they have our application.  Or maybe they don't even want to understand it.  They can just copy and paste the whole thing and go host it elsewhere, and now they have  a working solution because all they really need is a server on one side to provide some  data.  So we put everything we can over on the server in our spa, and making Ajax calls is not particularly  expensive, so err on that side.  Another thing to consider, how do I inject data from the server into my JavaScript on  page load?  And what I'm highlighting there is what I call the JavaScript configuration object pattern,  and I don't have a slide on it, but if I pull up, let me do this.  I'd help if I could type it.  There I am.  I've got a blog post on this that really sums it up.  And the idea of the configuration object pattern is to take any data that the server  knows that's needed on the client, send that data down on page load.  If you know the client is going to need it, get it down there fast.  And so let's go down here, and here's the example.  Imagine that I have a single code base that's used by a bunch of different customers, and  I have Google Analytics within there.  I need to inject a different key for every single one of those customers.  So I have all this static JavaScript sitting right here, and then this is the only thing  that changes this one line right here, the Google Analytics key.  Now the way that some people would want to solve this is go onto the server and then  write all your JavaScript in one big string and then inject that variable from the database,  right?  And how many people have done that?  That's a pretty common pattern.  And it's problematic for a number of reasons.  Now let me get to the solution first because we're pretty tight on time.  Ultimately if you go into here instead and write all your JavaScript is just plain old  JavaScript, put it in a JS file, then you can inject JSON into your page by using a  JavaScript serializer in your language of choice.  And C-sharp, I use the JavaScript serializer, there's JSON.net, whatever you want to use.  Ultimately you want to take an object on your server, serialize it to JSON, spit it into  the header of your page.  And this is a pattern that's used all over the web.  For instance, if I go to Google right now, you'll find, boy they have a lot going on,  I think an easier example is if I go to Stack Overflow and look at their source, what you'll  find is they do the same thing.  If I go into here, you'll see stackexchange.net.  So they're using what I call the JavaScript configuration object pattern to set all these  things that are specific to me.  The locale, off URL, all that is used by their JavaScript to make the application work.  So have your server send down the knowledge that it knows right up front.  And these are all the benefits of it.  You separate your concerns, you get caching, you're minimizing your string parsing overhead.  It is really painful trying to read JavaScript that isn't code colored and syntax checked  when you make those typos.  You're forcing somebody, if you write it on the server in a big string, then you're forcing  somebody to think in terms of, okay, well, let's see, you're writing in Java or you're  writing in C sharp, but this is a string that's ultimately going to be JavaScript.  So these escape characters won't get sent down.  And yeah, I don't have coloring, but I can see what you're doing.  It becomes really hard to maintain and understand.  So how do we organize all this JavaScript and HTML?  Well compose small views and models.  And that's what we saw.  That's why we broke it down to almost 100 different files.  Other than that one really large view model, most of our view models are 50-ish lines of  code and most of our views are 50, 100 lines of HTML.  They're solving small problems well.  And the beauty of that is when I come over here and look at the app and we say, okay,  there's, where's the app go?  There's a bug right here under recent deals.  Then I know what I need to do is come back over here and open recent deals or recent  desks.html, the fact that it's named wrong is a separate political argument that I lost,  but we won't get into that.  And so you notice how small this is because this view is just handling that little tiny  section right there that was listing the recent deals.  So it gets really easy to quickly come in and I go, okay, well there's something wrong  with the JavaScript.  Well I know that's going to be in recent desks.js because that's the corresponding view model  for this view.  So here's the little bit of view model.  And as you can see, it's a really small view model because there's not much logic here.  You can load a desk, you can toggle whether it's showing, and you can determine whether  the heading's visible.  So, it's pretty simple stuff going on there.  Durandal lets you compose views within other views.  This is one of the really cool, powerful pieces of Durandal.  And it's something that it does, I feel like, better than Angular right now.  But Angular has some interesting things that it only does right now too.  Angular's directives are really cool.  And if you're anybody familiar with web components, next year a lot more people will be raising  their hands.  That's the direction that things are going.  Web components are something that Angular's basically shimming in right now with their  idea of directives.  So it's a really powerful way to be able to remove the cruft in your code and think  at a higher level of abstraction.  So instead of having div, div, div, div, and then ul and all this, I can define that top  level item with a tag name.  For instance, if all those divs ultimately came together to be a voting button, then  I could put the tag in as voting button.  And all that stuff inside would just get thrown in.  So pretty powerful idea.  How do I avoid repeating myself?  Have your server send everything down and then just use what your server did because your  server can handle all this stuff.  Don't go defining empty objects for your spa on the client.  Have your server send down what's called a null object and empty object and then you  can use that empty object throughout your application if you, for instance, need to  add another row, that sort of thing.  We want to have time to get to this movement.  This is a really interesting conversation, though, about the style of JavaScript development  over time.  Ultimately, we are in a new era, though, and this era is data binding.  This old idea of unattrusive JavaScript.  It ended up there were some real problems with it.  If I was using unattrusive JavaScript, I could not have built this application.  It would have fallen down on itself and it would not have been maintainable.  So data binding is, at the moment, the most promising future that we have.  And it's definitely made things easier.  And I won't go into this, but download the slides.  You can see the difference here, though, that really the three different eras here.  Dating, data binding is the way that we are writing JavaScript.  Now I'm going to skip to the end here.  Does building a spa even make sense?  Well, not if you have proprietary business logic that you have to put down on the client  or very little interactivity, slow page load.  Ultimately, if the page is really called, then it's probably the wrong approach.  It can also be a real pain to debug.  There's a lot of downsides to doing single-page development.  So if you don't need to, then I don't recommend doing it.  You really need to be able to justify that a spa is the right approach.  Now there are some good reasons why, though.  It's very responsive.  You can really get awesome interactivity.  You can separate your concerns.  And it's very, very simple.  There are less abstractions in some ways over the code because you're sending down the real  deal HTML.  And you don't have to worry about debugging, too.  That's one really nice thing.  If you have an application with a really slow build time, I didn't have to pay any of that  price because I was just playing in JavaScript plan.  It's just save and load, save and load.  So we built this very, very quickly.  And ultimately, don't single-page all the things.  This is the wrong mindset, right?  What we need to think about is pockets of single-page applications.  Look at your whole app and go, is there a place within this app where a single-page  app makes sense?  And our application is almost exclusively plain old web forms from way back when.  But this is a pocket of single-page applications where we really thought it made sense.  That's it.  I'll be glad to take questions.  Just come on up and visit.  There's a few Pluralsight cards left.  Thanks for listening.  Thank you.  Thank you.
Cory_House_-_Real_World_Single_Page_Apps__A_Knockout_Case_Study_0_3191.png Cory_House_-_Real_World_Single_Page_Apps__A_Knockout_Case_Study_3192_14147.png Cory_House_-_Real_World_Single_Page_Apps__A_Knockout_Case_Study_14148_15287.png Cory_House_-_Real_World_Single_Page_Apps__A_Knockout_Case_Study_15288_15335.png Cory_House_-_Real_World_Single_Page_Apps__A_Knockout_Case_Study_15336_15455.png Cory_House_-_Real_World_Single_Page_Apps__A_Knockout_Case_Study_15456_15683.png Cory_House_-_Real_World_Single_Page_Apps__A_Knockout_Case_Study_15684_15755.png Cory_House_-_Real_World_Single_Page_Apps__A_Knockout_Case_Study_15756_15863.png Cory_House_-_Real_World_Single_Page_Apps__A_Knockout_Case_Study_15864_16355.png Cory_House_-_Real_World_Single_Page_Apps__A_Knockout_Case_Study_16356_16595.png Cory_House_-_Real_World_Single_Page_Apps__A_Knockout_Case_Study_16596_16691.png Cory_House_-_Real_World_Single_Page_Apps__A_Knockout_Case_Study_16692_17195.png Cory_House_-_Real_World_Single_Page_Apps__A_Knockout_Case_Study_17196_17255.png Cory_House_-_Real_World_Single_Page_Apps__A_Knockout_Case_Study_17256_18011.png Cory_House_-_Real_World_Single_Page_Apps__A_Knockout_Case_Study_18012_18071.png Cory_House_-_Real_World_Single_Page_Apps__A_Knockout_Case_Study_18072_18779.png Cory_House_-_Real_World_Single_Page_Apps__A_Knockout_Case_Study_18780_20711.png Cory_House_-_Real_World_Single_Page_Apps__A_Knockout_Case_Study_20712_20807.png Cory_House_-_Real_World_Single_Page_Apps__A_Knockout_Case_Study_20808_21491.png Cory_House_-_Real_World_Single_Page_Apps__A_Knockout_Case_Study_21492_21803.png Cory_House_-_Real_World_Single_Page_Apps__A_Knockout_Case_Study_21804_23699.png Cory_House_-_Real_World_Single_Page_Apps__A_Knockout_Case_Study_23700_23975.png Cory_House_-_Real_World_Single_Page_Apps__A_Knockout_Case_Study_23976_24059.png Cory_House_-_Real_World_Single_Page_Apps__A_Knockout_Case_Study_24060_24119.png Cory_House_-_Real_World_Single_Page_Apps__A_Knockout_Case_Study_24120_24527.png Cory_House_-_Real_World_Single_Page_Apps__A_Knockout_Case_Study_24528_33335.png Cory_House_-_Real_World_Single_Page_Apps__A_Knockout_Case_Study_33336_33755.png Cory_House_-_Real_World_Single_Page_Apps__A_Knockout_Case_Study_33756_34019.png Cory_House_-_Real_World_Single_Page_Apps__A_Knockout_Case_Study_34020_34595.png Cory_House_-_Real_World_Single_Page_Apps__A_Knockout_Case_Study_34596_36467.png Cory_House_-_Real_World_Single_Page_Apps__A_Knockout_Case_Study_36468_36803.png Cory_House_-_Real_World_Single_Page_Apps__A_Knockout_Case_Study_36804_36875.png Cory_House_-_Real_World_Single_Page_Apps__A_Knockout_Case_Study_36876_39011.png Cory_House_-_Real_World_Single_Page_Apps__A_Knockout_Case_Study_39012_39059.png Cory_House_-_Real_World_Single_Page_Apps__A_Knockout_Case_Study_39060_39107.png Cory_House_-_Real_World_Single_Page_Apps__A_Knockout_Case_Study_39108_42035.png Cory_House_-_Real_World_Single_Page_Apps__A_Knockout_Case_Study_42036_42227.png Cory_House_-_Real_World_Single_Page_Apps__A_Knockout_Case_Study_42228_42347.png Cory_House_-_Real_World_Single_Page_Apps__A_Knockout_Case_Study_42348_42443.png Cory_House_-_Real_World_Single_Page_Apps__A_Knockout_Case_Study_42444_42539.png Cory_House_-_Real_World_Single_Page_Apps__A_Knockout_Case_Study_42540_43019.png Cory_House_-_Real_World_Single_Page_Apps__A_Knockout_Case_Study_43020_43115.png Cory_House_-_Real_World_Single_Page_Apps__A_Knockout_Case_Study_43116_43163.png Cory_House_-_Real_World_Single_Page_Apps__A_Knockout_Case_Study_43164_43571.png Cory_House_-_Real_World_Single_Page_Apps__A_Knockout_Case_Study_43572_43763.png Cory_House_-_Real_World_Single_Page_Apps__A_Knockout_Case_Study_43764_43823.png Cory_House_-_Real_World_Single_Page_Apps__A_Knockout_Case_Study_43824_43871.png Cory_House_-_Real_World_Single_Page_Apps__A_Knockout_Case_Study_43872_46283.png Cory_House_-_Real_World_Single_Page_Apps__A_Knockout_Case_Study_46284_47759.png Cory_House_-_Real_World_Single_Page_Apps__A_Knockout_Case_Study_47760_47987.png Cory_House_-_Real_World_Single_Page_Apps__A_Knockout_Case_Study_47988_48095.png Cory_House_-_Real_World_Single_Page_Apps__A_Knockout_Case_Study_48096_48575.png Cory_House_-_Real_World_Single_Page_Apps__A_Knockout_Case_Study_48576_48623.png Cory_House_-_Real_World_Single_Page_Apps__A_Knockout_Case_Study_48624_51419.png Cory_House_-_Real_World_Single_Page_Apps__A_Knockout_Case_Study_51420_51479.png Cory_House_-_Real_World_Single_Page_Apps__A_Knockout_Case_Study_51480_51527.png Cory_House_-_Real_World_Single_Page_Apps__A_Knockout_Case_Study_51528_51707.png Cory_House_-_Real_World_Single_Page_Apps__A_Knockout_Case_Study_51708_51767.png Cory_House_-_Real_World_Single_Page_Apps__A_Knockout_Case_Study_51768_53711.png Cory_House_-_Real_World_Single_Page_Apps__A_Knockout_Case_Study_53712_55331.png Cory_House_-_Real_World_Single_Page_Apps__A_Knockout_Case_Study_55332_55403.png Cory_House_-_Real_World_Single_Page_Apps__A_Knockout_Case_Study_55404_55463.png Cory_House_-_Real_World_Single_Page_Apps__A_Knockout_Case_Study_55464_55523.png Cory_House_-_Real_World_Single_Page_Apps__A_Knockout_Case_Study_55524_58559.png Cory_House_-_Real_World_Single_Page_Apps__A_Knockout_Case_Study_58560_59723.png Cory_House_-_Real_World_Single_Page_Apps__A_Knockout_Case_Study_59724_65519.png Cory_House_-_Real_World_Single_Page_Apps__A_Knockout_Case_Study_65520_73307.png Cory_House_-_Real_World_Single_Page_Apps__A_Knockout_Case_Study_73308_73367.png Cory_House_-_Real_World_Single_Page_Apps__A_Knockout_Case_Study_73368_75971.png Cory_House_-_Real_World_Single_Page_Apps__A_Knockout_Case_Study_75972_77639.png Cory_House_-_Real_World_Single_Page_Apps__A_Knockout_Case_Study_77640_79127.png Cory_House_-_Real_World_Single_Page_Apps__A_Knockout_Case_Study_79128_79667.png Cory_House_-_Real_World_Single_Page_Apps__A_Knockout_Case_Study_79668_79895.png Cory_House_-_Real_World_Single_Page_Apps__A_Knockout_Case_Study_79896_80867.png Cory_House_-_Real_World_Single_Page_Apps__A_Knockout_Case_Study_80868_81155.png Cory_House_-_Real_World_Single_Page_Apps__A_Knockout_Case_Study_81156_81671.png Cory_House_-_Real_World_Single_Page_Apps__A_Knockout_Case_Study_81672_82031.png Cory_House_-_Real_World_Single_Page_Apps__A_Knockout_Case_Study_82032_82403.png Cory_House_-_Real_World_Single_Page_Apps__A_Knockout_Case_Study_82404_84035.png Cory_House_-_Real_World_Single_Page_Apps__A_Knockout_Case_Study_84036_84095.png Cory_House_-_Real_World_Single_Page_Apps__A_Knockout_Case_Study_84096_84203.png Cory_House_-_Real_World_Single_Page_Apps__A_Knockout_Case_Study_84204_84359.png Cory_House_-_Real_World_Single_Page_Apps__A_Knockout_Case_Study_84360_85295.png Cory_House_-_Real_World_Single_Page_Apps__A_Knockout_Case_Study_85296_88607.png Cory_House_-_Real_World_Single_Page_Apps__A_Knockout_Case_Study_88608_91115.png Cory_House_-_Real_World_Single_Page_Apps__A_Knockout_Case_Study_91116_92801.png