WEBVTT 00:00:18.330 --> 00:00:18.950 LUKE MELIA: All right, folks. 00:00:18.950 --> 00:00:24.040 Thanks for coming out. So you are at Lightning Fast 00:00:24.040 --> 00:00:26.180 Deployment of Your Rails-Baked Javascript APP. 00:00:26.180 --> 00:00:29.349 Hopefully you're in the right place. 00:00:29.349 --> 00:00:32.369 My name is Luke. I, Luke Melia. I live 00:00:32.369 --> 00:00:35.540 in Manhattan in New York City. Got a couple 00:00:35.540 --> 00:00:39.140 little girls who are learning Ruby and Javascript using 00:00:39.140 --> 00:00:44.050 Code Academy and KidsRuby. And I have a company 00:00:44.050 --> 00:00:46.980 called Yapp that I co-founded. We're one of these 00:00:46.980 --> 00:00:51.110 kind of hybrid product and consulting companies. And when 00:00:51.110 --> 00:00:54.080 I'm not doing Dad stuff or coding, I really 00:00:54.080 --> 00:00:57.000 love to play beach volleyball and have recently taken 00:00:57.000 --> 00:00:58.809 up parkour. 00:00:58.809 --> 00:01:01.549 So Yapp Labs is the consulting side of our 00:01:01.549 --> 00:01:04.290 business. We do Ember.js consulting and training based out 00:01:04.290 --> 00:01:08.000 of New York and Seattle, if, if that's interesting, 00:01:08.000 --> 00:01:09.900 happy to talk with you about that. 00:01:09.900 --> 00:01:12.850 So, by way of introducing this topic, I want 00:01:12.850 --> 00:01:16.130 to tell you a story. And it's a story 00:01:16.130 --> 00:01:21.840 of when deployments were driving me crazy. You know, 00:01:21.840 --> 00:01:24.530 kind of like, tear my hair out crazy. 00:01:24.530 --> 00:01:27.390 We had an app, and the app consisted, you 00:01:27.390 --> 00:01:29.280 know, it was pretty straightforward for a modern app. 00:01:29.280 --> 00:01:30.510 And it was a Rails app that had a 00:01:30.510 --> 00:01:33.510 home page. It had your terms and conditions page. 00:01:33.510 --> 00:01:35.570 You can't have a site without that. It had 00:01:35.570 --> 00:01:38.450 a Javascript app, which in this case was an 00:01:38.450 --> 00:01:40.660 Ember app, but, you know, you can substitute any 00:01:40.660 --> 00:01:44.280 kind of rich Javascript MVC app that you, style 00:01:44.280 --> 00:01:46.680 you'd like, for the purposes of this talk. I 00:01:46.680 --> 00:01:49.450 then, of course, had a JSON API. 00:01:49.450 --> 00:01:50.960 And so these, this was kind of the bullet 00:01:50.960 --> 00:01:53.870 points, but in terms of the amount of code, 00:01:53.870 --> 00:01:55.280 the complexity, and how much time that it took 00:01:55.280 --> 00:01:57.870 working on it, it was more like this, right. 00:01:57.870 --> 00:02:00.090 We had a lot of work on the Javascript 00:02:00.090 --> 00:02:02.409 app. Some, a bunch more in the JSON API. 00:02:02.409 --> 00:02:04.440 And the rest of the site was, you know, 00:02:04.440 --> 00:02:07.200 pretty trivial. 00:02:07.200 --> 00:02:09.470 But in terms of deployments, every time we wanted 00:02:09.470 --> 00:02:11.840 to, every time I made a change and wanted 00:02:11.840 --> 00:02:15.340 to deploy it, we would package everything up and 00:02:15.340 --> 00:02:18.430 deploy it. And so I have a question for 00:02:18.430 --> 00:02:21.260 you folks. Hopefully everybody's, in the room has worked 00:02:21.260 --> 00:02:22.930 with Rails. How long does it take to deploy 00:02:22.930 --> 00:02:24.930 a Rails app? We're gonna do a show of 00:02:24.930 --> 00:02:26.950 hands, and by the end, I hope everybody will 00:02:26.950 --> 00:02:28.959 have their Rails app, sorry, will have their hands 00:02:28.959 --> 00:02:29.800 up. 00:02:29.800 --> 00:02:32.480 And so, please start by raising your hand if 00:02:32.480 --> 00:02:34.730 your Rails app is deployed in less than thirty 00:02:34.730 --> 00:02:37.890 seconds. OK. Good awesome. One, I want to talk 00:02:37.890 --> 00:02:42.000 with you later. How about less than one minute? 00:02:42.000 --> 00:02:47.000 Cool. A few folks. Less than three minutes? A 00:02:47.000 --> 00:02:50.520 bunch more. Less than five minutes? Keep, keep your 00:02:50.520 --> 00:02:51.730 hands up even if you were in the early 00:02:51.730 --> 00:02:53.060 group. Less than five minutes. 00:02:53.060 --> 00:02:56.069 OK, so we're probably at a majority now. Less 00:02:56.069 --> 00:03:01.750 than ten minutes? Keep your hands up. OK. And 00:03:01.750 --> 00:03:03.569 less than twenty minutes? I hope that's everybody in 00:03:03.569 --> 00:03:06.580 the room. Please, please, mercy. OK. Cool. 00:03:06.580 --> 00:03:09.650 So, the, I think the, the answer is, it 00:03:09.650 --> 00:03:11.180 takes at least a few minutes to deploy a 00:03:11.180 --> 00:03:14.030 Rails app, unless you're one of an exceptional few 00:03:14.030 --> 00:03:16.920 folks in the audience. And I get it. There's 00:03:16.920 --> 00:03:19.530 a lot, you know, there's files to transfer. There's 00:03:19.530 --> 00:03:22.980 dependencies to install. Most modern Rails apps, you know, 00:03:22.980 --> 00:03:25.010 that I run into, that we create, have a 00:03:25.010 --> 00:03:28.150 lot of gem dependencies. It takes some time to 00:03:28.150 --> 00:03:30.520 boot the app with all those dependencies and just 00:03:30.520 --> 00:03:33.090 with, just with your app code. 00:03:33.090 --> 00:03:35.620 And so, that's fine, except for, I was going 00:03:35.620 --> 00:03:38.760 days just working on the Javascript app. Right, I 00:03:38.760 --> 00:03:41.950 was just making changes in Javascript, and every time 00:03:41.950 --> 00:03:44.770 I wanted to deploy, I was waiting five minutes 00:03:44.770 --> 00:03:50.540 in our case to just deploy static Javascript changes. 00:03:50.540 --> 00:03:52.050 And it really made me want to throw something 00:03:52.050 --> 00:03:53.959 across the room. Why was I doing this to 00:03:53.959 --> 00:03:55.030 myself? 00:03:55.030 --> 00:03:58.510 And it wasn't just me that I was annoying. 00:03:58.510 --> 00:04:02.430 I was also annoying our users, because, in most, 00:04:02.430 --> 00:04:06.680 in most Rails deployment scenarios, there are some, there 00:04:06.680 --> 00:04:09.200 can be some hiccups in each deploy. And we'll, 00:04:09.200 --> 00:04:11.230 so let's talk a little bit about this, this 00:04:11.230 --> 00:04:16.339 kind of hiccups and deployments and zero downtime deploys. 00:04:16.339 --> 00:04:19.060 So if your Rails app takes several seconds to 00:04:19.060 --> 00:04:22.449 boot, which is probably about average, obviously it can't 00:04:22.449 --> 00:04:25.830 serve requests during that time. And so, under high 00:04:25.830 --> 00:04:28.650 load in most architectures, most requesters are just gonna 00:04:28.650 --> 00:04:30.620 be queued, waiting for the app to be ready 00:04:30.620 --> 00:04:34.090 to handle requests. And then once it boots up, 00:04:34.090 --> 00:04:37.139 it's gonna start handling those requests, and eventually flush 00:04:37.139 --> 00:04:41.039 that queue and hopefully catch up to the requests 00:04:41.039 --> 00:04:43.210 as they're coming in. 00:04:43.210 --> 00:04:45.919 And so users that are hitting the, hitting your 00:04:45.919 --> 00:04:49.139 app during this time may experience at, at best 00:04:49.139 --> 00:04:51.289 case just a couple of seconds of downtime. At 00:04:51.289 --> 00:04:52.889 worst case, kind of a feeling like that, that 00:04:52.889 --> 00:04:55.330 this site is not responsive. 00:04:55.330 --> 00:04:57.520 And so it disappoints me that we don't yet 00:04:57.520 --> 00:05:01.800 have a kind of conventional solution for zero downtime 00:05:01.800 --> 00:05:03.990 deploys. But it kind of makes sense because, by 00:05:03.990 --> 00:05:08.490 definition, Rails runs inside of other web servers, and 00:05:08.490 --> 00:05:10.550 so, and that, this is really a concern kind 00:05:10.550 --> 00:05:11.889 of at that web server layer. 00:05:11.889 --> 00:05:15.300 So, Heroku, for example, has an experimental solution. Heroku 00:05:15.300 --> 00:05:20.330 Labs is, Heroku's kind of unsupported experimental area features. 00:05:20.330 --> 00:05:23.539 And you can run heroku labs:enable preboot, which will 00:05:23.539 --> 00:05:25.830 start up new servers or dynos with your new 00:05:25.830 --> 00:05:28.669 code, wait three minutes to give your Rails app 00:05:28.669 --> 00:05:30.979 plenty of time to boot, and then switch traffic 00:05:30.979 --> 00:05:32.650 over. 00:05:32.650 --> 00:05:36.680 For, if you're using Puma or Unicorn, there are 00:05:36.680 --> 00:05:39.419 facilities to start one worker at a time, or 00:05:39.419 --> 00:05:42.169 groups of workers by sending signals to the master 00:05:42.169 --> 00:05:45.020 process. HAProxy is a tool that I've used in 00:05:45.020 --> 00:05:48.229 the past to kind of split traffic, give yourself 00:05:48.229 --> 00:05:52.389 time to boot up another, another set of servers. 00:05:52.389 --> 00:05:54.499 HAProxy is nice because you can do health checks 00:05:54.499 --> 00:05:57.150 against those new servers and say, am I ready 00:05:57.150 --> 00:06:02.289 to deploy? And Passenger also has some solutions around 00:06:02.289 --> 00:06:04.589 this. 00:06:04.589 --> 00:06:06.339 In terms of kind of the full scope of 00:06:06.339 --> 00:06:08.619 zero downtime stuff, it gets more complicated when you 00:06:08.619 --> 00:06:12.569 talk about database migrations and what's safe and what's 00:06:12.569 --> 00:06:16.430 not safe for these, these types of, these types 00:06:16.430 --> 00:06:18.949 of deployments. And I'm happy to chat about that 00:06:18.949 --> 00:06:21.039 with anybody later, but that's out of scope for, 00:06:21.039 --> 00:06:22.729 for this particular talk. 00:06:22.729 --> 00:06:24.360 What I do want to drill into a little 00:06:24.360 --> 00:06:28.080 bit is issues with static assets and zero downtime 00:06:28.080 --> 00:06:30.219 deploys, because that's the thing that was, you know, 00:06:30.219 --> 00:06:31.589 kind of at the heart of what I was 00:06:31.589 --> 00:06:35.099 doing, was really dealing with these static Javascript assets. 00:06:35.099 --> 00:06:37.539 And I think that these issues aren't discussed often. 00:06:37.539 --> 00:06:38.839 So I kind of want to drill down, kind 00:06:38.839 --> 00:06:41.479 of at a detailed level, and talk about them 00:06:41.479 --> 00:06:43.419 here. 00:06:43.419 --> 00:06:46.279 So when a browser makes an initial request to 00:06:46.279 --> 00:06:49.479 your server for, to load your, your rich Javascript 00:06:49.479 --> 00:06:52.099 app, it's loading the index dot html file and 00:06:52.099 --> 00:06:54.899 by index.html, I'm gonna refer to the html file 00:06:54.899 --> 00:06:58.089 that's the bootstrapping, it's bootstrapping your Javascript app. It's 00:06:58.089 --> 00:07:00.069 the thing that has a little bit of code 00:07:00.069 --> 00:07:01.629 to fire things up and it pulls in the 00:07:01.629 --> 00:07:03.839 right Javascript and CSS assets. 00:07:03.839 --> 00:07:06.189 So the request comes into your servers, your server 00:07:06.189 --> 00:07:09.679 responds with the HTML file, with the text slash 00:07:09.679 --> 00:07:13.580 html mine type, and typically the, your asset files, 00:07:13.580 --> 00:07:15.729 the Javascript and CSS that are gonna be referenced 00:07:15.729 --> 00:07:19.479 here, are gonna be fingerprinted. Right, so we do, 00:07:19.479 --> 00:07:21.699 take a hash of the contents of the Javascript 00:07:21.699 --> 00:07:24.909 file, we set it as a, we include that 00:07:24.909 --> 00:07:27.409 hash in the file name, and we're then are 00:07:27.409 --> 00:07:30.149 able to set far features expires headers on those 00:07:30.149 --> 00:07:32.520 files, so that when the file changes, we don't 00:07:32.520 --> 00:07:35.809 have to worry about cache expire or anything. We 00:07:35.809 --> 00:07:38.749 just gotta new file that's gonna come through as 00:07:38.749 --> 00:07:41.179 if the browser's never seen it before. 00:07:41.179 --> 00:07:43.599 And so in this case, our html file might 00:07:43.599 --> 00:07:47.599 contain something like assets slash app dash abc123 dot 00:07:47.599 --> 00:07:51.779 js, where abc123 is this fingerprint we're talking about. 00:07:51.779 --> 00:07:54.830 And so the browser takes that html, parses the 00:07:54.830 --> 00:07:57.469 page, a short time later makes the request for 00:07:57.469 --> 00:08:01.550 app dash abc123. Server says, here you go, some 00:08:01.550 --> 00:08:05.330 text Javascript. Browser parses that, boots up the app. 00:08:05.330 --> 00:08:06.369 All is well. 00:08:06.369 --> 00:08:08.849 Hopefully this is very clear to everybody who's in 00:08:08.849 --> 00:08:12.029 the room. What's maybe less clear, unless you've thought 00:08:12.029 --> 00:08:14.740 about it in detail is that during deployments, this 00:08:14.740 --> 00:08:17.300 idea can break down a little bit. And so 00:08:17.300 --> 00:08:20.459 imagine that we've got our deployment and we've got 00:08:20.459 --> 00:08:23.319 two kind of sets of server. The top set 00:08:23.319 --> 00:08:25.300 that we're looking at here on the screen is 00:08:25.300 --> 00:08:27.749 the existing code. The bottom set is the new 00:08:27.749 --> 00:08:29.869 code that you're deploying. 00:08:29.869 --> 00:08:31.020 And in this case, there's a change to the 00:08:31.020 --> 00:08:35.080 Javascript file, so there's the new fingerprinted filename there. 00:08:35.080 --> 00:08:38.120 So when our initial request for our page comes 00:08:38.120 --> 00:08:40.830 in, it was, it will go to the old 00:08:40.830 --> 00:08:43.020 code, because we haven't yet switched traffic over to 00:08:43.020 --> 00:08:46.890 the, to the new deploy. And just like in 00:08:46.890 --> 00:08:49.209 our first example, it's gonna come back with the 00:08:49.209 --> 00:08:54.220 index file references app dash abc123 dot js. 00:08:54.220 --> 00:08:56.490 Now, what if, in that moment, where, as the 00:08:56.490 --> 00:08:59.710 page is being parsed, before this request comes back, 00:08:59.710 --> 00:09:02.000 we then switch traffic over to pointing to the 00:09:02.000 --> 00:09:05.510 new server? Well, request is gonna come in for 00:09:05.510 --> 00:09:09.060 app dash abc123 dot js, the new server gets 00:09:09.060 --> 00:09:11.640 the request and says, ah, I don't know what 00:09:11.640 --> 00:09:13.950 you're talking about. I don't have a Javascript file 00:09:13.950 --> 00:09:18.230 with that name. And so it says, 404 Not 00:09:18.230 --> 00:09:18.900 Found. 00:09:18.900 --> 00:09:24.130 And this is a challenging problem to, to address, 00:09:24.130 --> 00:09:26.240 because there's a, because of a few reasons. One 00:09:26.240 --> 00:09:28.280 is that most simply if I, at this point, 00:09:28.280 --> 00:09:30.900 now hit refresh in the browser, of course everything 00:09:30.900 --> 00:09:33.460 works fine. Right, because now both of those requests 00:09:33.460 --> 00:09:35.380 are going to the new server and the world 00:09:35.380 --> 00:09:36.200 is good. 00:09:36.200 --> 00:09:39.640 It can be further kind of shadowed, this issue, 00:09:39.640 --> 00:09:43.090 because, if you are serving your assets up through 00:09:43.090 --> 00:09:46.000 an assets host at CBN, you might have some, 00:09:46.000 --> 00:09:48.730 some, some of their, your edge nodes might have 00:09:48.730 --> 00:09:51.510 that old page cached. That old Javascript cached. In 00:09:51.510 --> 00:09:54.450 which case, those nodes will return it just fine. 00:09:54.450 --> 00:09:57.850 And so, to, to know that you're, you know, 00:09:57.850 --> 00:10:00.910 totally impervious to this, you know, might be a 00:10:00.910 --> 00:10:02.620 little bit fuzzy, and also to be able to 00:10:02.620 --> 00:10:05.350 reproduce it reliably is a challenging thing to do. 00:10:05.350 --> 00:10:08.320 But, in short, to avoid these hiccups, both the 00:10:08.320 --> 00:10:10.660 old versions of your assets and the new versions 00:10:10.660 --> 00:10:12.420 have to be available for at least a few 00:10:12.420 --> 00:10:15.670 minutes during your deployment in order to, to make 00:10:15.670 --> 00:10:19.450 this zero downtime approach really work well on the 00:10:19.450 --> 00:10:21.730 static asset front. 00:10:21.730 --> 00:10:23.330 And so this was one of the things I 00:10:23.330 --> 00:10:25.670 was thinking about during these many five minute deploys, 00:10:25.670 --> 00:10:29.540 where I was, you know, wishing that I had 00:10:29.540 --> 00:10:32.340 a solution. And so, in thinking about that, I 00:10:32.340 --> 00:10:34.040 said, well, we could figure out how to do 00:10:34.040 --> 00:10:35.810 this on our app servers. Kind of keep the 00:10:35.810 --> 00:10:38.830 old versions of the, of the Javascript and the 00:10:38.830 --> 00:10:40.610 new versions together. Or we could move the assets 00:10:40.610 --> 00:10:43.220 elsewhere. And the idea of moving the assets elsewhere 00:10:43.220 --> 00:10:45.780 really appealed to me, because that meant, if they 00:10:45.780 --> 00:10:47.870 weren't on the Rails, my Rails servers, then maybe 00:10:47.870 --> 00:10:50.060 I could avoid doing Rails deploys when I just 00:10:50.060 --> 00:10:52.580 had static asset changes. 00:10:52.580 --> 00:10:55.140 So I started to sketch out an idea. We've 00:10:55.140 --> 00:10:56.580 got our Rails server at the top, and we 00:10:56.580 --> 00:10:59.220 had this separate static asset server at the bottom. 00:10:59.220 --> 00:11:01.590 Let's deploy our Rails app code to the Rails 00:11:01.590 --> 00:11:05.860 servers, our Javascript, CSS, and images to these static 00:11:05.860 --> 00:11:08.800 assets servers, and then we would deploy our index 00:11:08.800 --> 00:11:13.070 file. Where would we deploy our index file? 00:11:13.070 --> 00:11:14.880 And so, I started to think about, well, what 00:11:14.880 --> 00:11:16.000 is the index file? It is kind of this 00:11:16.000 --> 00:11:18.240 thing that bridges the two? What are the requirements 00:11:18.240 --> 00:11:20.490 around it? What do we know about it? And 00:11:20.490 --> 00:11:24.070 this index, the html file points to fingerprinted Javascript 00:11:24.070 --> 00:11:27.250 and CSS, but it's not fingerprinted itself. That's obviously 00:11:27.250 --> 00:11:30.600 important, because it needs to be at, at a 00:11:30.600 --> 00:11:34.530 consistent location for browsers to locate, to load. It 00:11:34.530 --> 00:11:38.260 contains Javascript urls and code to boot the Javascript 00:11:38.260 --> 00:11:40.470 app to load CSS and such in the right 00:11:40.470 --> 00:11:44.080 order. It's a good place to provide environment-specific configuration 00:11:44.080 --> 00:11:46.960 to Javascript. Maybe you have some differences between dev 00:11:46.960 --> 00:11:49.520 and stage in production. 00:11:49.520 --> 00:11:51.150 One thing that I knew was key, because I 00:11:51.150 --> 00:11:53.250 had struggled with it, is that when you serve 00:11:53.250 --> 00:11:55.480 this html off of the same domain as your 00:11:55.480 --> 00:11:59.090 API, life is way simpler with respect to cores 00:11:59.090 --> 00:12:03.910 and cross origin security issues. And finally, if I 00:12:03.910 --> 00:12:06.140 wanted, if you wanted to be able to deploy 00:12:06.140 --> 00:12:08.920 changes quickly to your users, caching on this particular 00:12:08.920 --> 00:12:11.960 page should be minimal to none, so that you 00:12:11.960 --> 00:12:14.810 can pretty instantly switch over. 00:12:14.810 --> 00:12:17.920 So my conclusion, from thinking about this, is that 00:12:17.920 --> 00:12:20.190 the html page ideally should be managed and thought 00:12:20.190 --> 00:12:23.290 about as part of your static asset deployment process, 00:12:23.290 --> 00:12:25.350 but it should be served off of your Rails 00:12:25.350 --> 00:12:26.240 server. 00:12:26.240 --> 00:12:28.720 And, as importantly, it should be served off your 00:12:28.720 --> 00:12:33.210 Rails server without requiring a Rails reboot or redeploying 00:12:33.210 --> 00:12:36.760 the entire Rails app. And so, so we were 00:12:36.760 --> 00:12:39.000 able to start to refine this sketch and say, 00:12:39.000 --> 00:12:41.620 OK, our Rails server's gonna be serving up our 00:12:41.620 --> 00:12:45.100 API requests, our, kind of, traditional, dynamic Rails pages 00:12:45.100 --> 00:12:47.160 as part of the html for a Javascript app, 00:12:47.160 --> 00:12:49.490 and our static asset server's gonna be serving up 00:12:49.490 --> 00:12:51.860 the Javascript, CSS and images. 00:12:51.860 --> 00:12:53.740 And so that means we need to somehow deploy 00:12:53.740 --> 00:12:58.520 our html up to the Rails server without a 00:12:58.520 --> 00:13:00.360 full, a full reboot. And so, how could we 00:13:00.360 --> 00:13:01.070 do this? 00:13:01.070 --> 00:13:03.400 Well, the most obvious thing to me was, well, 00:13:03.400 --> 00:13:06.330 take a html file and put it on the 00:13:06.330 --> 00:13:09.590 file system of each Rails server. And this has 00:13:09.590 --> 00:13:11.610 a few things that aren't great about it. You 00:13:11.610 --> 00:13:15.310 can probably make this work in some configurations. In 00:13:15.310 --> 00:13:19.370 many deployment environments, disk is ephemeral, and so relying 00:13:19.370 --> 00:13:22.290 on, you know, on copying some things up might 00:13:22.290 --> 00:13:24.120 not be a great idea. It's also a little 00:13:24.120 --> 00:13:27.440 bit weird to mix assets, files deployed from a 00:13:27.440 --> 00:13:31.030 particular gitshaw, with files deployed from somewhere else, kind 00:13:31.030 --> 00:13:33.700 of in the same file system. 00:13:33.700 --> 00:13:35.450 And so, we said, well, what if there's something 00:13:35.450 --> 00:13:37.780 that we could all see and talk to? Well, 00:13:37.780 --> 00:13:40.900 what about uploading to S3? So then all the 00:13:40.900 --> 00:13:44.860 Rails servers can, can see S3, read from it, 00:13:44.860 --> 00:13:47.010 be able to serve up that html. And this 00:13:47.010 --> 00:13:48.930 could kind of work, but reading from S3 is 00:13:48.930 --> 00:13:52.310 a little bit slow. And we wanted this page 00:13:52.310 --> 00:13:55.790 to be fast, obviously. No Javascript or CSS is 00:13:55.790 --> 00:13:57.930 gonna start being loaded until this page is loaded 00:13:57.930 --> 00:13:59.790 in the browser. And so the fastest we could, 00:13:59.790 --> 00:14:01.060 the faster we could get this page to the 00:14:01.060 --> 00:14:03.370 user, the better. 00:14:03.370 --> 00:14:05.620 And so, then we said, well, what about redis? 00:14:05.620 --> 00:14:09.560 Redis is persistent. It's fast. For us, it was 00:14:09.560 --> 00:14:13.190 already in our environment. We liked this idea a 00:14:13.190 --> 00:14:16.000 lot. We decided to, to dig in. This is 00:14:16.000 --> 00:14:17.750 not the, as you'll see, this is not the 00:14:17.750 --> 00:14:21.029 only way to do it. It's totally possible to 00:14:21.029 --> 00:14:23.750 user other systems besides redis. But redis kind of 00:14:23.750 --> 00:14:26.960 firt the bill for us and works quite well, 00:14:26.960 --> 00:14:27.710 as you'll see. 00:14:27.710 --> 00:14:29.880 So, the general idea was we're gonna deploy into 00:14:29.880 --> 00:14:32.490 redis and then serve out of redis via a 00:14:32.490 --> 00:14:35.960 Rails controller. So here's the simplest possible kind of 00:14:35.960 --> 00:14:39.470 deploy code that we had. It's a rig task, 00:14:39.470 --> 00:14:42.760 and we're going to generate our html for the 00:14:42.760 --> 00:14:46.380 current assets, and that's, that's kind of an exercise 00:14:46.380 --> 00:14:48.110 for your build tooling, which we'll talk about a 00:14:48.110 --> 00:14:50.440 little bit later. And then once we had this 00:14:50.440 --> 00:14:52.090 html, we're actually going to set it as a, 00:14:52.090 --> 00:14:56.029 at a, as a redis key-value store. So the 00:14:56.029 --> 00:14:57.880 html is the value and the key would be 00:14:57.880 --> 00:15:02.730 something well-known like jsapp colon index, for example. And, 00:15:02.730 --> 00:15:04.840 and this is a redis connection that's connecting directly 00:15:04.840 --> 00:15:07.779 to your charted deployment environment. So that's staging more 00:15:07.779 --> 00:15:10.440 production. 00:15:10.440 --> 00:15:13.090 Once it's there in redis, our controller, again, the 00:15:13.090 --> 00:15:16.470 most simplest version, is get the value out of 00:15:16.470 --> 00:15:21.350 redis. Render text.html. Now, when I first looked at, 00:15:21.350 --> 00:15:22.910 looked at this code or wrote this code, I 00:15:22.910 --> 00:15:24.410 said, is that gonna be served up with the 00:15:24.410 --> 00:15:26.570 right mine type? Seems a little strange. And it 00:15:26.570 --> 00:15:29.920 turns out that, yes, if you do render text 00:15:29.920 --> 00:15:33.070 and some string, Rails serves that up with text 00:15:33.070 --> 00:15:36.690 slash html, if you don't specify. So, it's a 00:15:36.690 --> 00:15:38.520 little, I think a little bit of a confusing 00:15:38.520 --> 00:15:41.430 API, but it does what we want. 00:15:41.430 --> 00:15:44.370 So, we can now continue to refine this approach. 00:15:44.370 --> 00:15:46.370 We know we're deploying, when we need to deploy 00:15:46.370 --> 00:15:49.160 Rails app code, we're doing a deployment to our 00:15:49.160 --> 00:15:52.370 Rails server. When we're deploying Javascript, CSS and images, 00:15:52.370 --> 00:15:54.870 we're deploying to the static assets server, and then 00:15:54.870 --> 00:15:58.160 we're deploying html by connecting to redis and deploying 00:15:58.160 --> 00:15:59.430 into it. 00:15:59.430 --> 00:16:03.430 And we can make things a little bit nicer 00:16:03.430 --> 00:16:06.520 by dropping cloud front right in front of, by 00:16:06.520 --> 00:16:08.810 using S3 as our static assets server, and then 00:16:08.810 --> 00:16:10.940 dropping cloud front instead of in front of our, 00:16:10.940 --> 00:16:13.350 in front of S3. So, for very little effort 00:16:13.350 --> 00:16:15.620 and very little money, we've got now CBN distribution 00:16:15.620 --> 00:16:18.170 for our static assets. 00:16:18.170 --> 00:16:21.710 Now, there's a few things about this deployment to 00:16:21.710 --> 00:16:25.160 S3, in terms of making it fast. Getting a 00:16:25.160 --> 00:16:28.720 file list from S3 can be somewhat expensive, particularly 00:16:28.720 --> 00:16:31.839 the more files that you have. And so the 00:16:31.839 --> 00:16:34.440 approach that we took was to generate a manifest 00:16:34.440 --> 00:16:38.620 file of our current assets and store the copy 00:16:38.620 --> 00:16:42.000 of that manifest on S3 so we, we're basically 00:16:42.000 --> 00:16:44.500 gonna read the remote manifest, compare it to our 00:16:44.500 --> 00:16:46.310 local manifest, and know we only need to deploy 00:16:46.310 --> 00:16:48.520 what's different. And so this means that if I 00:16:48.520 --> 00:16:51.540 make one Javascript, one line of Javascript change, it's 00:16:51.540 --> 00:16:54.510 just the file that that's concatenated into that needs 00:16:54.510 --> 00:16:56.620 to be updated, and not all of my images 00:16:56.620 --> 00:17:00.260 and CSS, as we're doing our deploy, our assets 00:17:00.260 --> 00:17:02.110 deploy to S3. 00:17:02.110 --> 00:17:05.260 Now, purging has been on our to-do list for 00:17:05.260 --> 00:17:08.209 this architecture for quite a while, right. After a 00:17:08.209 --> 00:17:12.000 deploy is successfully completed, we can, in theory, remove 00:17:12.000 --> 00:17:15.039 stuff from S3. We never really got around to 00:17:15.039 --> 00:17:17.959 that. Mostly because it's so incredibly cheap to store 00:17:17.959 --> 00:17:20.730 these small files on S3, so, still on our 00:17:20.730 --> 00:17:23.638 to-do list. I would probably not recommend you prioritizing 00:17:23.638 --> 00:17:26.839 it too high for yourself. The code for this 00:17:26.839 --> 00:17:29.730 S3 sink is here at this link. I will 00:17:29.730 --> 00:17:31.399 make these slides available. You don't have to worry 00:17:31.399 --> 00:17:34.100 about copying it down. This repo is open source 00:17:34.100 --> 00:17:35.570 and contains a lot of the code that we're 00:17:35.570 --> 00:17:37.860 looking at today. And it's the actual code that 00:17:37.860 --> 00:17:41.169 we use for our, for our production environments. 00:17:41.169 --> 00:17:45.230 So, once you start thinking about this architecture, it 00:17:45.230 --> 00:17:47.799 paves the way to do something a little bit 00:17:47.799 --> 00:17:50.119 more fundamental with your rich Javascript app and your 00:17:50.119 --> 00:17:53.179 Rails app, which is that you pull them, tease 00:17:53.179 --> 00:17:56.179 them apart into separate repositories. And now why would 00:17:56.179 --> 00:17:57.340 you want to do that? 00:17:57.340 --> 00:17:59.470 Well, one of the reasons is, you know, thinking 00:17:59.470 --> 00:18:02.289 about tagging, do, you know, kind of tagging a 00:18:02.289 --> 00:18:04.840 deployed version of your code. Since you've got these 00:18:04.840 --> 00:18:08.360 independent deploy processes, it makes sense to be able 00:18:08.360 --> 00:18:11.230 to tag a Javascript deploy separate from a Rails 00:18:11.230 --> 00:18:13.559 deploy, because they really are now independent of each 00:18:13.559 --> 00:18:14.619 other. 00:18:14.619 --> 00:18:17.679 And I find also that thinking of your Javascript 00:18:17.679 --> 00:18:21.570 app as a separate, independent client of your API, 00:18:21.570 --> 00:18:22.850 works really well. Kind of puts it on the 00:18:22.850 --> 00:18:25.249 same level as a native app, for example, maybe 00:18:25.249 --> 00:18:26.769 if you've got an iPhone app that communicates to 00:18:26.769 --> 00:18:29.289 your API as well. 00:18:29.289 --> 00:18:33.289 It also opens up the realm of possibility to 00:18:33.289 --> 00:18:35.029 having a lot of flexibility with what kind of 00:18:35.029 --> 00:18:37.200 build tools you want to use with your Javascript 00:18:37.200 --> 00:18:40.899 app. You may choose to use sprockets in your 00:18:40.899 --> 00:18:44.119 separate standalone repo. Or you may choose to use 00:18:44.119 --> 00:18:49.119 grunt, gulp, broccoli, brunch. You name it, there's obviously 00:18:49.119 --> 00:18:52.509 a lot of innovation and creativity happening around build 00:18:52.509 --> 00:18:55.619 tools in the Javascript environment. And my guess would 00:18:55.619 --> 00:18:59.369 be that you're, we're gonna see faster, you know, 00:18:59.369 --> 00:19:03.749 innovation, iteration in the Javascript environment for building Javascript 00:19:03.749 --> 00:19:06.019 apps than we will in the Ruby environment for 00:19:06.019 --> 00:19:07.340 building Javascript apps. 00:19:07.340 --> 00:19:11.710 So, we've now got an approach that works pretty 00:19:11.710 --> 00:19:14.700 well. But I think the, the question is, is 00:19:14.700 --> 00:19:16.639 it worth doing the work to set this in 00:19:16.639 --> 00:19:18.820 place? Like, how fast is this in the real 00:19:18.820 --> 00:19:20.559 world? And so I took one of our apps, 00:19:20.559 --> 00:19:22.980 and this isn't, was not a scientific bench mark, 00:19:22.980 --> 00:19:27.039 so consider it directional. And our builds took about 00:19:27.039 --> 00:19:29.909 six and a half seconds. This particular app is 00:19:29.909 --> 00:19:31.669 using Rake Pipeline as a build tool for the 00:19:31.669 --> 00:19:37.799 Javascript side. Our transferring assets to S3 using this 00:19:37.799 --> 00:19:40.269 differential approach was about a second, and then uploading 00:19:40.269 --> 00:19:44.330 html into redis was about two and a half 00:19:44.330 --> 00:19:47.649 seconds. And so, instead of a five minute deploy, 00:19:47.649 --> 00:19:50.289 I was now able, we were now able to 00:19:50.289 --> 00:19:53.759 deploy this, our Javascript apps in under ten seconds. 00:19:53.759 --> 00:19:58.139 So just by that, that was a big win. 00:19:58.139 --> 00:20:00.429 And stopped me from wanting to throw things across 00:20:00.429 --> 00:20:03.149 the office. But, I think that, you know, in 00:20:03.149 --> 00:20:06.619 any kind of architectural choices like this, you learn 00:20:06.619 --> 00:20:09.200 if this is a good idea or not over 00:20:09.200 --> 00:20:12.200 time, right, based on, how does, how does this 00:20:12.200 --> 00:20:15.039 architecture respond to changes. What kind of possibilities does 00:20:15.039 --> 00:20:16.909 it enable? So I want to talk a little 00:20:16.909 --> 00:20:19.639 bit about the kind of emergent behavior that we've 00:20:19.639 --> 00:20:21.580 seen around, now that we've had this in production 00:20:21.580 --> 00:20:23.580 for awhile. 00:20:23.580 --> 00:20:26.239 The first thing is, the idea of preview. And 00:20:26.239 --> 00:20:28.950 so this is an actual command line session for 00:20:28.950 --> 00:20:31.929 deploying an app. In this case, it's yapp-prefs, which 00:20:31.929 --> 00:20:36.259 is our, kind of, account settings app. We first 00:20:36.259 --> 00:20:40.779 run rake dist. This is the build. And with 00:20:40.779 --> 00:20:42.580 the build completes, in this case, as we saw 00:20:42.580 --> 00:20:44.289 in the pie chart before, in about six seconds 00:20:44.289 --> 00:20:47.600 or so. And it says, OK, to deploy these 00:20:47.600 --> 00:20:52.529 assets to S3, run rake deploy:assets with this, what 00:20:52.529 --> 00:20:55.070 we call a manifest idea, this b35b. 00:20:55.070 --> 00:20:57.769 So what's a manifest id? We talked earlier about 00:20:57.769 --> 00:21:00.820 fingerprinting assets and we talked about creating a manifest 00:21:00.820 --> 00:21:03.289 file. So what we do also is we fingerprint 00:21:03.289 --> 00:21:05.129 the manifest file. So we take a hash of 00:21:05.129 --> 00:21:07.570 the contents of that manifest file and we say, 00:21:07.570 --> 00:21:10.210 OK, that is the manifest id for this deploy. 00:21:10.210 --> 00:21:12.249 And that's, it's, it's kind of a unique identifier 00:21:12.249 --> 00:21:15.399 as it's going through its unique deploy process. 00:21:15.399 --> 00:21:17.489 And so we run rake deploy:assets, which does the 00:21:17.489 --> 00:21:20.580 differential upload to S3 and it's gonna show us 00:21:20.580 --> 00:21:23.029 what it uploads. It's gonna spit out, OK, I've 00:21:23.029 --> 00:21:28.899 uploaded these four files. JS, CSS, two yaml files 00:21:28.899 --> 00:21:31.149 for the manifest. We, actually, these are two copies 00:21:31.149 --> 00:21:33.070 of the same thing. One is a, has a 00:21:33.070 --> 00:21:35.139 file name with the id, and one just is, 00:21:35.139 --> 00:21:38.470 hey I am the latest. And it's going to 00:21:38.470 --> 00:21:40.989 then tell us the next command to run is 00:21:40.989 --> 00:21:45.659 deploy:generate_index for this manifest id. And what this is 00:21:45.659 --> 00:21:49.049 gonna do is going to connect to redis and 00:21:49.049 --> 00:21:51.509 set this at a key named for the manifest 00:21:51.509 --> 00:21:54.369 id. So in the previous simplistic example we looked 00:21:54.369 --> 00:21:57.289 at, it was just updating jsapp index. Now it's 00:21:57.289 --> 00:21:59.779 updating a key at prefs, in this case, prefs:index 00:21:59.779 --> 00:22:04.039 b35b something, you know, named for the manifest id. 00:22:04.039 --> 00:22:06.989 And why is this awesome? Well, this command line 00:22:06.989 --> 00:22:10.429 tool can now tell us, hey, to preview this, 00:22:10.429 --> 00:22:12.610 this asset change, go ahead and take a look 00:22:12.610 --> 00:22:16.509 at your at, your site with the query param 00:22:16.509 --> 00:22:21.629 manifest id equals b35 et cetera. And what this 00:22:21.629 --> 00:22:24.110 is gonna do is it's going to pull the 00:22:24.110 --> 00:22:27.080 new html file from redis. Gonna show, which is 00:22:27.080 --> 00:22:29.899 loading up the new Javascript. It's connecting to the 00:22:29.899 --> 00:22:33.190 production API. So you're able to smoke test this 00:22:33.190 --> 00:22:36.039 in production. Everything is working just as the user 00:22:36.039 --> 00:22:38.659 will see it, except for your users don't see 00:22:38.659 --> 00:22:40.879 it yet. So if you screwed something up, you've 00:22:40.879 --> 00:22:42.580 got a chance before kind of pulling the trigger 00:22:42.580 --> 00:22:44.889 and switching it life to go. 00:22:44.889 --> 00:22:47.720 And then, finally, one more command to kind of 00:22:47.720 --> 00:22:49.779 active that redis key and make it the current 00:22:49.779 --> 00:22:53.659 key. And so what does this code look like? 00:22:53.659 --> 00:22:55.519 It's actually not that much more complicated than what 00:22:55.519 --> 00:22:59.200 we saw before. We invoke our rake task with 00:22:59.200 --> 00:23:04.730 the manifest id. Generate our html file. And then, 00:23:04.730 --> 00:23:07.549 instead of setting jsapp index, we'll set a jsapp 00:23:07.549 --> 00:23:09.529 key based on the manifest name, or redis key 00:23:09.529 --> 00:23:13.299 based on the manifest name. And then spit out 00:23:13.299 --> 00:23:15.700 something to give the developer the url to take 00:23:15.700 --> 00:23:20.480 a look at, to preview, to preview the app. 00:23:20.480 --> 00:23:23.409 On the server-side, we're gonna add one more redis 00:23:23.409 --> 00:23:27.529 request to the mix. If there's a manifest id 00:23:27.529 --> 00:23:30.899 param, then we'll just use that. If it's blank, 00:23:30.899 --> 00:23:33.269 then we'll go and we'll connect to a current 00:23:33.269 --> 00:23:35.509 key. Grab the manifest id, then use that to 00:23:35.509 --> 00:23:40.070 serve up the current version of, of the site. 00:23:40.070 --> 00:23:41.659 Of the, of this index file. 00:23:41.659 --> 00:23:46.119 And so, that has been pretty powerful, and it's, 00:23:46.119 --> 00:23:48.320 it's a super useful tool that we use in 00:23:48.320 --> 00:23:51.289 almost every single deploy. The developer's just gonna do 00:23:51.289 --> 00:23:53.789 a quick smoke test and say, yes, everything looks 00:23:53.789 --> 00:23:56.429 good, before they flip the switch. 00:23:56.429 --> 00:24:00.999 The next interesting aspect that this kind of enabled 00:24:00.999 --> 00:24:05.109 is around dynamic html rewriting. And so what we 00:24:05.109 --> 00:24:08.749 realize is that as html was passing through from 00:24:08.749 --> 00:24:11.950 redis through the controller back to the browser, we 00:24:11.950 --> 00:24:14.899 had the opportunity to make adjustments if we wanted 00:24:14.899 --> 00:24:18.929 to. And one category of adjustment that we ended 00:24:18.929 --> 00:24:22.259 up making, as you see in this example, is 00:24:22.259 --> 00:24:24.889 injecting some information about the current user. 00:24:24.889 --> 00:24:27.960 Now, obviously in a Rails controller we know typically 00:24:27.960 --> 00:24:31.409 who the current user is. Most apps will have 00:24:31.409 --> 00:24:35.100 a current_user method available to any controller that they 00:24:35.100 --> 00:24:38.590 can, it can grab. In contrast, when you're booting 00:24:38.590 --> 00:24:41.950 up a Javascript MVC app, at that point, you 00:24:41.950 --> 00:24:44.159 know, most apps don't know who the current user 00:24:44.159 --> 00:24:46.320 is. And if, in most, you know mostly there 00:24:46.320 --> 00:24:49.330 is some XHR request that's involved in figuring out, 00:24:49.330 --> 00:24:51.499 is this user logged in and, if so, what 00:24:51.499 --> 00:24:53.970 is their role in the system? And during that 00:24:53.970 --> 00:24:56.869 time, the user is sitting there waiting, right. The 00:24:56.869 --> 00:24:58.999 Javascript is just kind of, maybe it's rendering a 00:24:58.999 --> 00:25:01.889 loading spinner for the user or something. But it's 00:25:01.889 --> 00:25:04.489 a little bit annoying and it also makes the 00:25:04.489 --> 00:25:07.799 boot process for the, for your Javascript app more 00:25:07.799 --> 00:25:08.179 complicated. 00:25:08.179 --> 00:25:11.200 So we said, well what if the app could 00:25:11.200 --> 00:25:15.129 have, at boot time, have access to this information? 00:25:15.129 --> 00:25:17.600 So what we're doing here is, in the controller 00:25:17.600 --> 00:25:20.509 action at the top, between the time we get 00:25:20.509 --> 00:25:24.519 the html out of redis and return, render it, 00:25:24.519 --> 00:25:27.669 we're going to inject current_user information. We're gonna grab 00:25:27.669 --> 00:25:31.919 the current_user and then user our AcitveModel serializer to 00:25:31.919 --> 00:25:35.249 convert it to JSON, escape it, and stick it 00:25:35.249 --> 00:25:37.159 into the head tag. 00:25:37.159 --> 00:25:39.690 And you'll notice that the method that we're using 00:25:39.690 --> 00:25:42.720 to add this to the html, you might find 00:25:42.720 --> 00:25:46.419 a little crude. And certainly when I first started 00:25:46.419 --> 00:25:48.720 doing this, I said, OK, we'll use Nokogiri. We'll 00:25:48.720 --> 00:25:51.799 parse the html. And then we'll insert, you know, 00:25:51.799 --> 00:25:55.399 insert a node, and then we'll render, you know, 00:25:55.399 --> 00:25:58.279 convert that back to text. And it turns out 00:25:58.279 --> 00:26:00.889 that really what we're doing is so simple that, 00:26:00.889 --> 00:26:02.929 as fast as Nokogiri is, and it's pretty fast 00:26:02.929 --> 00:26:05.820 for an XML or html parser, it is not 00:26:05.820 --> 00:26:08.759 faster than string manipulation and string indexing. 00:26:08.759 --> 00:26:10.830 And so, in this case, we're just looking at, 00:26:10.830 --> 00:26:12.059 where's the end of the head tag or the 00:26:12.059 --> 00:26:15.309 beginning of the head tag, inject this meta tag 00:26:15.309 --> 00:26:18.350 in there. And this works great. 00:26:18.350 --> 00:26:20.739 The, some other use cases for this same approach 00:26:20.739 --> 00:26:24.950 might be injecting csrf tokens if you, you know, 00:26:24.950 --> 00:26:27.669 need to interact with Rails forms from, from your 00:26:27.669 --> 00:26:32.309 Javascript app. Including dynamic analytics params, we had a 00:26:32.309 --> 00:26:36.210 case where the, the Javascript app was kind of 00:26:36.210 --> 00:26:39.129 the, the, a goal page for a Google analytics 00:26:39.129 --> 00:26:41.960 kind of flow. And we needed to set some, 00:26:41.960 --> 00:26:45.220 certain Javascript only in some conditions. So this was 00:26:45.220 --> 00:26:46.499 a nice way to do that. 00:26:46.499 --> 00:26:49.049 If you're using feature flags through something like the 00:26:49.049 --> 00:26:53.980 excellent rollout gem, it's great that that's available throughout 00:26:53.980 --> 00:26:55.450 Rails. But how do you make it available inside 00:26:55.450 --> 00:26:57.789 of your Javascript app also, this is a nice 00:26:57.789 --> 00:27:00.389 solution to be able to kind of inject variables 00:27:00.389 --> 00:27:03.799 along those lines. 00:27:03.799 --> 00:27:07.039 Another pretty awesome thing that we've been able to 00:27:07.039 --> 00:27:09.529 do using this approach is doing A/B testing within 00:27:09.529 --> 00:27:13.639 our Javascript app. And we've experimented with two different 00:27:13.639 --> 00:27:17.220 kinds. One is, kind of, setting some flags based 00:27:17.220 --> 00:27:19.840 on which bucket the user ends up in, A 00:27:19.840 --> 00:27:23.359 or B. This is pretty similar to what we 00:27:23.359 --> 00:27:26.950 just described. And then the, the second is serving 00:27:26.950 --> 00:27:29.600 up wholly different html based on the A/B bucket. 00:27:29.600 --> 00:27:33.249 We'll, I'll talk, take you through each of those. 00:27:33.249 --> 00:27:36.859 So this is using the split gem, which, if 00:27:36.859 --> 00:27:39.210 you haven't seen, is a great A/B tool, A/B 00:27:39.210 --> 00:27:42.419 test tool for Ruby frameworks, web frameworks. It has 00:27:42.419 --> 00:27:45.590 a Rails integration that gives us the A/B test 00:27:45.590 --> 00:27:48.619 method, which you see on line eleven there. And 00:27:48.619 --> 00:27:52.470 so we're doing some injection into our html where 00:27:52.470 --> 00:27:54.649 we're saying, if the user is part of the 00:27:54.649 --> 00:27:58.840 show walkthrough experiment, then we're going to inject the 00:27:58.840 --> 00:28:01.720 script tag that just sets a global variable. And 00:28:01.720 --> 00:28:04.429 then our Javascript app as it boots in is 00:28:04.429 --> 00:28:06.229 running, is, is, can consult that global variable to 00:28:06.229 --> 00:28:08.989 decide whether to show the walkthrough that you're doing, 00:28:08.989 --> 00:28:10.090 doing some testing on. 00:28:10.090 --> 00:28:13.759 And then later, elsewhere in your app, you would 00:28:13.759 --> 00:28:16.830 indicate that, that the goal was achieved, that the 00:28:16.830 --> 00:28:19.720 user signed up or published or whatever it is 00:28:19.720 --> 00:28:22.950 that was kind of the, the goal for you 00:28:22.950 --> 00:28:25.830 A/B test. And so this was great. This is 00:28:25.830 --> 00:28:28.249 excellent for the kinds of A/B tests where both 00:28:28.249 --> 00:28:32.830 paths are supported by your, by a given incarnation 00:28:32.830 --> 00:28:34.700 of your Javascript app. 00:28:34.700 --> 00:28:38.649 We had another case, though, where, this was right 00:28:38.649 --> 00:28:41.259 around the time that iOS7 released and there was, 00:28:41.259 --> 00:28:43.289 if you recall, there was a lot of excitement 00:28:43.289 --> 00:28:46.389 in, around flat design. And so we did a 00:28:46.389 --> 00:28:49.139 redesign of our Javascript app. We weren't immune to 00:28:49.139 --> 00:28:54.559 the hype. And, but as we got near completion, 00:28:54.559 --> 00:28:56.789 we started to wonder, well, we're gonna release this. 00:28:56.789 --> 00:28:58.009 How do we know that this is any better 00:28:58.009 --> 00:29:00.809 than our existing site? Is this going to improve 00:29:00.809 --> 00:29:04.119 our metrics or hurt them? And we wanted to 00:29:04.119 --> 00:29:06.129 try to get some confidence one way or the 00:29:06.129 --> 00:29:06.769 other. 00:29:06.769 --> 00:29:08.929 So we said, well, we've been developing this in 00:29:08.929 --> 00:29:10.950 a branch, and we already know that we can 00:29:10.950 --> 00:29:13.669 preview different versions of our Javascript app, because we 00:29:13.669 --> 00:29:16.090 had this preview mechanism in place. Could we use 00:29:16.090 --> 00:29:18.350 this for A/B testing, also? 00:29:18.350 --> 00:29:21.249 And so, it turns out that we were able 00:29:21.249 --> 00:29:23.840 to just update our deploy scripts to be able 00:29:23.840 --> 00:29:27.450 to deploy from a branch into an experiment kind 00:29:27.450 --> 00:29:30.129 of redis key, and then use the same A/B 00:29:30.129 --> 00:29:33.929 test mechanism to determine, for the new design experiment, 00:29:33.929 --> 00:29:36.190 should the user use the current manifest or the 00:29:36.190 --> 00:29:38.989 experimental manifest? 00:29:38.989 --> 00:29:41.019 Once we made that decision, we then got the 00:29:41.019 --> 00:29:45.440 appropriate manifest id from redis, got the html, rendered 00:29:45.440 --> 00:29:48.499 it, and users either saw our old app or 00:29:48.499 --> 00:29:52.029 the new flat-design app. Turns out, flat design, about 00:29:52.029 --> 00:29:55.919 nine percent better. So good news. 00:29:55.919 --> 00:29:58.259 So this is suitable for changes where your development's 00:29:58.259 --> 00:30:00.210 capping at a branch, and you want to A/B 00:30:00.210 --> 00:30:03.070 between the branches. Not a common scenario, but if 00:30:03.070 --> 00:30:05.429 it's, when it's, it's useful, it was great to 00:30:05.429 --> 00:30:09.830 see how this approach supported that architecture. 00:30:09.830 --> 00:30:11.960 One more possibility that I didn't cover here, but 00:30:11.960 --> 00:30:16.759 you can imagine how this might work, is around 00:30:16.759 --> 00:30:20.239 doing rollback. So what if every time that we 00:30:20.239 --> 00:30:23.590 did this deploy and updated our html in redis 00:30:23.590 --> 00:30:26.259 we pushed into a redis list and said, hey, 00:30:26.259 --> 00:30:29.309 so and so user deployed such and such manifest 00:30:29.309 --> 00:30:31.940 id at this time, and then we were able 00:30:31.940 --> 00:30:33.979 to have a rake task that reads that list 00:30:33.979 --> 00:30:37.299 and lets you rollback to any particular version. Hopefully, 00:30:37.299 --> 00:30:39.460 at this point, you can see how straightforward that 00:30:39.460 --> 00:30:42.200 would, that kind of thing would be as well. 00:30:42.200 --> 00:30:44.039 So, with that, I want to say thank you 00:30:44.039 --> 00:30:47.409 to my colleagues at Yapp Labs who helped create 00:30:47.409 --> 00:30:50.769 this. Kris Seldon, Stefan Penner and Ray Cohen. And 00:30:50.769 --> 00:30:52.229 while we were working on this, we had heard 00:30:52.229 --> 00:30:56.769 some rumors about some Square engineers doing a, using 00:30:56.769 --> 00:30:59.369 a similar approach at Square. So we took some 00:30:59.369 --> 00:31:01.899 inspiration from those rumors as well, and so thank 00:31:01.899 --> 00:31:05.210 you, nameless Square engineers, or if anybody's here. Love, 00:31:05.210 --> 00:31:07.879 love to chat with you about it. 00:31:07.879 --> 00:31:11.820 We've got some time for questions, and so I 00:31:11.820 --> 00:31:14.409 want to open it up to all of you. 00:31:14.409 --> 00:31:15.789 Question in the middle? 00:31:15.789 --> 00:31:17.009 All right, cool. Thank you all so much. Appreciate 00:31:17.009 --> 00:31:19.429 it. Enjoy the rest of the conference.