[Script Info] Title: [Events] Format: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text Dialogue: 0,0:00:18.33,0:00:18.95,Default,,0000,0000,0000,,LUKE MELIA: All right, folks. Dialogue: 0,0:00:18.95,0:00:24.04,Default,,0000,0000,0000,,Thanks for coming out. So you are at Lightning\NFast Dialogue: 0,0:00:24.04,0:00:26.18,Default,,0000,0000,0000,,Deployment of Your Rails-Baked Javascript\NAPP. Dialogue: 0,0:00:26.18,0:00:29.35,Default,,0000,0000,0000,,Hopefully you're in the right place. Dialogue: 0,0:00:29.35,0:00:32.37,Default,,0000,0000,0000,,My name is Luke. I, Luke Melia. I live Dialogue: 0,0:00:32.37,0:00:35.54,Default,,0000,0000,0000,,in Manhattan in New York City. Got a couple Dialogue: 0,0:00:35.54,0:00:39.14,Default,,0000,0000,0000,,little girls who are learning Ruby and Javascript\Nusing Dialogue: 0,0:00:39.14,0:00:44.05,Default,,0000,0000,0000,,Code Academy and KidsRuby. And I have a company Dialogue: 0,0:00:44.05,0:00:46.98,Default,,0000,0000,0000,,called Yapp that I co-founded. We're one of\Nthese Dialogue: 0,0:00:46.98,0:00:51.11,Default,,0000,0000,0000,,kind of hybrid product and consulting companies.\NAnd when Dialogue: 0,0:00:51.11,0:00:54.08,Default,,0000,0000,0000,,I'm not doing Dad stuff or coding, I really Dialogue: 0,0:00:54.08,0:00:57.00,Default,,0000,0000,0000,,love to play beach volleyball and have recently\Ntaken Dialogue: 0,0:00:57.00,0:00:58.81,Default,,0000,0000,0000,,up parkour. Dialogue: 0,0:00:58.81,0:01:01.55,Default,,0000,0000,0000,,So Yapp Labs is the consulting side of our Dialogue: 0,0:01:01.55,0:01:04.29,Default,,0000,0000,0000,,business. We do Ember.js consulting and training\Nbased out Dialogue: 0,0:01:04.29,0:01:08.00,Default,,0000,0000,0000,,of New York and Seattle, if, if that's interesting, Dialogue: 0,0:01:08.00,0:01:09.90,Default,,0000,0000,0000,,happy to talk with you about that. Dialogue: 0,0:01:09.90,0:01:12.85,Default,,0000,0000,0000,,So, by way of introducing this topic, I want Dialogue: 0,0:01:12.85,0:01:16.13,Default,,0000,0000,0000,,to tell you a story. And it's a story Dialogue: 0,0:01:16.13,0:01:21.84,Default,,0000,0000,0000,,of when deployments were driving me crazy.\NYou know, Dialogue: 0,0:01:21.84,0:01:24.53,Default,,0000,0000,0000,,kind of like, tear my hair out crazy. Dialogue: 0,0:01:24.53,0:01:27.39,Default,,0000,0000,0000,,We had an app, and the app consisted, you Dialogue: 0,0:01:27.39,0:01:29.28,Default,,0000,0000,0000,,know, it was pretty straightforward for a\Nmodern app. Dialogue: 0,0:01:29.28,0:01:30.51,Default,,0000,0000,0000,,And it was a Rails app that had a Dialogue: 0,0:01:30.51,0:01:33.51,Default,,0000,0000,0000,,home page. It had your terms and conditions\Npage. Dialogue: 0,0:01:33.51,0:01:35.57,Default,,0000,0000,0000,,You can't have a site without that. It had Dialogue: 0,0:01:35.57,0:01:38.45,Default,,0000,0000,0000,,a Javascript app, which in this case was an Dialogue: 0,0:01:38.45,0:01:40.66,Default,,0000,0000,0000,,Ember app, but, you know, you can substitute\Nany Dialogue: 0,0:01:40.66,0:01:44.28,Default,,0000,0000,0000,,kind of rich Javascript MVC app that you,\Nstyle Dialogue: 0,0:01:44.28,0:01:46.68,Default,,0000,0000,0000,,you'd like, for the purposes of this talk.\NI Dialogue: 0,0:01:46.68,0:01:49.45,Default,,0000,0000,0000,,then, of course, had a JSON API. Dialogue: 0,0:01:49.45,0:01:50.96,Default,,0000,0000,0000,,And so these, this was kind of the bullet Dialogue: 0,0:01:50.96,0:01:53.87,Default,,0000,0000,0000,,points, but in terms of the amount of code, Dialogue: 0,0:01:53.87,0:01:55.28,Default,,0000,0000,0000,,the complexity, and how much time that it\Ntook Dialogue: 0,0:01:55.28,0:01:57.87,Default,,0000,0000,0000,,working on it, it was more like this, right. Dialogue: 0,0:01:57.87,0:02:00.09,Default,,0000,0000,0000,,We had a lot of work on the Javascript Dialogue: 0,0:02:00.09,0:02:02.41,Default,,0000,0000,0000,,app. Some, a bunch more in the JSON API. Dialogue: 0,0:02:02.41,0:02:04.44,Default,,0000,0000,0000,,And the rest of the site was, you know, Dialogue: 0,0:02:04.44,0:02:07.20,Default,,0000,0000,0000,,pretty trivial. Dialogue: 0,0:02:07.20,0:02:09.47,Default,,0000,0000,0000,,But in terms of deployments, every time we\Nwanted Dialogue: 0,0:02:09.47,0:02:11.84,Default,,0000,0000,0000,,to, every time I made a change and wanted Dialogue: 0,0:02:11.84,0:02:15.34,Default,,0000,0000,0000,,to deploy it, we would package everything\Nup and Dialogue: 0,0:02:15.34,0:02:18.43,Default,,0000,0000,0000,,deploy it. And so I have a question for Dialogue: 0,0:02:18.43,0:02:21.26,Default,,0000,0000,0000,,you folks. Hopefully everybody's, in the room\Nhas worked Dialogue: 0,0:02:21.26,0:02:22.93,Default,,0000,0000,0000,,with Rails. How long does it take to deploy Dialogue: 0,0:02:22.93,0:02:24.93,Default,,0000,0000,0000,,a Rails app? We're gonna do a show of Dialogue: 0,0:02:24.93,0:02:26.95,Default,,0000,0000,0000,,hands, and by the end, I hope everybody will Dialogue: 0,0:02:26.95,0:02:28.96,Default,,0000,0000,0000,,have their Rails app, sorry, will have their\Nhands Dialogue: 0,0:02:28.96,0:02:29.80,Default,,0000,0000,0000,,up. Dialogue: 0,0:02:29.80,0:02:32.48,Default,,0000,0000,0000,,And so, please start by raising your hand\Nif Dialogue: 0,0:02:32.48,0:02:34.73,Default,,0000,0000,0000,,your Rails app is deployed in less than thirty Dialogue: 0,0:02:34.73,0:02:37.89,Default,,0000,0000,0000,,seconds. OK. Good awesome. One, I want to\Ntalk Dialogue: 0,0:02:37.89,0:02:42.00,Default,,0000,0000,0000,,with you later. How about less than one minute? Dialogue: 0,0:02:42.00,0:02:47.00,Default,,0000,0000,0000,,Cool. A few folks. Less than three minutes?\NA Dialogue: 0,0:02:47.00,0:02:50.52,Default,,0000,0000,0000,,bunch more. Less than five minutes? Keep,\Nkeep your Dialogue: 0,0:02:50.52,0:02:51.73,Default,,0000,0000,0000,,hands up even if you were in the early Dialogue: 0,0:02:51.73,0:02:53.06,Default,,0000,0000,0000,,group. Less than five minutes. Dialogue: 0,0:02:53.06,0:02:56.07,Default,,0000,0000,0000,,OK, so we're probably at a majority now. Less Dialogue: 0,0:02:56.07,0:03:01.75,Default,,0000,0000,0000,,than ten minutes? Keep your hands up. OK.\NAnd Dialogue: 0,0:03:01.75,0:03:03.57,Default,,0000,0000,0000,,less than twenty minutes? I hope that's everybody\Nin Dialogue: 0,0:03:03.57,0:03:06.58,Default,,0000,0000,0000,,the room. Please, please, mercy. OK. Cool. Dialogue: 0,0:03:06.58,0:03:09.65,Default,,0000,0000,0000,,So, the, I think the, the answer is, it Dialogue: 0,0:03:09.65,0:03:11.18,Default,,0000,0000,0000,,takes at least a few minutes to deploy a Dialogue: 0,0:03:11.18,0:03:14.03,Default,,0000,0000,0000,,Rails app, unless you're one of an exceptional\Nfew Dialogue: 0,0:03:14.03,0:03:16.92,Default,,0000,0000,0000,,folks in the audience. And I get it. There's Dialogue: 0,0:03:16.92,0:03:19.53,Default,,0000,0000,0000,,a lot, you know, there's files to transfer.\NThere's Dialogue: 0,0:03:19.53,0:03:22.98,Default,,0000,0000,0000,,dependencies to install. Most modern Rails\Napps, you know, Dialogue: 0,0:03:22.98,0:03:25.01,Default,,0000,0000,0000,,that I run into, that we create, have a Dialogue: 0,0:03:25.01,0:03:28.15,Default,,0000,0000,0000,,lot of gem dependencies. It takes some time\Nto Dialogue: 0,0:03:28.15,0:03:30.52,Default,,0000,0000,0000,,boot the app with all those dependencies and\Njust Dialogue: 0,0:03:30.52,0:03:33.09,Default,,0000,0000,0000,,with, just with your app code. Dialogue: 0,0:03:33.09,0:03:35.62,Default,,0000,0000,0000,,And so, that's fine, except for, I was going Dialogue: 0,0:03:35.62,0:03:38.76,Default,,0000,0000,0000,,days just working on the Javascript app. Right,\NI Dialogue: 0,0:03:38.76,0:03:41.95,Default,,0000,0000,0000,,was just making changes in Javascript, and\Nevery time Dialogue: 0,0:03:41.95,0:03:44.77,Default,,0000,0000,0000,,I wanted to deploy, I was waiting five minutes Dialogue: 0,0:03:44.77,0:03:50.54,Default,,0000,0000,0000,,in our case to just deploy static Javascript\Nchanges. Dialogue: 0,0:03:50.54,0:03:52.05,Default,,0000,0000,0000,,And it really made me want to throw something Dialogue: 0,0:03:52.05,0:03:53.96,Default,,0000,0000,0000,,across the room. Why was I doing this to Dialogue: 0,0:03:53.96,0:03:55.03,Default,,0000,0000,0000,,myself? Dialogue: 0,0:03:55.03,0:03:58.51,Default,,0000,0000,0000,,And it wasn't just me that I was annoying. Dialogue: 0,0:03:58.51,0:04:02.43,Default,,0000,0000,0000,,I was also annoying our users, because, in\Nmost, Dialogue: 0,0:04:02.43,0:04:06.68,Default,,0000,0000,0000,,in most Rails deployment scenarios, there\Nare some, there Dialogue: 0,0:04:06.68,0:04:09.20,Default,,0000,0000,0000,,can be some hiccups in each deploy. And we'll, Dialogue: 0,0:04:09.20,0:04:11.23,Default,,0000,0000,0000,,so let's talk a little bit about this, this Dialogue: 0,0:04:11.23,0:04:16.34,Default,,0000,0000,0000,,kind of hiccups and deployments and zero downtime\Ndeploys. Dialogue: 0,0:04:16.34,0:04:19.06,Default,,0000,0000,0000,,So if your Rails app takes several seconds\Nto Dialogue: 0,0:04:19.06,0:04:22.45,Default,,0000,0000,0000,,boot, which is probably about average, obviously\Nit can't Dialogue: 0,0:04:22.45,0:04:25.83,Default,,0000,0000,0000,,serve requests during that time. And so, under\Nhigh Dialogue: 0,0:04:25.83,0:04:28.65,Default,,0000,0000,0000,,load in most architectures, most requesters\Nare just gonna Dialogue: 0,0:04:28.65,0:04:30.62,Default,,0000,0000,0000,,be queued, waiting for the app to be ready Dialogue: 0,0:04:30.62,0:04:34.09,Default,,0000,0000,0000,,to handle requests. And then once it boots\Nup, Dialogue: 0,0:04:34.09,0:04:37.14,Default,,0000,0000,0000,,it's gonna start handling those requests,\Nand eventually flush Dialogue: 0,0:04:37.14,0:04:41.04,Default,,0000,0000,0000,,that queue and hopefully catch up to the requests Dialogue: 0,0:04:41.04,0:04:43.21,Default,,0000,0000,0000,,as they're coming in. Dialogue: 0,0:04:43.21,0:04:45.92,Default,,0000,0000,0000,,And so users that are hitting the, hitting\Nyour Dialogue: 0,0:04:45.92,0:04:49.14,Default,,0000,0000,0000,,app during this time may experience at, at\Nbest Dialogue: 0,0:04:49.14,0:04:51.29,Default,,0000,0000,0000,,case just a couple of seconds of downtime.\NAt Dialogue: 0,0:04:51.29,0:04:52.89,Default,,0000,0000,0000,,worst case, kind of a feeling like that, that Dialogue: 0,0:04:52.89,0:04:55.33,Default,,0000,0000,0000,,this site is not responsive. Dialogue: 0,0:04:55.33,0:04:57.52,Default,,0000,0000,0000,,And so it disappoints me that we don't yet Dialogue: 0,0:04:57.52,0:05:01.80,Default,,0000,0000,0000,,have a kind of conventional solution for zero\Ndowntime Dialogue: 0,0:05:01.80,0:05:03.99,Default,,0000,0000,0000,,deploys. But it kind of makes sense because,\Nby Dialogue: 0,0:05:03.99,0:05:08.49,Default,,0000,0000,0000,,definition, Rails runs inside of other web\Nservers, and Dialogue: 0,0:05:08.49,0:05:10.55,Default,,0000,0000,0000,,so, and that, this is really a concern kind Dialogue: 0,0:05:10.55,0:05:11.89,Default,,0000,0000,0000,,of at that web server layer. Dialogue: 0,0:05:11.89,0:05:15.30,Default,,0000,0000,0000,,So, Heroku, for example, has an experimental\Nsolution. Heroku Dialogue: 0,0:05:15.30,0:05:20.33,Default,,0000,0000,0000,,Labs is, Heroku's kind of unsupported experimental\Narea features. Dialogue: 0,0:05:20.33,0:05:23.54,Default,,0000,0000,0000,,And you can run heroku labs:enable preboot,\Nwhich will Dialogue: 0,0:05:23.54,0:05:25.83,Default,,0000,0000,0000,,start up new servers or dynos with your new Dialogue: 0,0:05:25.83,0:05:28.67,Default,,0000,0000,0000,,code, wait three minutes to give your Rails\Napp Dialogue: 0,0:05:28.67,0:05:30.98,Default,,0000,0000,0000,,plenty of time to boot, and then switch traffic Dialogue: 0,0:05:30.98,0:05:32.65,Default,,0000,0000,0000,,over. Dialogue: 0,0:05:32.65,0:05:36.68,Default,,0000,0000,0000,,For, if you're using Puma or Unicorn, there\Nare Dialogue: 0,0:05:36.68,0:05:39.42,Default,,0000,0000,0000,,facilities to start one worker at a time,\Nor Dialogue: 0,0:05:39.42,0:05:42.17,Default,,0000,0000,0000,,groups of workers by sending signals to the\Nmaster Dialogue: 0,0:05:42.17,0:05:45.02,Default,,0000,0000,0000,,process. HAProxy is a tool that I've used\Nin Dialogue: 0,0:05:45.02,0:05:48.23,Default,,0000,0000,0000,,the past to kind of split traffic, give yourself Dialogue: 0,0:05:48.23,0:05:52.39,Default,,0000,0000,0000,,time to boot up another, another set of servers. Dialogue: 0,0:05:52.39,0:05:54.50,Default,,0000,0000,0000,,HAProxy is nice because you can do health\Nchecks Dialogue: 0,0:05:54.50,0:05:57.15,Default,,0000,0000,0000,,against those new servers and say, am I ready Dialogue: 0,0:05:57.15,0:06:02.29,Default,,0000,0000,0000,,to deploy? And Passenger also has some solutions\Naround Dialogue: 0,0:06:02.29,0:06:04.59,Default,,0000,0000,0000,,this. Dialogue: 0,0:06:04.59,0:06:06.34,Default,,0000,0000,0000,,In terms of kind of the full scope of Dialogue: 0,0:06:06.34,0:06:08.62,Default,,0000,0000,0000,,zero downtime stuff, it gets more complicated\Nwhen you Dialogue: 0,0:06:08.62,0:06:12.57,Default,,0000,0000,0000,,talk about database migrations and what's\Nsafe and what's Dialogue: 0,0:06:12.57,0:06:16.43,Default,,0000,0000,0000,,not safe for these, these types of, these\Ntypes Dialogue: 0,0:06:16.43,0:06:18.95,Default,,0000,0000,0000,,of deployments. And I'm happy to chat about\Nthat Dialogue: 0,0:06:18.95,0:06:21.04,Default,,0000,0000,0000,,with anybody later, but that's out of scope\Nfor, Dialogue: 0,0:06:21.04,0:06:22.73,Default,,0000,0000,0000,,for this particular talk. Dialogue: 0,0:06:22.73,0:06:24.36,Default,,0000,0000,0000,,What I do want to drill into a little Dialogue: 0,0:06:24.36,0:06:28.08,Default,,0000,0000,0000,,bit is issues with static assets and zero\Ndowntime Dialogue: 0,0:06:28.08,0:06:30.22,Default,,0000,0000,0000,,deploys, because that's the thing that was,\Nyou know, Dialogue: 0,0:06:30.22,0:06:31.59,Default,,0000,0000,0000,,kind of at the heart of what I was Dialogue: 0,0:06:31.59,0:06:35.10,Default,,0000,0000,0000,,doing, was really dealing with these static\NJavascript assets. Dialogue: 0,0:06:35.10,0:06:37.54,Default,,0000,0000,0000,,And I think that these issues aren't discussed\Noften. Dialogue: 0,0:06:37.54,0:06:38.84,Default,,0000,0000,0000,,So I kind of want to drill down, kind Dialogue: 0,0:06:38.84,0:06:41.48,Default,,0000,0000,0000,,of at a detailed level, and talk about them Dialogue: 0,0:06:41.48,0:06:43.42,Default,,0000,0000,0000,,here. Dialogue: 0,0:06:43.42,0:06:46.28,Default,,0000,0000,0000,,So when a browser makes an initial request\Nto Dialogue: 0,0:06:46.28,0:06:49.48,Default,,0000,0000,0000,,your server for, to load your, your rich Javascript Dialogue: 0,0:06:49.48,0:06:52.10,Default,,0000,0000,0000,,app, it's loading the index dot html file\Nand Dialogue: 0,0:06:52.10,0:06:54.90,Default,,0000,0000,0000,,by index.html, I'm gonna refer to the html\Nfile Dialogue: 0,0:06:54.90,0:06:58.09,Default,,0000,0000,0000,,that's the bootstrapping, it's bootstrapping\Nyour Javascript app. It's Dialogue: 0,0:06:58.09,0:07:00.07,Default,,0000,0000,0000,,the thing that has a little bit of code Dialogue: 0,0:07:00.07,0:07:01.63,Default,,0000,0000,0000,,to fire things up and it pulls in the Dialogue: 0,0:07:01.63,0:07:03.84,Default,,0000,0000,0000,,right Javascript and CSS assets. Dialogue: 0,0:07:03.84,0:07:06.19,Default,,0000,0000,0000,,So the request comes into your servers, your\Nserver Dialogue: 0,0:07:06.19,0:07:09.68,Default,,0000,0000,0000,,responds with the HTML file, with the text\Nslash Dialogue: 0,0:07:09.68,0:07:13.58,Default,,0000,0000,0000,,html mine type, and typically the, your asset\Nfiles, Dialogue: 0,0:07:13.58,0:07:15.73,Default,,0000,0000,0000,,the Javascript and CSS that are gonna be referenced Dialogue: 0,0:07:15.73,0:07:19.48,Default,,0000,0000,0000,,here, are gonna be fingerprinted. Right, so\Nwe do, Dialogue: 0,0:07:19.48,0:07:21.70,Default,,0000,0000,0000,,take a hash of the contents of the Javascript Dialogue: 0,0:07:21.70,0:07:24.91,Default,,0000,0000,0000,,file, we set it as a, we include that Dialogue: 0,0:07:24.91,0:07:27.41,Default,,0000,0000,0000,,hash in the file name, and we're then are Dialogue: 0,0:07:27.41,0:07:30.15,Default,,0000,0000,0000,,able to set far features expires headers on\Nthose Dialogue: 0,0:07:30.15,0:07:32.52,Default,,0000,0000,0000,,files, so that when the file changes, we don't Dialogue: 0,0:07:32.52,0:07:35.81,Default,,0000,0000,0000,,have to worry about cache expire or anything.\NWe Dialogue: 0,0:07:35.81,0:07:38.75,Default,,0000,0000,0000,,just gotta new file that's gonna come through\Nas Dialogue: 0,0:07:38.75,0:07:41.18,Default,,0000,0000,0000,,if the browser's never seen it before. Dialogue: 0,0:07:41.18,0:07:43.60,Default,,0000,0000,0000,,And so in this case, our html file might Dialogue: 0,0:07:43.60,0:07:47.60,Default,,0000,0000,0000,,contain something like assets slash app dash\Nabc123 dot Dialogue: 0,0:07:47.60,0:07:51.78,Default,,0000,0000,0000,,js, where abc123 is this fingerprint we're\Ntalking about. Dialogue: 0,0:07:51.78,0:07:54.83,Default,,0000,0000,0000,,And so the browser takes that html, parses\Nthe Dialogue: 0,0:07:54.83,0:07:57.47,Default,,0000,0000,0000,,page, a short time later makes the request\Nfor Dialogue: 0,0:07:57.47,0:08:01.55,Default,,0000,0000,0000,,app dash abc123. Server says, here you go,\Nsome Dialogue: 0,0:08:01.55,0:08:05.33,Default,,0000,0000,0000,,text Javascript. Browser parses that, boots\Nup the app. Dialogue: 0,0:08:05.33,0:08:06.37,Default,,0000,0000,0000,,All is well. Dialogue: 0,0:08:06.37,0:08:08.85,Default,,0000,0000,0000,,Hopefully this is very clear to everybody\Nwho's in Dialogue: 0,0:08:08.85,0:08:12.03,Default,,0000,0000,0000,,the room. What's maybe less clear, unless\Nyou've thought Dialogue: 0,0:08:12.03,0:08:14.74,Default,,0000,0000,0000,,about it in detail is that during deployments,\Nthis Dialogue: 0,0:08:14.74,0:08:17.30,Default,,0000,0000,0000,,idea can break down a little bit. And so Dialogue: 0,0:08:17.30,0:08:20.46,Default,,0000,0000,0000,,imagine that we've got our deployment and\Nwe've got Dialogue: 0,0:08:20.46,0:08:23.32,Default,,0000,0000,0000,,two kind of sets of server. The top set Dialogue: 0,0:08:23.32,0:08:25.30,Default,,0000,0000,0000,,that we're looking at here on the screen is Dialogue: 0,0:08:25.30,0:08:27.75,Default,,0000,0000,0000,,the existing code. The bottom set is the new Dialogue: 0,0:08:27.75,0:08:29.87,Default,,0000,0000,0000,,code that you're deploying. Dialogue: 0,0:08:29.87,0:08:31.02,Default,,0000,0000,0000,,And in this case, there's a change to the Dialogue: 0,0:08:31.02,0:08:35.08,Default,,0000,0000,0000,,Javascript file, so there's the new fingerprinted\Nfilename there. Dialogue: 0,0:08:35.08,0:08:38.12,Default,,0000,0000,0000,,So when our initial request for our page comes Dialogue: 0,0:08:38.12,0:08:40.83,Default,,0000,0000,0000,,in, it was, it will go to the old Dialogue: 0,0:08:40.83,0:08:43.02,Default,,0000,0000,0000,,code, because we haven't yet switched traffic\Nover to Dialogue: 0,0:08:43.02,0:08:46.89,Default,,0000,0000,0000,,the, to the new deploy. And just like in Dialogue: 0,0:08:46.89,0:08:49.21,Default,,0000,0000,0000,,our first example, it's gonna come back with\Nthe Dialogue: 0,0:08:49.21,0:08:54.22,Default,,0000,0000,0000,,index file references app dash abc123 dot\Njs. Dialogue: 0,0:08:54.22,0:08:56.49,Default,,0000,0000,0000,,Now, what if, in that moment, where, as the Dialogue: 0,0:08:56.49,0:08:59.71,Default,,0000,0000,0000,,page is being parsed, before this request\Ncomes back, Dialogue: 0,0:08:59.71,0:09:02.00,Default,,0000,0000,0000,,we then switch traffic over to pointing to\Nthe Dialogue: 0,0:09:02.00,0:09:05.51,Default,,0000,0000,0000,,new server? Well, request is gonna come in\Nfor Dialogue: 0,0:09:05.51,0:09:09.06,Default,,0000,0000,0000,,app dash abc123 dot js, the new server gets Dialogue: 0,0:09:09.06,0:09:11.64,Default,,0000,0000,0000,,the request and says, ah, I don't know what Dialogue: 0,0:09:11.64,0:09:13.95,Default,,0000,0000,0000,,you're talking about. I don't have a Javascript\Nfile Dialogue: 0,0:09:13.95,0:09:18.23,Default,,0000,0000,0000,,with that name. And so it says, 404 Not Dialogue: 0,0:09:18.23,0:09:18.90,Default,,0000,0000,0000,,Found. Dialogue: 0,0:09:18.90,0:09:24.13,Default,,0000,0000,0000,,And this is a challenging problem to, to address, Dialogue: 0,0:09:24.13,0:09:26.24,Default,,0000,0000,0000,,because there's a, because of a few reasons.\NOne Dialogue: 0,0:09:26.24,0:09:28.28,Default,,0000,0000,0000,,is that most simply if I, at this point, Dialogue: 0,0:09:28.28,0:09:30.90,Default,,0000,0000,0000,,now hit refresh in the browser, of course\Neverything Dialogue: 0,0:09:30.90,0:09:33.46,Default,,0000,0000,0000,,works fine. Right, because now both of those\Nrequests Dialogue: 0,0:09:33.46,0:09:35.38,Default,,0000,0000,0000,,are going to the new server and the world Dialogue: 0,0:09:35.38,0:09:36.20,Default,,0000,0000,0000,,is good. Dialogue: 0,0:09:36.20,0:09:39.64,Default,,0000,0000,0000,,It can be further kind of shadowed, this issue, Dialogue: 0,0:09:39.64,0:09:43.09,Default,,0000,0000,0000,,because, if you are serving your assets up\Nthrough Dialogue: 0,0:09:43.09,0:09:46.00,Default,,0000,0000,0000,,an assets host at CBN, you might have some, Dialogue: 0,0:09:46.00,0:09:48.73,Default,,0000,0000,0000,,some, some of their, your edge nodes might\Nhave Dialogue: 0,0:09:48.73,0:09:51.51,Default,,0000,0000,0000,,that old page cached. That old Javascript\Ncached. In Dialogue: 0,0:09:51.51,0:09:54.45,Default,,0000,0000,0000,,which case, those nodes will return it just\Nfine. Dialogue: 0,0:09:54.45,0:09:57.85,Default,,0000,0000,0000,,And so, to, to know that you're, you know, Dialogue: 0,0:09:57.85,0:10:00.91,Default,,0000,0000,0000,,totally impervious to this, you know, might\Nbe a Dialogue: 0,0:10:00.91,0:10:02.62,Default,,0000,0000,0000,,little bit fuzzy, and also to be able to Dialogue: 0,0:10:02.62,0:10:05.35,Default,,0000,0000,0000,,reproduce it reliably is a challenging thing\Nto do. Dialogue: 0,0:10:05.35,0:10:08.32,Default,,0000,0000,0000,,But, in short, to avoid these hiccups, both\Nthe Dialogue: 0,0:10:08.32,0:10:10.66,Default,,0000,0000,0000,,old versions of your assets and the new versions Dialogue: 0,0:10:10.66,0:10:12.42,Default,,0000,0000,0000,,have to be available for at least a few Dialogue: 0,0:10:12.42,0:10:15.67,Default,,0000,0000,0000,,minutes during your deployment in order to,\Nto make Dialogue: 0,0:10:15.67,0:10:19.45,Default,,0000,0000,0000,,this zero downtime approach really work well\Non the Dialogue: 0,0:10:19.45,0:10:21.73,Default,,0000,0000,0000,,static asset front. Dialogue: 0,0:10:21.73,0:10:23.33,Default,,0000,0000,0000,,And so this was one of the things I Dialogue: 0,0:10:23.33,0:10:25.67,Default,,0000,0000,0000,,was thinking about during these many five\Nminute deploys, Dialogue: 0,0:10:25.67,0:10:29.54,Default,,0000,0000,0000,,where I was, you know, wishing that I had Dialogue: 0,0:10:29.54,0:10:32.34,Default,,0000,0000,0000,,a solution. And so, in thinking about that,\NI Dialogue: 0,0:10:32.34,0:10:34.04,Default,,0000,0000,0000,,said, well, we could figure out how to do Dialogue: 0,0:10:34.04,0:10:35.81,Default,,0000,0000,0000,,this on our app servers. Kind of keep the Dialogue: 0,0:10:35.81,0:10:38.83,Default,,0000,0000,0000,,old versions of the, of the Javascript and\Nthe Dialogue: 0,0:10:38.83,0:10:40.61,Default,,0000,0000,0000,,new versions together. Or we could move the\Nassets Dialogue: 0,0:10:40.61,0:10:43.22,Default,,0000,0000,0000,,elsewhere. And the idea of moving the assets\Nelsewhere Dialogue: 0,0:10:43.22,0:10:45.78,Default,,0000,0000,0000,,really appealed to me, because that meant,\Nif they Dialogue: 0,0:10:45.78,0:10:47.87,Default,,0000,0000,0000,,weren't on the Rails, my Rails servers, then\Nmaybe Dialogue: 0,0:10:47.87,0:10:50.06,Default,,0000,0000,0000,,I could avoid doing Rails deploys when I just Dialogue: 0,0:10:50.06,0:10:52.58,Default,,0000,0000,0000,,had static asset changes. Dialogue: 0,0:10:52.58,0:10:55.14,Default,,0000,0000,0000,,So I started to sketch out an idea. We've Dialogue: 0,0:10:55.14,0:10:56.58,Default,,0000,0000,0000,,got our Rails server at the top, and we Dialogue: 0,0:10:56.58,0:10:59.22,Default,,0000,0000,0000,,had this separate static asset server at the\Nbottom. Dialogue: 0,0:10:59.22,0:11:01.59,Default,,0000,0000,0000,,Let's deploy our Rails app code to the Rails Dialogue: 0,0:11:01.59,0:11:05.86,Default,,0000,0000,0000,,servers, our Javascript, CSS, and images to\Nthese static Dialogue: 0,0:11:05.86,0:11:08.80,Default,,0000,0000,0000,,assets servers, and then we would deploy our\Nindex Dialogue: 0,0:11:08.80,0:11:13.07,Default,,0000,0000,0000,,file. Where would we deploy our index file? Dialogue: 0,0:11:13.07,0:11:14.88,Default,,0000,0000,0000,,And so, I started to think about, well, what Dialogue: 0,0:11:14.88,0:11:16.00,Default,,0000,0000,0000,,is the index file? It is kind of this Dialogue: 0,0:11:16.00,0:11:18.24,Default,,0000,0000,0000,,thing that bridges the two? What are the requirements Dialogue: 0,0:11:18.24,0:11:20.49,Default,,0000,0000,0000,,around it? What do we know about it? And Dialogue: 0,0:11:20.49,0:11:24.07,Default,,0000,0000,0000,,this index, the html file points to fingerprinted\NJavascript Dialogue: 0,0:11:24.07,0:11:27.25,Default,,0000,0000,0000,,and CSS, but it's not fingerprinted itself.\NThat's obviously Dialogue: 0,0:11:27.25,0:11:30.60,Default,,0000,0000,0000,,important, because it needs to be at, at a Dialogue: 0,0:11:30.60,0:11:34.53,Default,,0000,0000,0000,,consistent location for browsers to locate,\Nto load. It Dialogue: 0,0:11:34.53,0:11:38.26,Default,,0000,0000,0000,,contains Javascript urls and code to boot\Nthe Javascript Dialogue: 0,0:11:38.26,0:11:40.47,Default,,0000,0000,0000,,app to load CSS and such in the right Dialogue: 0,0:11:40.47,0:11:44.08,Default,,0000,0000,0000,,order. It's a good place to provide environment-specific\Nconfiguration Dialogue: 0,0:11:44.08,0:11:46.96,Default,,0000,0000,0000,,to Javascript. Maybe you have some differences\Nbetween dev Dialogue: 0,0:11:46.96,0:11:49.52,Default,,0000,0000,0000,,and stage in production. Dialogue: 0,0:11:49.52,0:11:51.15,Default,,0000,0000,0000,,One thing that I knew was key, because I Dialogue: 0,0:11:51.15,0:11:53.25,Default,,0000,0000,0000,,had struggled with it, is that when you serve Dialogue: 0,0:11:53.25,0:11:55.48,Default,,0000,0000,0000,,this html off of the same domain as your Dialogue: 0,0:11:55.48,0:11:59.09,Default,,0000,0000,0000,,API, life is way simpler with respect to cores Dialogue: 0,0:11:59.09,0:12:03.91,Default,,0000,0000,0000,,and cross origin security issues. And finally,\Nif I Dialogue: 0,0:12:03.91,0:12:06.14,Default,,0000,0000,0000,,wanted, if you wanted to be able to deploy Dialogue: 0,0:12:06.14,0:12:08.92,Default,,0000,0000,0000,,changes quickly to your users, caching on\Nthis particular Dialogue: 0,0:12:08.92,0:12:11.96,Default,,0000,0000,0000,,page should be minimal to none, so that you Dialogue: 0,0:12:11.96,0:12:14.81,Default,,0000,0000,0000,,can pretty instantly switch over. Dialogue: 0,0:12:14.81,0:12:17.92,Default,,0000,0000,0000,,So my conclusion, from thinking about this,\Nis that Dialogue: 0,0:12:17.92,0:12:20.19,Default,,0000,0000,0000,,the html page ideally should be managed and\Nthought Dialogue: 0,0:12:20.19,0:12:23.29,Default,,0000,0000,0000,,about as part of your static asset deployment\Nprocess, Dialogue: 0,0:12:23.29,0:12:25.35,Default,,0000,0000,0000,,but it should be served off of your Rails Dialogue: 0,0:12:25.35,0:12:26.24,Default,,0000,0000,0000,,server. Dialogue: 0,0:12:26.24,0:12:28.72,Default,,0000,0000,0000,,And, as importantly, it should be served off\Nyour Dialogue: 0,0:12:28.72,0:12:33.21,Default,,0000,0000,0000,,Rails server without requiring a Rails reboot\Nor redeploying Dialogue: 0,0:12:33.21,0:12:36.76,Default,,0000,0000,0000,,the entire Rails app. And so, so we were Dialogue: 0,0:12:36.76,0:12:39.00,Default,,0000,0000,0000,,able to start to refine this sketch and say, Dialogue: 0,0:12:39.00,0:12:41.62,Default,,0000,0000,0000,,OK, our Rails server's gonna be serving up\Nour Dialogue: 0,0:12:41.62,0:12:45.10,Default,,0000,0000,0000,,API requests, our, kind of, traditional, dynamic\NRails pages Dialogue: 0,0:12:45.10,0:12:47.16,Default,,0000,0000,0000,,as part of the html for a Javascript app, Dialogue: 0,0:12:47.16,0:12:49.49,Default,,0000,0000,0000,,and our static asset server's gonna be serving\Nup Dialogue: 0,0:12:49.49,0:12:51.86,Default,,0000,0000,0000,,the Javascript, CSS and images. Dialogue: 0,0:12:51.86,0:12:53.74,Default,,0000,0000,0000,,And so that means we need to somehow deploy Dialogue: 0,0:12:53.74,0:12:58.52,Default,,0000,0000,0000,,our html up to the Rails server without a Dialogue: 0,0:12:58.52,0:13:00.36,Default,,0000,0000,0000,,full, a full reboot. And so, how could we Dialogue: 0,0:13:00.36,0:13:01.07,Default,,0000,0000,0000,,do this? Dialogue: 0,0:13:01.07,0:13:03.40,Default,,0000,0000,0000,,Well, the most obvious thing to me was, well, Dialogue: 0,0:13:03.40,0:13:06.33,Default,,0000,0000,0000,,take a html file and put it on the Dialogue: 0,0:13:06.33,0:13:09.59,Default,,0000,0000,0000,,file system of each Rails server. And this\Nhas Dialogue: 0,0:13:09.59,0:13:11.61,Default,,0000,0000,0000,,a few things that aren't great about it. You Dialogue: 0,0:13:11.61,0:13:15.31,Default,,0000,0000,0000,,can probably make this work in some configurations.\NIn Dialogue: 0,0:13:15.31,0:13:19.37,Default,,0000,0000,0000,,many deployment environments, disk is ephemeral,\Nand so relying Dialogue: 0,0:13:19.37,0:13:22.29,Default,,0000,0000,0000,,on, you know, on copying some things up might Dialogue: 0,0:13:22.29,0:13:24.12,Default,,0000,0000,0000,,not be a great idea. It's also a little Dialogue: 0,0:13:24.12,0:13:27.44,Default,,0000,0000,0000,,bit weird to mix assets, files deployed from\Na Dialogue: 0,0:13:27.44,0:13:31.03,Default,,0000,0000,0000,,particular gitshaw, with files deployed from\Nsomewhere else, kind Dialogue: 0,0:13:31.03,0:13:33.70,Default,,0000,0000,0000,,of in the same file system. Dialogue: 0,0:13:33.70,0:13:35.45,Default,,0000,0000,0000,,And so, we said, well, what if there's something Dialogue: 0,0:13:35.45,0:13:37.78,Default,,0000,0000,0000,,that we could all see and talk to? Well, Dialogue: 0,0:13:37.78,0:13:40.90,Default,,0000,0000,0000,,what about uploading to S3? So then all the Dialogue: 0,0:13:40.90,0:13:44.86,Default,,0000,0000,0000,,Rails servers can, can see S3, read from it, Dialogue: 0,0:13:44.86,0:13:47.01,Default,,0000,0000,0000,,be able to serve up that html. And this Dialogue: 0,0:13:47.01,0:13:48.93,Default,,0000,0000,0000,,could kind of work, but reading from S3 is Dialogue: 0,0:13:48.93,0:13:52.31,Default,,0000,0000,0000,,a little bit slow. And we wanted this page Dialogue: 0,0:13:52.31,0:13:55.79,Default,,0000,0000,0000,,to be fast, obviously. No Javascript or CSS\Nis Dialogue: 0,0:13:55.79,0:13:57.93,Default,,0000,0000,0000,,gonna start being loaded until this page is\Nloaded Dialogue: 0,0:13:57.93,0:13:59.79,Default,,0000,0000,0000,,in the browser. And so the fastest we could, Dialogue: 0,0:13:59.79,0:14:01.06,Default,,0000,0000,0000,,the faster we could get this page to the Dialogue: 0,0:14:01.06,0:14:03.37,Default,,0000,0000,0000,,user, the better. Dialogue: 0,0:14:03.37,0:14:05.62,Default,,0000,0000,0000,,And so, then we said, well, what about redis? Dialogue: 0,0:14:05.62,0:14:09.56,Default,,0000,0000,0000,,Redis is persistent. It's fast. For us, it\Nwas Dialogue: 0,0:14:09.56,0:14:13.19,Default,,0000,0000,0000,,already in our environment. We liked this\Nidea a Dialogue: 0,0:14:13.19,0:14:16.00,Default,,0000,0000,0000,,lot. We decided to, to dig in. This is Dialogue: 0,0:14:16.00,0:14:17.75,Default,,0000,0000,0000,,not the, as you'll see, this is not the Dialogue: 0,0:14:17.75,0:14:21.03,Default,,0000,0000,0000,,only way to do it. It's totally possible to Dialogue: 0,0:14:21.03,0:14:23.75,Default,,0000,0000,0000,,user other systems besides redis. But redis\Nkind of Dialogue: 0,0:14:23.75,0:14:26.96,Default,,0000,0000,0000,,firt the bill for us and works quite well, Dialogue: 0,0:14:26.96,0:14:27.71,Default,,0000,0000,0000,,as you'll see. Dialogue: 0,0:14:27.71,0:14:29.88,Default,,0000,0000,0000,,So, the general idea was we're gonna deploy\Ninto Dialogue: 0,0:14:29.88,0:14:32.49,Default,,0000,0000,0000,,redis and then serve out of redis via a Dialogue: 0,0:14:32.49,0:14:35.96,Default,,0000,0000,0000,,Rails controller. So here's the simplest possible\Nkind of Dialogue: 0,0:14:35.96,0:14:39.47,Default,,0000,0000,0000,,deploy code that we had. It's a rig task, Dialogue: 0,0:14:39.47,0:14:42.76,Default,,0000,0000,0000,,and we're going to generate our html for the Dialogue: 0,0:14:42.76,0:14:46.38,Default,,0000,0000,0000,,current assets, and that's, that's kind of\Nan exercise Dialogue: 0,0:14:46.38,0:14:48.11,Default,,0000,0000,0000,,for your build tooling, which we'll talk about\Na Dialogue: 0,0:14:48.11,0:14:50.44,Default,,0000,0000,0000,,little bit later. And then once we had this Dialogue: 0,0:14:50.44,0:14:52.09,Default,,0000,0000,0000,,html, we're actually going to set it as a, Dialogue: 0,0:14:52.09,0:14:56.03,Default,,0000,0000,0000,,at a, as a redis key-value store. So the Dialogue: 0,0:14:56.03,0:14:57.88,Default,,0000,0000,0000,,html is the value and the key would be Dialogue: 0,0:14:57.88,0:15:02.73,Default,,0000,0000,0000,,something well-known like jsapp colon index,\Nfor example. And, Dialogue: 0,0:15:02.73,0:15:04.84,Default,,0000,0000,0000,,and this is a redis connection that's connecting\Ndirectly Dialogue: 0,0:15:04.84,0:15:07.78,Default,,0000,0000,0000,,to your charted deployment environment. So\Nthat's staging more Dialogue: 0,0:15:07.78,0:15:10.44,Default,,0000,0000,0000,,production. Dialogue: 0,0:15:10.44,0:15:13.09,Default,,0000,0000,0000,,Once it's there in redis, our controller,\Nagain, the Dialogue: 0,0:15:13.09,0:15:16.47,Default,,0000,0000,0000,,most simplest version, is get the value out\Nof Dialogue: 0,0:15:16.47,0:15:21.35,Default,,0000,0000,0000,,redis. Render text.html. Now, when I first\Nlooked at, Dialogue: 0,0:15:21.35,0:15:22.91,Default,,0000,0000,0000,,looked at this code or wrote this code, I Dialogue: 0,0:15:22.91,0:15:24.41,Default,,0000,0000,0000,,said, is that gonna be served up with the Dialogue: 0,0:15:24.41,0:15:26.57,Default,,0000,0000,0000,,right mine type? Seems a little strange. And\Nit Dialogue: 0,0:15:26.57,0:15:29.92,Default,,0000,0000,0000,,turns out that, yes, if you do render text Dialogue: 0,0:15:29.92,0:15:33.07,Default,,0000,0000,0000,,and some string, Rails serves that up with\Ntext Dialogue: 0,0:15:33.07,0:15:36.69,Default,,0000,0000,0000,,slash html, if you don't specify. So, it's\Na Dialogue: 0,0:15:36.69,0:15:38.52,Default,,0000,0000,0000,,little, I think a little bit of a confusing Dialogue: 0,0:15:38.52,0:15:41.43,Default,,0000,0000,0000,,API, but it does what we want. Dialogue: 0,0:15:41.43,0:15:44.37,Default,,0000,0000,0000,,So, we can now continue to refine this approach. Dialogue: 0,0:15:44.37,0:15:46.37,Default,,0000,0000,0000,,We know we're deploying, when we need to deploy Dialogue: 0,0:15:46.37,0:15:49.16,Default,,0000,0000,0000,,Rails app code, we're doing a deployment to\Nour Dialogue: 0,0:15:49.16,0:15:52.37,Default,,0000,0000,0000,,Rails server. When we're deploying Javascript,\NCSS and images, Dialogue: 0,0:15:52.37,0:15:54.87,Default,,0000,0000,0000,,we're deploying to the static assets server,\Nand then Dialogue: 0,0:15:54.87,0:15:58.16,Default,,0000,0000,0000,,we're deploying html by connecting to redis\Nand deploying Dialogue: 0,0:15:58.16,0:15:59.43,Default,,0000,0000,0000,,into it. Dialogue: 0,0:15:59.43,0:16:03.43,Default,,0000,0000,0000,,And we can make things a little bit nicer Dialogue: 0,0:16:03.43,0:16:06.52,Default,,0000,0000,0000,,by dropping cloud front right in front of,\Nby Dialogue: 0,0:16:06.52,0:16:08.81,Default,,0000,0000,0000,,using S3 as our static assets server, and\Nthen Dialogue: 0,0:16:08.81,0:16:10.94,Default,,0000,0000,0000,,dropping cloud front instead of in front of\Nour, Dialogue: 0,0:16:10.94,0:16:13.35,Default,,0000,0000,0000,,in front of S3. So, for very little effort Dialogue: 0,0:16:13.35,0:16:15.62,Default,,0000,0000,0000,,and very little money, we've got now CBN distribution Dialogue: 0,0:16:15.62,0:16:18.17,Default,,0000,0000,0000,,for our static assets. Dialogue: 0,0:16:18.17,0:16:21.71,Default,,0000,0000,0000,,Now, there's a few things about this deployment\Nto Dialogue: 0,0:16:21.71,0:16:25.16,Default,,0000,0000,0000,,S3, in terms of making it fast. Getting a Dialogue: 0,0:16:25.16,0:16:28.72,Default,,0000,0000,0000,,file list from S3 can be somewhat expensive,\Nparticularly Dialogue: 0,0:16:28.72,0:16:31.84,Default,,0000,0000,0000,,the more files that you have. And so the Dialogue: 0,0:16:31.84,0:16:34.44,Default,,0000,0000,0000,,approach that we took was to generate a manifest Dialogue: 0,0:16:34.44,0:16:38.62,Default,,0000,0000,0000,,file of our current assets and store the copy Dialogue: 0,0:16:38.62,0:16:42.00,Default,,0000,0000,0000,,of that manifest on S3 so we, we're basically Dialogue: 0,0:16:42.00,0:16:44.50,Default,,0000,0000,0000,,gonna read the remote manifest, compare it\Nto our Dialogue: 0,0:16:44.50,0:16:46.31,Default,,0000,0000,0000,,local manifest, and know we only need to deploy Dialogue: 0,0:16:46.31,0:16:48.52,Default,,0000,0000,0000,,what's different. And so this means that if\NI Dialogue: 0,0:16:48.52,0:16:51.54,Default,,0000,0000,0000,,make one Javascript, one line of Javascript\Nchange, it's Dialogue: 0,0:16:51.54,0:16:54.51,Default,,0000,0000,0000,,just the file that that's concatenated into\Nthat needs Dialogue: 0,0:16:54.51,0:16:56.62,Default,,0000,0000,0000,,to be updated, and not all of my images Dialogue: 0,0:16:56.62,0:17:00.26,Default,,0000,0000,0000,,and CSS, as we're doing our deploy, our assets Dialogue: 0,0:17:00.26,0:17:02.11,Default,,0000,0000,0000,,deploy to S3. Dialogue: 0,0:17:02.11,0:17:05.26,Default,,0000,0000,0000,,Now, purging has been on our to-do list for Dialogue: 0,0:17:05.26,0:17:08.21,Default,,0000,0000,0000,,this architecture for quite a while, right.\NAfter a Dialogue: 0,0:17:08.21,0:17:12.00,Default,,0000,0000,0000,,deploy is successfully completed, we can,\Nin theory, remove Dialogue: 0,0:17:12.00,0:17:15.04,Default,,0000,0000,0000,,stuff from S3. We never really got around\Nto Dialogue: 0,0:17:15.04,0:17:17.96,Default,,0000,0000,0000,,that. Mostly because it's so incredibly cheap\Nto store Dialogue: 0,0:17:17.96,0:17:20.73,Default,,0000,0000,0000,,these small files on S3, so, still on our Dialogue: 0,0:17:20.73,0:17:23.64,Default,,0000,0000,0000,,to-do list. I would probably not recommend\Nyou prioritizing Dialogue: 0,0:17:23.64,0:17:26.84,Default,,0000,0000,0000,,it too high for yourself. The code for this Dialogue: 0,0:17:26.84,0:17:29.73,Default,,0000,0000,0000,,S3 sink is here at this link. I will Dialogue: 0,0:17:29.73,0:17:31.40,Default,,0000,0000,0000,,make these slides available. You don't have\Nto worry Dialogue: 0,0:17:31.40,0:17:34.10,Default,,0000,0000,0000,,about copying it down. This repo is open source Dialogue: 0,0:17:34.10,0:17:35.57,Default,,0000,0000,0000,,and contains a lot of the code that we're Dialogue: 0,0:17:35.57,0:17:37.86,Default,,0000,0000,0000,,looking at today. And it's the actual code\Nthat Dialogue: 0,0:17:37.86,0:17:41.17,Default,,0000,0000,0000,,we use for our, for our production environments. Dialogue: 0,0:17:41.17,0:17:45.23,Default,,0000,0000,0000,,So, once you start thinking about this architecture,\Nit Dialogue: 0,0:17:45.23,0:17:47.80,Default,,0000,0000,0000,,paves the way to do something a little bit Dialogue: 0,0:17:47.80,0:17:50.12,Default,,0000,0000,0000,,more fundamental with your rich Javascript\Napp and your Dialogue: 0,0:17:50.12,0:17:53.18,Default,,0000,0000,0000,,Rails app, which is that you pull them, tease Dialogue: 0,0:17:53.18,0:17:56.18,Default,,0000,0000,0000,,them apart into separate repositories. And\Nnow why would Dialogue: 0,0:17:56.18,0:17:57.34,Default,,0000,0000,0000,,you want to do that? Dialogue: 0,0:17:57.34,0:17:59.47,Default,,0000,0000,0000,,Well, one of the reasons is, you know, thinking Dialogue: 0,0:17:59.47,0:18:02.29,Default,,0000,0000,0000,,about tagging, do, you know, kind of tagging\Na Dialogue: 0,0:18:02.29,0:18:04.84,Default,,0000,0000,0000,,deployed version of your code. Since you've\Ngot these Dialogue: 0,0:18:04.84,0:18:08.36,Default,,0000,0000,0000,,independent deploy processes, it makes sense\Nto be able Dialogue: 0,0:18:08.36,0:18:11.23,Default,,0000,0000,0000,,to tag a Javascript deploy separate from a\NRails Dialogue: 0,0:18:11.23,0:18:13.56,Default,,0000,0000,0000,,deploy, because they really are now independent\Nof each Dialogue: 0,0:18:13.56,0:18:14.62,Default,,0000,0000,0000,,other. Dialogue: 0,0:18:14.62,0:18:17.68,Default,,0000,0000,0000,,And I find also that thinking of your Javascript Dialogue: 0,0:18:17.68,0:18:21.57,Default,,0000,0000,0000,,app as a separate, independent client of your\NAPI, Dialogue: 0,0:18:21.57,0:18:22.85,Default,,0000,0000,0000,,works really well. Kind of puts it on the Dialogue: 0,0:18:22.85,0:18:25.25,Default,,0000,0000,0000,,same level as a native app, for example, maybe Dialogue: 0,0:18:25.25,0:18:26.77,Default,,0000,0000,0000,,if you've got an iPhone app that communicates\Nto Dialogue: 0,0:18:26.77,0:18:29.29,Default,,0000,0000,0000,,your API as well. Dialogue: 0,0:18:29.29,0:18:33.29,Default,,0000,0000,0000,,It also opens up the realm of possibility\Nto Dialogue: 0,0:18:33.29,0:18:35.03,Default,,0000,0000,0000,,having a lot of flexibility with what kind\Nof Dialogue: 0,0:18:35.03,0:18:37.20,Default,,0000,0000,0000,,build tools you want to use with your Javascript Dialogue: 0,0:18:37.20,0:18:40.90,Default,,0000,0000,0000,,app. You may choose to use sprockets in your Dialogue: 0,0:18:40.90,0:18:44.12,Default,,0000,0000,0000,,separate standalone repo. Or you may choose\Nto use Dialogue: 0,0:18:44.12,0:18:49.12,Default,,0000,0000,0000,,grunt, gulp, broccoli, brunch. You name it,\Nthere's obviously Dialogue: 0,0:18:49.12,0:18:52.51,Default,,0000,0000,0000,,a lot of innovation and creativity happening\Naround build Dialogue: 0,0:18:52.51,0:18:55.62,Default,,0000,0000,0000,,tools in the Javascript environment. And my\Nguess would Dialogue: 0,0:18:55.62,0:18:59.37,Default,,0000,0000,0000,,be that you're, we're gonna see faster, you\Nknow, Dialogue: 0,0:18:59.37,0:19:03.75,Default,,0000,0000,0000,,innovation, iteration in the Javascript environment\Nfor building Javascript Dialogue: 0,0:19:03.75,0:19:06.02,Default,,0000,0000,0000,,apps than we will in the Ruby environment\Nfor Dialogue: 0,0:19:06.02,0:19:07.34,Default,,0000,0000,0000,,building Javascript apps. Dialogue: 0,0:19:07.34,0:19:11.71,Default,,0000,0000,0000,,So, we've now got an approach that works pretty Dialogue: 0,0:19:11.71,0:19:14.70,Default,,0000,0000,0000,,well. But I think the, the question is, is Dialogue: 0,0:19:14.70,0:19:16.64,Default,,0000,0000,0000,,it worth doing the work to set this in Dialogue: 0,0:19:16.64,0:19:18.82,Default,,0000,0000,0000,,place? Like, how fast is this in the real Dialogue: 0,0:19:18.82,0:19:20.56,Default,,0000,0000,0000,,world? And so I took one of our apps, Dialogue: 0,0:19:20.56,0:19:22.98,Default,,0000,0000,0000,,and this isn't, was not a scientific bench\Nmark, Dialogue: 0,0:19:22.98,0:19:27.04,Default,,0000,0000,0000,,so consider it directional. And our builds\Ntook about Dialogue: 0,0:19:27.04,0:19:29.91,Default,,0000,0000,0000,,six and a half seconds. This particular app\Nis Dialogue: 0,0:19:29.91,0:19:31.67,Default,,0000,0000,0000,,using Rake Pipeline as a build tool for the Dialogue: 0,0:19:31.67,0:19:37.80,Default,,0000,0000,0000,,Javascript side. Our transferring assets to\NS3 using this Dialogue: 0,0:19:37.80,0:19:40.27,Default,,0000,0000,0000,,differential approach was about a second,\Nand then uploading Dialogue: 0,0:19:40.27,0:19:44.33,Default,,0000,0000,0000,,html into redis was about two and a half Dialogue: 0,0:19:44.33,0:19:47.65,Default,,0000,0000,0000,,seconds. And so, instead of a five minute\Ndeploy, Dialogue: 0,0:19:47.65,0:19:50.29,Default,,0000,0000,0000,,I was now able, we were now able to Dialogue: 0,0:19:50.29,0:19:53.76,Default,,0000,0000,0000,,deploy this, our Javascript apps in under\Nten seconds. Dialogue: 0,0:19:53.76,0:19:58.14,Default,,0000,0000,0000,,So just by that, that was a big win. Dialogue: 0,0:19:58.14,0:20:00.43,Default,,0000,0000,0000,,And stopped me from wanting to throw things\Nacross Dialogue: 0,0:20:00.43,0:20:03.15,Default,,0000,0000,0000,,the office. But, I think that, you know, in Dialogue: 0,0:20:03.15,0:20:06.62,Default,,0000,0000,0000,,any kind of architectural choices like this,\Nyou learn Dialogue: 0,0:20:06.62,0:20:09.20,Default,,0000,0000,0000,,if this is a good idea or not over Dialogue: 0,0:20:09.20,0:20:12.20,Default,,0000,0000,0000,,time, right, based on, how does, how does\Nthis Dialogue: 0,0:20:12.20,0:20:15.04,Default,,0000,0000,0000,,architecture respond to changes. What kind\Nof possibilities does Dialogue: 0,0:20:15.04,0:20:16.91,Default,,0000,0000,0000,,it enable? So I want to talk a little Dialogue: 0,0:20:16.91,0:20:19.64,Default,,0000,0000,0000,,bit about the kind of emergent behavior that\Nwe've Dialogue: 0,0:20:19.64,0:20:21.58,Default,,0000,0000,0000,,seen around, now that we've had this in production Dialogue: 0,0:20:21.58,0:20:23.58,Default,,0000,0000,0000,,for awhile. Dialogue: 0,0:20:23.58,0:20:26.24,Default,,0000,0000,0000,,The first thing is, the idea of preview. And Dialogue: 0,0:20:26.24,0:20:28.95,Default,,0000,0000,0000,,so this is an actual command line session\Nfor Dialogue: 0,0:20:28.95,0:20:31.93,Default,,0000,0000,0000,,deploying an app. In this case, it's yapp-prefs,\Nwhich Dialogue: 0,0:20:31.93,0:20:36.26,Default,,0000,0000,0000,,is our, kind of, account settings app. We\Nfirst Dialogue: 0,0:20:36.26,0:20:40.78,Default,,0000,0000,0000,,run rake dist. This is the build. And with Dialogue: 0,0:20:40.78,0:20:42.58,Default,,0000,0000,0000,,the build completes, in this case, as we saw Dialogue: 0,0:20:42.58,0:20:44.29,Default,,0000,0000,0000,,in the pie chart before, in about six seconds Dialogue: 0,0:20:44.29,0:20:47.60,Default,,0000,0000,0000,,or so. And it says, OK, to deploy these Dialogue: 0,0:20:47.60,0:20:52.53,Default,,0000,0000,0000,,assets to S3, run rake deploy:assets with\Nthis, what Dialogue: 0,0:20:52.53,0:20:55.07,Default,,0000,0000,0000,,we call a manifest idea, this b35b. Dialogue: 0,0:20:55.07,0:20:57.77,Default,,0000,0000,0000,,So what's a manifest id? We talked earlier\Nabout Dialogue: 0,0:20:57.77,0:21:00.82,Default,,0000,0000,0000,,fingerprinting assets and we talked about\Ncreating a manifest Dialogue: 0,0:21:00.82,0:21:03.29,Default,,0000,0000,0000,,file. So what we do also is we fingerprint Dialogue: 0,0:21:03.29,0:21:05.13,Default,,0000,0000,0000,,the manifest file. So we take a hash of Dialogue: 0,0:21:05.13,0:21:07.57,Default,,0000,0000,0000,,the contents of that manifest file and we\Nsay, Dialogue: 0,0:21:07.57,0:21:10.21,Default,,0000,0000,0000,,OK, that is the manifest id for this deploy. Dialogue: 0,0:21:10.21,0:21:12.25,Default,,0000,0000,0000,,And that's, it's, it's kind of a unique identifier Dialogue: 0,0:21:12.25,0:21:15.40,Default,,0000,0000,0000,,as it's going through its unique deploy process. Dialogue: 0,0:21:15.40,0:21:17.49,Default,,0000,0000,0000,,And so we run rake deploy:assets, which does\Nthe Dialogue: 0,0:21:17.49,0:21:20.58,Default,,0000,0000,0000,,differential upload to S3 and it's gonna show\Nus Dialogue: 0,0:21:20.58,0:21:23.03,Default,,0000,0000,0000,,what it uploads. It's gonna spit out, OK,\NI've Dialogue: 0,0:21:23.03,0:21:28.90,Default,,0000,0000,0000,,uploaded these four files. JS, CSS, two yaml\Nfiles Dialogue: 0,0:21:28.90,0:21:31.15,Default,,0000,0000,0000,,for the manifest. We, actually, these are\Ntwo copies Dialogue: 0,0:21:31.15,0:21:33.07,Default,,0000,0000,0000,,of the same thing. One is a, has a Dialogue: 0,0:21:33.07,0:21:35.14,Default,,0000,0000,0000,,file name with the id, and one just is, Dialogue: 0,0:21:35.14,0:21:38.47,Default,,0000,0000,0000,,hey I am the latest. And it's going to Dialogue: 0,0:21:38.47,0:21:40.99,Default,,0000,0000,0000,,then tell us the next command to run is Dialogue: 0,0:21:40.99,0:21:45.66,Default,,0000,0000,0000,,deploy:generate_index for this manifest id.\NAnd what this is Dialogue: 0,0:21:45.66,0:21:49.05,Default,,0000,0000,0000,,gonna do is going to connect to redis and Dialogue: 0,0:21:49.05,0:21:51.51,Default,,0000,0000,0000,,set this at a key named for the manifest Dialogue: 0,0:21:51.51,0:21:54.37,Default,,0000,0000,0000,,id. So in the previous simplistic example\Nwe looked Dialogue: 0,0:21:54.37,0:21:57.29,Default,,0000,0000,0000,,at, it was just updating jsapp index. Now\Nit's Dialogue: 0,0:21:57.29,0:21:59.78,Default,,0000,0000,0000,,updating a key at prefs, in this case, prefs:index Dialogue: 0,0:21:59.78,0:22:04.04,Default,,0000,0000,0000,,b35b something, you know, named for the manifest\Nid. Dialogue: 0,0:22:04.04,0:22:06.99,Default,,0000,0000,0000,,And why is this awesome? Well, this command\Nline Dialogue: 0,0:22:06.99,0:22:10.43,Default,,0000,0000,0000,,tool can now tell us, hey, to preview this, Dialogue: 0,0:22:10.43,0:22:12.61,Default,,0000,0000,0000,,this asset change, go ahead and take a look Dialogue: 0,0:22:12.61,0:22:16.51,Default,,0000,0000,0000,,at your at, your site with the query param Dialogue: 0,0:22:16.51,0:22:21.63,Default,,0000,0000,0000,,manifest id equals b35 et cetera. And what\Nthis Dialogue: 0,0:22:21.63,0:22:24.11,Default,,0000,0000,0000,,is gonna do is it's going to pull the Dialogue: 0,0:22:24.11,0:22:27.08,Default,,0000,0000,0000,,new html file from redis. Gonna show, which\Nis Dialogue: 0,0:22:27.08,0:22:29.90,Default,,0000,0000,0000,,loading up the new Javascript. It's connecting\Nto the Dialogue: 0,0:22:29.90,0:22:33.19,Default,,0000,0000,0000,,production API. So you're able to smoke test\Nthis Dialogue: 0,0:22:33.19,0:22:36.04,Default,,0000,0000,0000,,in production. Everything is working just\Nas the user Dialogue: 0,0:22:36.04,0:22:38.66,Default,,0000,0000,0000,,will see it, except for your users don't see Dialogue: 0,0:22:38.66,0:22:40.88,Default,,0000,0000,0000,,it yet. So if you screwed something up, you've Dialogue: 0,0:22:40.88,0:22:42.58,Default,,0000,0000,0000,,got a chance before kind of pulling the trigger Dialogue: 0,0:22:42.58,0:22:44.89,Default,,0000,0000,0000,,and switching it life to go. Dialogue: 0,0:22:44.89,0:22:47.72,Default,,0000,0000,0000,,And then, finally, one more command to kind\Nof Dialogue: 0,0:22:47.72,0:22:49.78,Default,,0000,0000,0000,,active that redis key and make it the current Dialogue: 0,0:22:49.78,0:22:53.66,Default,,0000,0000,0000,,key. And so what does this code look like? Dialogue: 0,0:22:53.66,0:22:55.52,Default,,0000,0000,0000,,It's actually not that much more complicated\Nthan what Dialogue: 0,0:22:55.52,0:22:59.20,Default,,0000,0000,0000,,we saw before. We invoke our rake task with Dialogue: 0,0:22:59.20,0:23:04.73,Default,,0000,0000,0000,,the manifest id. Generate our html file. And\Nthen, Dialogue: 0,0:23:04.73,0:23:07.55,Default,,0000,0000,0000,,instead of setting jsapp index, we'll set\Na jsapp Dialogue: 0,0:23:07.55,0:23:09.53,Default,,0000,0000,0000,,key based on the manifest name, or redis key Dialogue: 0,0:23:09.53,0:23:13.30,Default,,0000,0000,0000,,based on the manifest name. And then spit\Nout Dialogue: 0,0:23:13.30,0:23:15.70,Default,,0000,0000,0000,,something to give the developer the url to\Ntake Dialogue: 0,0:23:15.70,0:23:20.48,Default,,0000,0000,0000,,a look at, to preview, to preview the app. Dialogue: 0,0:23:20.48,0:23:23.41,Default,,0000,0000,0000,,On the server-side, we're gonna add one more\Nredis Dialogue: 0,0:23:23.41,0:23:27.53,Default,,0000,0000,0000,,request to the mix. If there's a manifest\Nid Dialogue: 0,0:23:27.53,0:23:30.90,Default,,0000,0000,0000,,param, then we'll just use that. If it's blank, Dialogue: 0,0:23:30.90,0:23:33.27,Default,,0000,0000,0000,,then we'll go and we'll connect to a current Dialogue: 0,0:23:33.27,0:23:35.51,Default,,0000,0000,0000,,key. Grab the manifest id, then use that to Dialogue: 0,0:23:35.51,0:23:40.07,Default,,0000,0000,0000,,serve up the current version of, of the site. Dialogue: 0,0:23:40.07,0:23:41.66,Default,,0000,0000,0000,,Of the, of this index file. Dialogue: 0,0:23:41.66,0:23:46.12,Default,,0000,0000,0000,,And so, that has been pretty powerful, and\Nit's, Dialogue: 0,0:23:46.12,0:23:48.32,Default,,0000,0000,0000,,it's a super useful tool that we use in Dialogue: 0,0:23:48.32,0:23:51.29,Default,,0000,0000,0000,,almost every single deploy. The developer's\Njust gonna do Dialogue: 0,0:23:51.29,0:23:53.79,Default,,0000,0000,0000,,a quick smoke test and say, yes, everything\Nlooks Dialogue: 0,0:23:53.79,0:23:56.43,Default,,0000,0000,0000,,good, before they flip the switch. Dialogue: 0,0:23:56.43,0:24:00.100,Default,,0000,0000,0000,,The next interesting aspect that this kind\Nof enabled Dialogue: 0,0:24:00.100,0:24:05.11,Default,,0000,0000,0000,,is around dynamic html rewriting. And so what\Nwe Dialogue: 0,0:24:05.11,0:24:08.75,Default,,0000,0000,0000,,realize is that as html was passing through\Nfrom Dialogue: 0,0:24:08.75,0:24:11.95,Default,,0000,0000,0000,,redis through the controller back to the browser,\Nwe Dialogue: 0,0:24:11.95,0:24:14.90,Default,,0000,0000,0000,,had the opportunity to make adjustments if\Nwe wanted Dialogue: 0,0:24:14.90,0:24:18.93,Default,,0000,0000,0000,,to. And one category of adjustment that we\Nended Dialogue: 0,0:24:18.93,0:24:22.26,Default,,0000,0000,0000,,up making, as you see in this example, is Dialogue: 0,0:24:22.26,0:24:24.89,Default,,0000,0000,0000,,injecting some information about the current\Nuser. Dialogue: 0,0:24:24.89,0:24:27.96,Default,,0000,0000,0000,,Now, obviously in a Rails controller we know\Ntypically Dialogue: 0,0:24:27.96,0:24:31.41,Default,,0000,0000,0000,,who the current user is. Most apps will have Dialogue: 0,0:24:31.41,0:24:35.10,Default,,0000,0000,0000,,a current_user method available to any controller\Nthat they Dialogue: 0,0:24:35.10,0:24:38.59,Default,,0000,0000,0000,,can, it can grab. In contrast, when you're\Nbooting Dialogue: 0,0:24:38.59,0:24:41.95,Default,,0000,0000,0000,,up a Javascript MVC app, at that point, you Dialogue: 0,0:24:41.95,0:24:44.16,Default,,0000,0000,0000,,know, most apps don't know who the current\Nuser Dialogue: 0,0:24:44.16,0:24:46.32,Default,,0000,0000,0000,,is. And if, in most, you know mostly there Dialogue: 0,0:24:46.32,0:24:49.33,Default,,0000,0000,0000,,is some XHR request that's involved in figuring\Nout, Dialogue: 0,0:24:49.33,0:24:51.50,Default,,0000,0000,0000,,is this user logged in and, if so, what Dialogue: 0,0:24:51.50,0:24:53.97,Default,,0000,0000,0000,,is their role in the system? And during that Dialogue: 0,0:24:53.97,0:24:56.87,Default,,0000,0000,0000,,time, the user is sitting there waiting, right.\NThe Dialogue: 0,0:24:56.87,0:24:58.100,Default,,0000,0000,0000,,Javascript is just kind of, maybe it's rendering\Na Dialogue: 0,0:24:58.100,0:25:01.89,Default,,0000,0000,0000,,loading spinner for the user or something.\NBut it's Dialogue: 0,0:25:01.89,0:25:04.49,Default,,0000,0000,0000,,a little bit annoying and it also makes the Dialogue: 0,0:25:04.49,0:25:07.80,Default,,0000,0000,0000,,boot process for the, for your Javascript\Napp more Dialogue: 0,0:25:07.80,0:25:08.18,Default,,0000,0000,0000,,complicated. Dialogue: 0,0:25:08.18,0:25:11.20,Default,,0000,0000,0000,,So we said, well what if the app could Dialogue: 0,0:25:11.20,0:25:15.13,Default,,0000,0000,0000,,have, at boot time, have access to this information? Dialogue: 0,0:25:15.13,0:25:17.60,Default,,0000,0000,0000,,So what we're doing here is, in the controller Dialogue: 0,0:25:17.60,0:25:20.51,Default,,0000,0000,0000,,action at the top, between the time we get Dialogue: 0,0:25:20.51,0:25:24.52,Default,,0000,0000,0000,,the html out of redis and return, render it, Dialogue: 0,0:25:24.52,0:25:27.67,Default,,0000,0000,0000,,we're going to inject current_user information.\NWe're gonna grab Dialogue: 0,0:25:27.67,0:25:31.92,Default,,0000,0000,0000,,the current_user and then user our AcitveModel\Nserializer to Dialogue: 0,0:25:31.92,0:25:35.25,Default,,0000,0000,0000,,convert it to JSON, escape it, and stick it Dialogue: 0,0:25:35.25,0:25:37.16,Default,,0000,0000,0000,,into the head tag. Dialogue: 0,0:25:37.16,0:25:39.69,Default,,0000,0000,0000,,And you'll notice that the method that we're\Nusing Dialogue: 0,0:25:39.69,0:25:42.72,Default,,0000,0000,0000,,to add this to the html, you might find Dialogue: 0,0:25:42.72,0:25:46.42,Default,,0000,0000,0000,,a little crude. And certainly when I first\Nstarted Dialogue: 0,0:25:46.42,0:25:48.72,Default,,0000,0000,0000,,doing this, I said, OK, we'll use Nokogiri.\NWe'll Dialogue: 0,0:25:48.72,0:25:51.80,Default,,0000,0000,0000,,parse the html. And then we'll insert, you\Nknow, Dialogue: 0,0:25:51.80,0:25:55.40,Default,,0000,0000,0000,,insert a node, and then we'll render, you\Nknow, Dialogue: 0,0:25:55.40,0:25:58.28,Default,,0000,0000,0000,,convert that back to text. And it turns out Dialogue: 0,0:25:58.28,0:26:00.89,Default,,0000,0000,0000,,that really what we're doing is so simple\Nthat, Dialogue: 0,0:26:00.89,0:26:02.93,Default,,0000,0000,0000,,as fast as Nokogiri is, and it's pretty fast Dialogue: 0,0:26:02.93,0:26:05.82,Default,,0000,0000,0000,,for an XML or html parser, it is not Dialogue: 0,0:26:05.82,0:26:08.76,Default,,0000,0000,0000,,faster than string manipulation and string\Nindexing. Dialogue: 0,0:26:08.76,0:26:10.83,Default,,0000,0000,0000,,And so, in this case, we're just looking at, Dialogue: 0,0:26:10.83,0:26:12.06,Default,,0000,0000,0000,,where's the end of the head tag or the Dialogue: 0,0:26:12.06,0:26:15.31,Default,,0000,0000,0000,,beginning of the head tag, inject this meta\Ntag Dialogue: 0,0:26:15.31,0:26:18.35,Default,,0000,0000,0000,,in there. And this works great. Dialogue: 0,0:26:18.35,0:26:20.74,Default,,0000,0000,0000,,The, some other use cases for this same approach Dialogue: 0,0:26:20.74,0:26:24.95,Default,,0000,0000,0000,,might be injecting csrf tokens if you, you\Nknow, Dialogue: 0,0:26:24.95,0:26:27.67,Default,,0000,0000,0000,,need to interact with Rails forms from, from\Nyour Dialogue: 0,0:26:27.67,0:26:32.31,Default,,0000,0000,0000,,Javascript app. Including dynamic analytics\Nparams, we had a Dialogue: 0,0:26:32.31,0:26:36.21,Default,,0000,0000,0000,,case where the, the Javascript app was kind\Nof Dialogue: 0,0:26:36.21,0:26:39.13,Default,,0000,0000,0000,,the, the, a goal page for a Google analytics Dialogue: 0,0:26:39.13,0:26:41.96,Default,,0000,0000,0000,,kind of flow. And we needed to set some, Dialogue: 0,0:26:41.96,0:26:45.22,Default,,0000,0000,0000,,certain Javascript only in some conditions.\NSo this was Dialogue: 0,0:26:45.22,0:26:46.50,Default,,0000,0000,0000,,a nice way to do that. Dialogue: 0,0:26:46.50,0:26:49.05,Default,,0000,0000,0000,,If you're using feature flags through something\Nlike the Dialogue: 0,0:26:49.05,0:26:53.98,Default,,0000,0000,0000,,excellent rollout gem, it's great that that's\Navailable throughout Dialogue: 0,0:26:53.98,0:26:55.45,Default,,0000,0000,0000,,Rails. But how do you make it available inside Dialogue: 0,0:26:55.45,0:26:57.79,Default,,0000,0000,0000,,of your Javascript app also, this is a nice Dialogue: 0,0:26:57.79,0:27:00.39,Default,,0000,0000,0000,,solution to be able to kind of inject variables Dialogue: 0,0:27:00.39,0:27:03.80,Default,,0000,0000,0000,,along those lines. Dialogue: 0,0:27:03.80,0:27:07.04,Default,,0000,0000,0000,,Another pretty awesome thing that we've been\Nable to Dialogue: 0,0:27:07.04,0:27:09.53,Default,,0000,0000,0000,,do using this approach is doing A/B testing\Nwithin Dialogue: 0,0:27:09.53,0:27:13.64,Default,,0000,0000,0000,,our Javascript app. And we've experimented\Nwith two different Dialogue: 0,0:27:13.64,0:27:17.22,Default,,0000,0000,0000,,kinds. One is, kind of, setting some flags\Nbased Dialogue: 0,0:27:17.22,0:27:19.84,Default,,0000,0000,0000,,on which bucket the user ends up in, A Dialogue: 0,0:27:19.84,0:27:23.36,Default,,0000,0000,0000,,or B. This is pretty similar to what we Dialogue: 0,0:27:23.36,0:27:26.95,Default,,0000,0000,0000,,just described. And then the, the second is\Nserving Dialogue: 0,0:27:26.95,0:27:29.60,Default,,0000,0000,0000,,up wholly different html based on the A/B\Nbucket. Dialogue: 0,0:27:29.60,0:27:33.25,Default,,0000,0000,0000,,We'll, I'll talk, take you through each of\Nthose. Dialogue: 0,0:27:33.25,0:27:36.86,Default,,0000,0000,0000,,So this is using the split gem, which, if Dialogue: 0,0:27:36.86,0:27:39.21,Default,,0000,0000,0000,,you haven't seen, is a great A/B tool, A/B Dialogue: 0,0:27:39.21,0:27:42.42,Default,,0000,0000,0000,,test tool for Ruby frameworks, web frameworks.\NIt has Dialogue: 0,0:27:42.42,0:27:45.59,Default,,0000,0000,0000,,a Rails integration that gives us the A/B\Ntest Dialogue: 0,0:27:45.59,0:27:48.62,Default,,0000,0000,0000,,method, which you see on line eleven there.\NAnd Dialogue: 0,0:27:48.62,0:27:52.47,Default,,0000,0000,0000,,so we're doing some injection into our html\Nwhere Dialogue: 0,0:27:52.47,0:27:54.65,Default,,0000,0000,0000,,we're saying, if the user is part of the Dialogue: 0,0:27:54.65,0:27:58.84,Default,,0000,0000,0000,,show walkthrough experiment, then we're going\Nto inject the Dialogue: 0,0:27:58.84,0:28:01.72,Default,,0000,0000,0000,,script tag that just sets a global variable.\NAnd Dialogue: 0,0:28:01.72,0:28:04.43,Default,,0000,0000,0000,,then our Javascript app as it boots in is Dialogue: 0,0:28:04.43,0:28:06.23,Default,,0000,0000,0000,,running, is, is, can consult that global variable\Nto Dialogue: 0,0:28:06.23,0:28:08.99,Default,,0000,0000,0000,,decide whether to show the walkthrough that\Nyou're doing, Dialogue: 0,0:28:08.99,0:28:10.09,Default,,0000,0000,0000,,doing some testing on. Dialogue: 0,0:28:10.09,0:28:13.76,Default,,0000,0000,0000,,And then later, elsewhere in your app, you\Nwould Dialogue: 0,0:28:13.76,0:28:16.83,Default,,0000,0000,0000,,indicate that, that the goal was achieved,\Nthat the Dialogue: 0,0:28:16.83,0:28:19.72,Default,,0000,0000,0000,,user signed up or published or whatever it\Nis Dialogue: 0,0:28:19.72,0:28:22.95,Default,,0000,0000,0000,,that was kind of the, the goal for you Dialogue: 0,0:28:22.95,0:28:25.83,Default,,0000,0000,0000,,A/B test. And so this was great. This is Dialogue: 0,0:28:25.83,0:28:28.25,Default,,0000,0000,0000,,excellent for the kinds of A/B tests where\Nboth Dialogue: 0,0:28:28.25,0:28:32.83,Default,,0000,0000,0000,,paths are supported by your, by a given incarnation Dialogue: 0,0:28:32.83,0:28:34.70,Default,,0000,0000,0000,,of your Javascript app. Dialogue: 0,0:28:34.70,0:28:38.65,Default,,0000,0000,0000,,We had another case, though, where, this was\Nright Dialogue: 0,0:28:38.65,0:28:41.26,Default,,0000,0000,0000,,around the time that iOS7 released and there\Nwas, Dialogue: 0,0:28:41.26,0:28:43.29,Default,,0000,0000,0000,,if you recall, there was a lot of excitement Dialogue: 0,0:28:43.29,0:28:46.39,Default,,0000,0000,0000,,in, around flat design. And so we did a Dialogue: 0,0:28:46.39,0:28:49.14,Default,,0000,0000,0000,,redesign of our Javascript app. We weren't\Nimmune to Dialogue: 0,0:28:49.14,0:28:54.56,Default,,0000,0000,0000,,the hype. And, but as we got near completion, Dialogue: 0,0:28:54.56,0:28:56.79,Default,,0000,0000,0000,,we started to wonder, well, we're gonna release\Nthis. Dialogue: 0,0:28:56.79,0:28:58.01,Default,,0000,0000,0000,,How do we know that this is any better Dialogue: 0,0:28:58.01,0:29:00.81,Default,,0000,0000,0000,,than our existing site? Is this going to improve Dialogue: 0,0:29:00.81,0:29:04.12,Default,,0000,0000,0000,,our metrics or hurt them? And we wanted to Dialogue: 0,0:29:04.12,0:29:06.13,Default,,0000,0000,0000,,try to get some confidence one way or the Dialogue: 0,0:29:06.13,0:29:06.77,Default,,0000,0000,0000,,other. Dialogue: 0,0:29:06.77,0:29:08.93,Default,,0000,0000,0000,,So we said, well, we've been developing this\Nin Dialogue: 0,0:29:08.93,0:29:10.95,Default,,0000,0000,0000,,a branch, and we already know that we can Dialogue: 0,0:29:10.95,0:29:13.67,Default,,0000,0000,0000,,preview different versions of our Javascript\Napp, because we Dialogue: 0,0:29:13.67,0:29:16.09,Default,,0000,0000,0000,,had this preview mechanism in place. Could\Nwe use Dialogue: 0,0:29:16.09,0:29:18.35,Default,,0000,0000,0000,,this for A/B testing, also? Dialogue: 0,0:29:18.35,0:29:21.25,Default,,0000,0000,0000,,And so, it turns out that we were able Dialogue: 0,0:29:21.25,0:29:23.84,Default,,0000,0000,0000,,to just update our deploy scripts to be able Dialogue: 0,0:29:23.84,0:29:27.45,Default,,0000,0000,0000,,to deploy from a branch into an experiment\Nkind Dialogue: 0,0:29:27.45,0:29:30.13,Default,,0000,0000,0000,,of redis key, and then use the same A/B Dialogue: 0,0:29:30.13,0:29:33.93,Default,,0000,0000,0000,,test mechanism to determine, for the new design\Nexperiment, Dialogue: 0,0:29:33.93,0:29:36.19,Default,,0000,0000,0000,,should the user use the current manifest or\Nthe Dialogue: 0,0:29:36.19,0:29:38.99,Default,,0000,0000,0000,,experimental manifest? Dialogue: 0,0:29:38.99,0:29:41.02,Default,,0000,0000,0000,,Once we made that decision, we then got the Dialogue: 0,0:29:41.02,0:29:45.44,Default,,0000,0000,0000,,appropriate manifest id from redis, got the\Nhtml, rendered Dialogue: 0,0:29:45.44,0:29:48.50,Default,,0000,0000,0000,,it, and users either saw our old app or Dialogue: 0,0:29:48.50,0:29:52.03,Default,,0000,0000,0000,,the new flat-design app. Turns out, flat design,\Nabout Dialogue: 0,0:29:52.03,0:29:55.92,Default,,0000,0000,0000,,nine percent better. So good news. Dialogue: 0,0:29:55.92,0:29:58.26,Default,,0000,0000,0000,,So this is suitable for changes where your\Ndevelopment's Dialogue: 0,0:29:58.26,0:30:00.21,Default,,0000,0000,0000,,capping at a branch, and you want to A/B Dialogue: 0,0:30:00.21,0:30:03.07,Default,,0000,0000,0000,,between the branches. Not a common scenario,\Nbut if Dialogue: 0,0:30:03.07,0:30:05.43,Default,,0000,0000,0000,,it's, when it's, it's useful, it was great\Nto Dialogue: 0,0:30:05.43,0:30:09.83,Default,,0000,0000,0000,,see how this approach supported that architecture. Dialogue: 0,0:30:09.83,0:30:11.96,Default,,0000,0000,0000,,One more possibility that I didn't cover here,\Nbut Dialogue: 0,0:30:11.96,0:30:16.76,Default,,0000,0000,0000,,you can imagine how this might work, is around Dialogue: 0,0:30:16.76,0:30:20.24,Default,,0000,0000,0000,,doing rollback. So what if every time that\Nwe Dialogue: 0,0:30:20.24,0:30:23.59,Default,,0000,0000,0000,,did this deploy and updated our html in redis Dialogue: 0,0:30:23.59,0:30:26.26,Default,,0000,0000,0000,,we pushed into a redis list and said, hey, Dialogue: 0,0:30:26.26,0:30:29.31,Default,,0000,0000,0000,,so and so user deployed such and such manifest Dialogue: 0,0:30:29.31,0:30:31.94,Default,,0000,0000,0000,,id at this time, and then we were able Dialogue: 0,0:30:31.94,0:30:33.98,Default,,0000,0000,0000,,to have a rake task that reads that list Dialogue: 0,0:30:33.98,0:30:37.30,Default,,0000,0000,0000,,and lets you rollback to any particular version.\NHopefully, Dialogue: 0,0:30:37.30,0:30:39.46,Default,,0000,0000,0000,,at this point, you can see how straightforward\Nthat Dialogue: 0,0:30:39.46,0:30:42.20,Default,,0000,0000,0000,,would, that kind of thing would be as well. Dialogue: 0,0:30:42.20,0:30:44.04,Default,,0000,0000,0000,,So, with that, I want to say thank you Dialogue: 0,0:30:44.04,0:30:47.41,Default,,0000,0000,0000,,to my colleagues at Yapp Labs who helped create Dialogue: 0,0:30:47.41,0:30:50.77,Default,,0000,0000,0000,,this. Kris Seldon, Stefan Penner and Ray Cohen.\NAnd Dialogue: 0,0:30:50.77,0:30:52.23,Default,,0000,0000,0000,,while we were working on this, we had heard Dialogue: 0,0:30:52.23,0:30:56.77,Default,,0000,0000,0000,,some rumors about some Square engineers doing\Na, using Dialogue: 0,0:30:56.77,0:30:59.37,Default,,0000,0000,0000,,a similar approach at Square. So we took some Dialogue: 0,0:30:59.37,0:31:01.90,Default,,0000,0000,0000,,inspiration from those rumors as well, and\Nso thank Dialogue: 0,0:31:01.90,0:31:05.21,Default,,0000,0000,0000,,you, nameless Square engineers, or if anybody's\Nhere. Love, Dialogue: 0,0:31:05.21,0:31:07.88,Default,,0000,0000,0000,,love to chat with you about it. Dialogue: 0,0:31:07.88,0:31:11.82,Default,,0000,0000,0000,,We've got some time for questions, and so\NI Dialogue: 0,0:31:11.82,0:31:14.41,Default,,0000,0000,0000,,want to open it up to all of you. Dialogue: 0,0:31:14.41,0:31:15.79,Default,,0000,0000,0000,,Question in the middle? Dialogue: 0,0:31:15.79,0:31:17.01,Default,,0000,0000,0000,,All right, cool. Thank you all so much. Appreciate Dialogue: 0,0:31:17.01,0:31:19.43,Default,,0000,0000,0000,,it. Enjoy the rest of the conference.