 Welcome to my webinar. Thank you for coming, everyone. One thing that I like to do a lot is laugh. So I say this phrase very frequently. Where are my subtitles? I thought we had subtitles. Oh, well. Anyway, I was hoping that this would be on the subtitles. So we say this in the United States a lot, LOL. And so I've been studying Catalan because I'm here in Spain and I understand that apparently in Spanish it's LOL. As you can tell, I've been studying very hard. Hi, my name is Aaron Patterson. You might know me on the Internet as Tenderlove. I work for a company called Red Hat. That is where I work. I'm on the manage IQ team and we build software to manage clouds. So if you have a cloud, we can manage clouds and our software is open source. So you should go there and check it out. It's on GitHub. So you can go see it if you want to. I own two cats and I need to show them off. This one is, this is SeaTec Airport Facebook YouTube. She's named after the airport and Facebook and YouTube. That is what she's named after. This is another picture of her. She likes to sit on my desk while I'm working. This is my other more famous cat. This one is Gorbachev Puff Puff Thunder Horse. That's my second cat. And actually I have stickers of him with me. So if you would like a sticker of my cat, then come say hello to me afterwards and I will give you one. Just say Aaron, I would like a sticker and I will give it to you. So I'm on the Ruby core team, the Rails core team and the Rack core team. And that last one is important for this talk. We'll talk about that in a bit. And I'm really happy to be here at Barucho. So thank you for having me. I'm really honored to be here. Thank you so much. I'm also happy that this is part of the full stack fest. Although I have to admit, I'm not sure why you're allowing me to speak here because I'm actually just a short stack developer. Yes, you knew there were going to be pancake jokes at this conference, right? Anyway, I have one product announcement that I want to make here before we really get into the meat of this talk. We heard earlier Brian was talking about 12 factor apps. And well, actually I want to announce that today we're releasing 13 factor apps. It's one E0 factor better. So I know a lot of you are developers. You're probably app developers. I want to talk to you about apps. I really want to talk to you about apps. Especially, I know a lot of you, we're all developers here and you're probably developing multiple apps, right? Maybe not right now, but in the past you've developed one or more applications. And in the U.S., we like to refer to this as NN applications. But typically we shorten that to naps. Or as you call that here in Spain, siesta. I told you, I've been working on my Spanish. So yeah, that's pretty much it. Please fill out the speaker cards. Vote me number one. We're going to go take a nap now. Well, thank you. Thank you very much. We can end it now. Thank you. I wanted to make a joke about apps and tapas, but I couldn't quite figure that one out. Sorry. Oh, I should talk. So last night, oh man. So last night we go out. This is off script. I'm going off script here for a minute. We went out for dinner last night and we're leaving. And Brian says, ah, it's rained. It's definitely rained. And I was like, no, that's impossible. And he's like, why did you say that? And I'm like, well, we're in the city. And he's like, what do you mean? And I said, well, it's because the rain in Spain falls mainly on the plane. And I almost hurt myself laughing. So basically that's what it's going to be up here is me 30 minutes making stupid jokes and laughing at myself. So really this talk is for me. Anyway, OK, OK, OK, let's let's talk about some tech stuff. So I want to talk about the request and response system, the way that that works in Rails. And I want to talk about basically the future of that. We're going to talk about HTTP 2, which I will from now refer to as H2 because HTTP 2 is way too long to say. And I don't want to say that over and over again. We're going to talk about rack. And then we'll look at the Rails request and response pipeline, how a request and response goes through the system. And then at the end here, we'll talk about the future of Rails, Rack and H2. So the first thing I want to look at, we're going to look at H2, but I want to look at it from an app developer's perspective. So I mean, we work on applications, and I don't really care about the protocol necessarily. I care about what can I build with this or what can I do with this. That's what I really want to talk about this is from an app developer's perspective. So first we'll take a look at the benefits. Some of the benefits are that it's a binary protocol, which means it's more compact over the wire. It's easier to parse. There's only one parse path through the parser. Only one code path you have to go through in order to parse a response. But that's not always a good thing. It means that we can't just look at the data over the wire and understand exactly what's going on. It's binary. You can't just look at it and say, oh, that's what's happening. So that's one downside. Another upside is that it's multiplexed. And what that means is that we can have multiple requests and responses going over one socket. So today we'd have maybe multiple sockets for multiple requests. If you want to do requests in parallel, you have to open multiple sockets to do that. So for example, this would be an example of the network today. We have one client making many requests to the server for assets or whatever. And maybe, of course, there's keep lives and whatnot, but we'll ignore that for now. There's probably many open connections. With H2, it'll look something like this. We'll just have one connection, and you'll do all of your requests and responses over that one particular connection. Another advantage is that it has header compression. So all those headers, all the HTTP headers, get compressed before they're sent over the wire, and that actually saves a lot of data. And another thing that's a good benefit is it uses SSL, but doesn't have to. Actually, when the H2 spec was approved, the SSL requirement was dropped from it, so you don't have to do H2 over SSL. But browsers today, like I said, we're going to talk about from an app developer perspective. The only browsers today that implement H2, Chrome and Firefox, I think Safari does, but only on the new betas of OS X. Chrome and Firefox only do H2 over SSL. So you don't have to, but it does. Another nice advantage is you can do server pushes, so you can say, like, okay, I know that the client is going to need this particular asset, so I'm going to push it down to the client in advance. Like, let's say you're building some sort of, I don't know, an Ember app or something that typically what you would do is embed that first JSON payload in the HTML and send it down. Now you don't have to do that anymore. You can do a JSON payload down with a server push. Now, one thing I want to talk about is how to tell whether or not you're using H2. This was a problem for me is, how do I know that I'm actually using it? When you look at the browser, you can't necessarily tell. In Chrome, what you do is you go to the special URL here. If you go to this URL, you can see the connections that you have open. And this is what it will kind of look like. You'll see this. You can see it's open to localhost, port 3000. And the protocol is H2. So you'll see right there. Now, what's cool is, there's a bunch of other stuff there, too, that's like, whatever, I don't know, some stuff. Anyway, what's neat is that in this demo, you'll see up here I have multiple tabs open to the same, I have like five tabs open to localhost. But, yes, my nice little transition there. Look at those beautiful tabs. All of those tabs are open, but in the previous slide we saw the connection settings. There's only one connection open. So, like I said earlier, that it shares, you do all of your requests and responses over one connection, and that even goes to multiple tabs on your browser. So despite the fact that I have five tabs open, it's only maintaining one connection back to the server, which I think is interesting. Another thing you can see is, if you click protocol here, you can add protocol in the debugger, and it'll show you the protocol for each of the requests, and you'll see when I add that, you get a protocol column, and all of those indicate H2. Another way to tell that you're doing H2 is you'll see all the headers are actually lowercase. So they're standardized on lowercase headers, which is like, yes. Yes. Very happy about that. And then we have down here these special headers. You'll see there are special headers that start with a colon, and they indicate the different parts of the request, like the path and the verb. Those things that would be in the first line, those are actually broken down into special headers, and those ones start with a colon. So you can tell that you're using H2 from there as well. Now, if we look at Firefox, Firefox, I have to admit, is not nearly as user-friendly with this, with regards to this as Chrome is. If we look in Firefox, you can see, basically, the only way I could tell that I'm using H2 in Firefox is right there. That says X Firefox speedy H2. And what was really, really annoying about this is, as I'm doing development work, I'm not sending that header. That's just inserted by Firefox. Firefox just inserted that and was like, hey, here you go. Here's this header that you didn't send. Like, how did that header get there? I don't know, I just added it. There you go. Anyway, so, all right. We know how to tell whether or not we're using H2. We can see from the browser, we see what the connections look like. Now, let's start talking about Rack and then move into Rails, and then how we'll get H2 with Rails. So here's, we're going to talk about Rack. This is what the API looks like today. This is a very simple Rack application. What happens is Rack calls your object with call, and it passes an environment, and that environment is a hash, and an array, and that array contains all of your response information, like the status code, the headers, and then the body. This is the entire API, and this works, this API works, and I also think this API is successful, and I was thinking about this, and I think the reason that this API is successful is because it's easy. It's very easy. You can look at that code and you see, hey, that's our whole application there in a few lines of code, no problem. It's very easy. And one problem that Rack solves, I mean, the API is easy, but I don't think that's the main reason that Rack is successful. I think the main reason that Rack is successful is because it helps us avoid an explosion of dependencies, and it does this through the adapter pattern. And what I mean is, right here we have a bunch of adapters. All of these web servers speak the Rack protocol, and then all of the application servers, also speak the Rack protocol, and then we just converge on that one place in the middle. Now imagine a world that we didn't have Rack if this, such a world existed, rather than having this one gem in the middle there, we would have to have, like, you know, unicorn rails, passenger rails, Puma rails, Webrick rails, every single combination of web server plus framework. Rack solves this issue, so we don't have to have this explosion of, of dependencies. So one thing, the next thing I want to do a little bit here is, I know that there is, I mean, a dark side to this conference, and this dark side is coming in a couple days, and I believe that is the JavaScript side. So we're going to get a little, a tiny little preview of that, so this is what I want to compare Node.js with Rack. This is the top one there is a very simple Node.js application, and then the very bottom one is a Rack application, and we're going to talk about that a little bit later, but I just want to show this to you to kind of get your minds, like, rolling a little bit. You can see the differences here is that in Node you get a request and a response object, and you don't return the response. That does not happen. You actually write the response out to a response object where with Rack we can end and we actually have to return the response. Okay, so just think about that a little bit as we journey through the rest of this talk. So let's talk about Rack middleware. Yes, Rack middleware, one of my favorite things in the entire world, and if you follow me on Twitter I'm sure that you'll notice how much I love Rack middleware. Rack middleware is all those effing frames in the call stack when I do puts caller. I do a lot of work with Rails, the framework itself, and I'm looking at all the stuff in the stack itself so typically I'll be in the controller doing puts call and look at all the stuff that's in there. So all those things in the stack are pretty much Rack middleware. Okay, there's Rack middleware in there. How does Rack middleware work? All right, here's how Rack middleware works. Today we have the Rack API which we've looked at. Rack middleware looks something like this. Basically it's a linked list. We have a middleware which points at another middleware which points at another middleware and it just calls down that chain of middlewares until it finally middleware. I'm not sure how to pluralize that. Middle something. All the way down until something returns a response body. And this is what it looks like. We say okay, the next application, we hold a reference to that, we call the next application and then maybe we do something with a response like for example we add a header and then we return that back up to call stack. So, what I want to do is we're going to do something a little bit interesting. We're going to look at all of the middleware in the Rails stack and I know this is going to be super exciting because all of you have just eaten lunch and you're just thinking to yourself wow, I'm in a room, it's kind of warm, had that great lunch. I'd just love to hear about all of the rack middleware and what it does. That's exactly what we're going to do. We have an application here that we have an application with one resource, resources post. That's it. Post. We just process post. Done. One simple Rails application with that. Now somebody comes along and we're going to imagine what happens is we have a request, the request comes in and the request is for get users. This is the request that comes in and what we're going to do is we're going to find out what happens to the request all the way down the Rails stack and then back up. We're going to look at every single middleware all the way down. Now I have to deal with this on a daily basis so I'm going to make you deal with it today. The first thing that happens is of course the web server parses the request and sends it off to the next thing and sends that request off to our rack middleware. The very first thing that it hits, the very, very first thing is Rails application, an instance of Rails application. This is the very first thing that it hits. If you look in that stack you won't ever see Rails application. Your application, your Rails application actually inherits from this. It inherits from Rails application so you won't see this. You'll see your app. Your app. This is the very first thing that it hits. The very, very first thing that it hits. It hits your application and this is the stuff that it does. Builds a request object and you can see that there is the end hash going on there and I included both of these because it calls super. The top one is lower in the stack and that bottom one is the super call unintuitively. This is exciting. Let's hit our application. We requested our application. We should be done now. We're done. We did it. Here's the next one. You know what? This one's rack send file. This is in charge of sending files. The description is something like this is a send file, this middleware, something, something. You know what? I only have 30 minutes. We're just going to do this. There's all these. I don't know. I mean, there's many, many... Many... Many... We're not done yet. Okay. Okay. No, still not done. Okay. Still... Okay. Okay. Now we're done. Okay. No, we're not. Sorry. So after all of those middleware, which I'm sure you're very interested in what all of them do, and I will post these slides later, the slides I put in there really are descriptions of what each of the middleware does, and you can ask me after this talk. We can talk about it all you want to, or all we want to, but I figured we've had lunch. It is warm in here. Nobody cares. So after all of those things, finally we hit the router. This is where stuff gets real. Right? It's time. It's time. We're actually going to send this request to the controller. Right? We hit the router right after the router is going to hit the controller. Okay. This is it. This is it. We're excited, right? Everybody's excited. We went through all those slides to get here. Finally, we did. Remember, we have an application with one resource, resources post, and then, boom, 404. Sorry. Okay. I have music to go with this next slide, but I'm not plugged in, so we're just going to watch the slide. I made this slide. This slide took me forever, and ever. And I was playing the music over and over and over again, and my wife is like, what the hell are you doing? And I'm like, this is work. This is really work. We're going to go back to the stack. That stack that we went through, all those slides. Imagine that we flipped that upside down and turned it into a mountain. Imagine that it's a mountain. Right? This is what it would look like. Okay. This is our mountain. And what happens is we're climbing the mountain. We're going along here. Just imagine, like, you're climbing that mountain. We're doing really good. We got this request going. It's going through our system. Going along. Finally, we reach the top. Almost get there. The anticipation is killing me. We get to the router, and then, oh, sorry. 404. Not found. So I'm really sorry. I'm really sorry I put you through all of this. Now, okay. Clearly, this has some problems. There are many problems. I mean, one of the problems is it's just too long. There's too much stuff here. There's so much stuff going on. Honestly, it's just way too boring. Really, who's going to dig through all those middleware to figure out what's going on? Well, honestly, the main problem, though, is like, I kept thinking about this, and I'm like, why is the router actually buried so far? Do we really need to go through that entire stack just to figure out, oh, it's 404. Can you imagine how frustrating that is? Like, I'm sitting there. I'm running a request through. I sit there. I look through all the middleware, and I'm like, we executed all of that stuff. All of it. Just to return a 404. I'm sitting there like this. Why? Why? Come on. So one thing I would like to do in the future is maybe take the router and move that further up the stack so we can say, okay, let's return a 404 ASAP. So why, you know, why are there so many of these? Ah, it's here. Okay, hold on. Uh... LOL. Okay, okay, now let me try it in Catalan. LOL. I don't like that one. I think I broke it. I broke it. If you don't do public speaking, you definitely should. Just for doing stuff like this. All right, all right, all right. So let's talk about rack API limitations, and then after this we're going to move into H2 and Rails and what our path moving forward is. So obviously we saw that huge stack of stuff. So middleware, one of the problems with rack is that if you think about the middleware that we have today, there's only one type of middleware. There's only one middleware. We have a thing that calls stuff, but when you think about that just keeps calling down the stack, but when you think about the tasks, the different jobs that these middleware have, they're clearly different. For example, you have something that maybe you need to check out a database connection at the beginning of the request and then check it back in at the response, but you really don't care what happened in between. You don't care at all. It makes no difference to you, right? So, oh, I'm getting ahead of myself. Let's talk about the rack API itself first. So this is our rack API. This is it. We said it was some office. LOL is gone. So this is the API itself, and the first problem that we have with this API is the end hash itself. So we can't really change the type of this hash or the type of this object. If you look at it, there's a number of methods that are on a hash, and if I want to quack like a hash, it's nearly impossible. Now, the other problem is we can't change the keys. So what's really, really nice about objects is if you typo on a method name, you get an exception. That's really cool. If you typo on a hash key, you get a nil, and you're like, well, did I do it right? Was it supposed to be set? Was that supposed to be in the hash? Am I just missing it? Or did I typo? You have no idea what's going on. Actually, you know, I don't we're programmers. I don't need to tell you why using objects is better than just using random hash keys. I don't think I need to tell you this. So we have stuff like this too. You'll see here that our hash is this hash-driven development is coupled to these hash keys. Apps are coupled to these particular key names. Another annoying feature about this API is that hash access encourages allocations. You'll see we have those strings there that get allocated every time we execute this code. For example, that string will get allocated. It actually gets allocated twice when the code is executed and then another time when it's duped and when storing into the hash. Now, this type of stuff isn't going to happen when you're hidden behind an object. So the next thing we have to look at is the return value, which is this array, and again we have some similar problems here. We can't change the type. I mean, we have all those methods which means what if someday I want to put that status code at the end of the array? What if I just want to put it at the end of the array? I break everyone's applications. I can't change the layout of that array at all. It's coupled to that. The other problem is this API makes streaming very, very difficult. We actually have to put essentially a promise in that last position in the array. It's not actually an array of strings. It would have to be a thing that quacks to the end of the array. Another example, a more concrete example, is adding a header. Let's say I wanted to add a header to the response. I'm going to write a middleware that adds a header to the response. Here's my middleware. It's going to add two headers. Basically, we've got one. X Cat, Gorby, another one that's X middleware, belt. All right. So we add the header. We add the header and all that stuff. Our object graph looks like this. We have the web server. The web server points has a reference to the middleware. Then the middleware has a reference to our application. The way that the data flows through the program looks like this. We have the client. It sends data to the web server which sends it to the middleware. The application sends it back up. The middleware adds that new header and then it gets sent on to the client. What's interesting about this is you'll see that the header didn't get added to the response until after the client had an opportunity to finish. We had to hand off everything to the client before we could add that header to the response. Now imagine that our application now wants to stream data to the client. So let's say we add that in. Let's look at the data flow if we do streaming responses. The same thing happens. The client sends data down here, keeps sending down. Then the application directly sends it back up to the stack. The response clearly does go back up the stack, but we sent data to the client via some other means, not via the stack. On the left-hand side we have a stack and on the right-hand side we have IO. We're doing communication on the left with the stack and communication on the right with IO. Our response is coupled to the stack. That middleware is coupled to that particular stack. You could even say that the response is coupled to the full stack. Conf. I heard the groans. I could feel it. I could feel it. I think I even saw someone just go like this. All right. So the question is what should we be doing? What should we be doing instead? Instead I think what we should be doing is something like, well, I'm really sorry to say this, something like Node.js is doing. Where we're actually writing out a response. We should be writing out a response. We should be using objects with small APIs. We want to use small APIs so that we can actually replace those objects with something else. If you wanted to have a custom request or a custom response, it's impossible to do today. I'd also like to add a context for allocating request and response objects so that we can have application servers that decide what type of request and response they have. Another thing that I would like to do eventually in RAC is essentially eliminate the concept of middleware, which I think is interesting. If you look at Node, if you look at Node today, you'll note I'm really sorry we're talking about JavaScript. If you look at Node today, you go install Node. It has no concept of middleware. That does not exist. It's not a thing. You actually have to install something else like connect in order to get middleware with your Node applications. And I think it's really cool. And I think it's cool because it actually encourages competition in the JavaScript space with regard to middleware. And I would like it if we had that same thing. Although I do have a suggestion for middleware, which would be three different types of middleware. I think going through every single middleware in the RAC stack in Rails, I see these three different types. Essentially, we have event listeners, things that care about different types of events that occur in your system . We actually have content filters like gzip, things like that. And then we have content producers. So your application is actually producing content. I also want to take a look at my desired H2 API. Essentially, it would look something like this, where you just get a custom request object that has an HTTP to question mark method on it. So if you say, hey, is this an H2 request? If so, I want to push some data down. If not, I'll just do the normal thing. So I want to show a concrete example here, because this is a technical talk. I'm giving technical information. I want to show a concrete example. And I don't really want you to read this stuff. I just want you to notice the, like, look at the shape of the code and look at how long it is and note that it's not super hard. This is our basic example. And we can say, like, we only respond, this is a basic H2 server. We only dispatch our request or dispatch to the application if the headers have been finished streaming to us. And then we write a body out here. And I want to zoom in on that one particular method, because I think it's important. Right here, we talked about earlier, H2 shares IO objects. So there's only one IO stream, which is kind of interesting. When you think about the consequences that has on, say, multi-part posts, right? You think to yourself, well, I'm going to parse the multi-part posts, so I'll just grab that IO object and read off of it until I parse all the stuff on there. But you can't do that with H2 because we're actually doing multiple requests and responses over the same socket. So the way that that's actually handled is there's IDs for each particular stream. And you'll see here that's the stream ID. So for this one request and response, this is the ID for that particular stream. So here's our Web Brick. I did a Web Brick integration for this. And basically I can look at the protocol and say, hey, is this H2? If not, I call super, and then Web Brick does its normal thing. Okay. Then we have a response here. That's my default one, hi mom. I always use that because I love my mom. So I just every time I do that. So this is our response object integrating with Web Brick. And again, I don't want you to read this particularly, but I want you to notice that it's actually a subclass of Web Brick's normal response object. Same thing here with the request object. It's a subclass of the normal request object. So from you as a client, it looks just like any other application. It looks exactly the same. The point I want to drive home here is that I think we can integrate this into our application servers and have it be completely transparent to you as an app developer. So anyway, after that I served it up. And you can see this is our 404 not found page with H2 from Web Brick, which I think is exciting. And then we have, you can see the response there was 4 milliseconds. So that's like, I like that. That's very nice. Protocol H2 with a real response. That says hi mom, of course. So let's talk about Rails integration and then I think we can finish up. So I want to add event handlers. If we add event handlers in the middleware, this is the justification I have for adding event handlers. We have one middleware called rack lock. This one essentially takes out a mutex around your request and response. This is what it looks like before and it doesn't, this locking mechanism doesn't really care about the actual response itself. So if we just use event handlers, this is what the code cleans up to and it's much nicer in my opinion. And in fact, it's more performant as well. The previous code had three allocations, eight method calls and one conditional and we actually reduced that to zero allocations, two method calls and no conditionals, which I think is a nice improvement. So what I've been doing is if you go look at my commits through Rails, you'll see recently everything I've been doing is essentially converting end hashes into requests and response objects. So the legacy conversions that I've been doing in Rails, because Rails is a legacy code base, is essentially wrapping all end hashes into a request object and then accessing methods on those. So our old code might look something like this where we're directly accessing that end hash. So in order to make the code forward compatible, what I'm doing is essentially turning that end hash or just calling methods on the request instead. So I just do that. Basically I implement a method called session and have it do that call itself and then in the new versions we will just not have the hash. So the result is something like this. Yes. This is Rails on H2. Rails running H2. Okay, so I want to finish this up with some, this is our future here, it looks nice. I want to finish up with some H2 issues. I like to call them Htt problem. But these are, these are all over SSL so it's Htt problem. So even in H2 the header values still suck. There's been nothing to improve the headers except for standardized on lower case. So all the keys are lower case, that's great, we're all very happy about that. But the values, for example, anybody who's had to parse cookies or parse any of those header values, it's exactly the same. We still have all of that annoying stuff there. Another thing, annoying thing is that browsers are dumb. So for example, we were talking about pushing responses earlier. One question is, can you push assets twice? Can you do that? And the answer is yes, you can. You can just push that asset down as many times as you want to. And the browser may or may not reject it even if you push the same one over and over again. So if we think about it pushing that same one, that actually sounds very inefficient. Ideally you'd only want to push it once. Right? You only want to push that asset down once. One way I think we can get around this is we did talk about earlier how the browser maintains one connection open to the server. We have one connection open always. So since we have one browser or one context for each browser, we can say, okay, in that context we'll just keep track of different assets that we've pushed. And if the application tries to push an asset that we've already pushed, we'll just say no. Now, we can't do this in production. The reason we can't do this in production is because maybe somebody's browser, well, maybe we could do it in production, but a browser could stay open for days and days and days, and they actually lose a connection with the server and maybe we don't want to push again in that particular case. So there are edge cases there. So anyway, I was saying we don't want to do that. We may not be able to do this in production. One thing we can do, though, is we can say, well, if we're running behind Nginx or something which does support HTTP2, we can actually insert link headers in our response codes and Nginx will take care of that for us. It'll actually do the pushes for us. So we don't have to deal with it on the Rails side at all. We can just insert those headers and Nginx decides what to do. So why do I want to do this? I'm sure you've requested it in this, and I'll tell you why. Our application at work has tons and tons of assets in it. If you go look at that repo I pointed out earlier, I encourage you to go take a look at it. We have tons of assets in our application, and when I load that app in development, it's not fun. I don't know if you have old apps like this with lots of assets, but you just sit there and you watch all the things go by and you're like, yep. Loading a page. So ideally what I'd like to do is be able to take advantage of this in development. Especially what I want to do is I want to see stuff like this where we have the style sheet link tags in our ERB or Hamel if you're using that, whatever you're using. We have the style sheet link tag and we can inside of Rails, we can actually leverage that to say, hey, I know that they're generating a style sheet link tag now. I know that this is a CSS they want to have pushed down to the client. We could also do that with JSON Assets too, so if you want to push down JSON payloads with your Amber application. And there's other benefits, but my personal goal for doing this is that I want to have a very fast development environment. That is what I personally want. I'm a developer. I like fast development. So future work, things that I'm going to be working on in the future here coming up, integrating a push server with Rails, getting all the tests to pass. I'm sorry. I should have written that in Catalan. LOL? Did it show up? No? Anyway, another very important thing is backwards compatibility. So we need to make sure that we support the old rack environment and hash middleware stuff. As Matt said during his keynote, compatibility is extremely important and that's very true for me as well. I don't want to end up with Rails 5 being like Python 3. Can I say that? Is that mean to say? I'm sorry. I don't mean any offense, Pythoners. I love you all. All right, so conclusion. I will conclude this with, Ruby's strength is OO. Really, it's an OO language and we should use that strength to our advantage. So thank you very much.