Rack

Summarized using AI

Keynote: It's been a minute!

Aaron Patterson • May 17, 2022 • Portland, OR

In the keynote address from RailsConf 2022 titled "It's been a minute!" by Aaron Patterson, the speaker reflects on the significant changes in the tech community over the past three years, including his personal journey and experiences since the last in-person conference. He discusses his transition from a poker dealer to a software engineer and shares humorous anecdotes about his experiences in Portland, where the conference is held.

Key points covered in the presentation include:

- Return to In-Person Events: Patterson expresses excitement about reconnecting at RailsConf after three years of virtual meetings, emphasizing the importance of community. He introduces a lighthearted 'Friday hug' for developers in Ukraine, showcasing solidarity and joy.

- Personal Reflections: He shares updates on his life, including his new job at Shopify, his love for cheese-making, and a fond tribute to his late cat, Gorby.

- Software Development Insights: Patterson introduces technical aspects, highlighting the development of a Just-In-Time (JIT) compiler for Ruby called 'tenderjit' and discusses the potential for writing a pure Ruby JIT compiler.

- Rails 7 Features: He explains new features in Rails 7, such as import maps and how these developments are designed to streamline JavaScript integration, particularly for backend developers like him who may not be familiar with front-end coding.

- Overview of Rack: The speaker provides a historical overview of Rack, explaining its purpose in defining the interface between web servers and Ruby applications, and discusses the impact of changes in HTTP protocols on web application development.

- Future of Rack: Patterson encourages rethinking the Rack framework to better accommodate future developments like HTTP/2 and potential integration with WebAssembly (Wasm), which could lead to executing Ruby in a browser environment.

In conclusion, Patterson invites attendees to embrace exploration and creativity in software development, encouraging the audience to evolve alongside emerging technologies and maintain the spirit of fun in programming.

Keynote: It's been a minute!
Aaron Patterson • May 17, 2022 • Portland, OR

Keynote: RailsConf 2022 - It's been a minute! by Aaron Patterson

RailsConf 2022

00:00:12.240 Twelve years ago, I was a poker dealer, and I got laid off at the casino right before my second child was born, my son. In America at that time, you didn't get access to healthcare unless you worked for a major corporation. I hope that changes forever. So, I decided to become a software engineer, as one does, and I moved to Bend, Oregon.
00:00:29.880 I noticed someone in the back here wearing a shirt from a conference called Ruby on Ales. Did anyone attend Ruby on Ales? I see you! Those are my people right here. There aren't enough of us, but hopefully, we can have a revival someday. I met this one guy at my very first Ruby conference, which was Ruby on Ales, before I could even program or had ever spoken at a conference. That man is Aaron Patterson.
00:00:42.600 About half of you have probably been to one of these conferences before, if history serves. Some of you might not know who this man is, but Aaron has been a Rubyist for far longer than I've known him, and I've known him for at least ten years. After meeting Aaron, after many false starts in software over the years, I finally became a Rubyist, and he played a significant role in that transformation. Aaron embodies exactly the values that represent our community; he consistently contributes positive energy to all of us and even fantastical puns on the internet that are, quite frankly, not so fantastic. I've heard them in Japanese; they're worse.
00:01:23.580 He is exactly the kind of person that made me want to become a Rubyist. So I began learning to write Ruby and started speaking at conferences. Aaron is the reason I am here, and I suspect that is true for many of you as well. He goes by Tender Love on the internet. If you go to twitter.com/tenderlove, you too can be Aaron's friend! Let's give a round of applause for our closing talk titled "End of the Day Keynote" by Aaron Patterson.
00:02:12.360 Hello! Okay, it’s like, jeez, if I had known I was going to get that kind of introduction, I don’t think I would have agreed to give a talk here. Wow, wow, wow! I don’t know how to follow that. Thank you so much, Dylan; I really appreciate it. I’m very, very nervous right now. It is RailsConf 2022, and it truly has been a minute. I am your host for this presentation; my name is Aaron Patterson, and I am excited to be here in Portland.
00:02:42.739 How many of you here are from Portland? That’s awesome; that’s really great! I’m from Seattle, and I know that a lot of people think that Portland is just like a mini Seattle, but that’s not true! It’s not fair to Portland. The Starbucks here tastes way better than the Starbucks in Seattle, and I think that’s just not fair! Also, Portland has a lot of really nice boutique hotels, and I enjoy those. I’m actually staying at one for the conference -- it’s the DoubleTree by Hilton!
00:03:22.500 It’s really fancy; you can tell because of the little thing as an accent over the e. Whenever I come to Portland, I really enjoy supporting local businesses, like Nike and Intel. It’s just great! But honestly, this time I wanted to support more mom-and-pop businesses, so I recommend that folks check out the Old Spaghetti Factory. Sorry, Portland people, for laughing — this is really great!
00:03:41.159 I also really recommend you stop by and get a local cup at Dutch Bros. This is basically a small saddle, so I feel like I'm qualified to give you local recommendations. Check out the Dutch Bros on the corner of Couch and Glisan Street. I know the Portland people here are probably so mad at me right now! But seriously, one thing I think is fun is that you should find my brick-and-mortar store.
00:05:00.280 It's been three years since we last gathered for RailsConf in person. Please, let’s celebrate — we made it! We are finally here after three long years.
00:05:20.280 Since this is our first RailsConf back in person, I’d like to joke for a moment — oh, I forgot I'm wearing green screen gloves! Did anyone notice? The reason I'm wearing these green screen gloves is because I know we will be streaming this online later this year. I figured if I’m too boring or something, we can fix it in post, maybe add some wings on me or something like that to make it a little bit more interesting.
00:06:08.820 Anyway, it’s been three years, and I really want to do a Friday hug today. So I’m going to get my camera ready, and let’s do this! We are going to have a Friday hug, and this year, I want to dedicate this Friday hug to the developers in Ukraine. So please, everybody, let’s have a Friday hug — ah, happy Friday! Yeah, I will tweet these!
00:06:31.380 Some of you are probably saying, "But Aaron, it’s not Friday!" Well, the thing is, it’s always Friday somewhere! I want to share some of the things that have happened to me over the past three years. I started a job at Shopify; I’ve actually been there for two years now, which is blowing my mind! It’s hard to believe it’s been such a long time since we've gathered like this in person.
00:06:59.520 You could say Shopify is my current active job. I’ve had that joke in the queue for quite a while! This is a photo of many of the folks on my Shopify team that I met up with in London a few weeks ago. However, I have some sad news to share as well; over the past year, my little buddy Gorby passed away.
00:08:02.699 This is a photo of him doing what cats do best: sleeping on my computer, which was very nice of him. After he passed, I wanted to compile all his photos into a compilation. Unfortunately, it turns out you can only add 5,000 photos to a shared album! But my partner, Evie, and I took a look, and I calculated that we had taken an average of five photos of Gorby per day for his entire life! This genuinely made me laugh.
00:08:50.520 At least I have most of his life documented. Our other cat, the more shy and less famous one, SeaTac, is still doing well. I’m trying to get her to pose with mini hands, but it’s not working too well; it's kind of a struggle, and she doesn't seem to care. I’ve also been making cheese; this is a Camembert I made, and it’s very, very good! But my cheese-making fun has left our house a little funky at times.
00:09:45.180 I made a new headshot, because when you're stuck at home for three years, you have to entertain yourself somehow, right? I bought a green screen for producing online conferences and stuff, and it’s been fun to mess with. However, this green screen cost me about 300 bucks, so I'm trying to use it as often as possible to amortize that cost. I decided to start an online stream; I've been turning into a YouTuber! Please come check out my YouTube page — it’s tenderlove's cool stuff. Make sure to like, subscribe, and smash that bell!
00:10:38.460 Now, I don’t want to brag or anything, but my channel has tens of subscribers! I’m really blowing up here! If you Google my live stream, I’m on the second page — it’s a big deal! Last December, I got COVID. It was awful; zero stars, do not recommend.
00:11:01.260 That said, let’s talk about some of the stuff my team does at work. Our main responsibility is to speed up Ruby and Rails. One of the projects we’ve been working on is called Widget, which is a JIT compiler for Ruby, and it’s shipped in Ruby 3.1, so please give it a try with your applications!
00:11:25.500 I’m not going to dive into the details of this project too much, but I just wanted to mention it. So try it out when you install Ruby 3.1! I do want to talk about JITs for a second. A JIT, like all legitimate ones, generates machine code at runtime. That’s really all it is; it figures out how to generate machine code at runtime.
00:12:02.400 If you think about machine code, it’s just a sequence of bytes, and anything that can put together a sequence of bytes can be used to make a compiler. Interestingly, Ruby can indeed assemble a sequence of bytes; this thought came to me during the pandemic. It led me to wonder: could I write a pure Ruby JIT? Is that possible?
00:12:34.380 The answer is yes; we can actually construct a pure Ruby JIT! That's one of the things I’ve been working on during this time off; I'm calling it Tender JIT. You can check it out right here. I was considering other logos for it, and I thought these could be good, but so far, I've stuck with my original design. I’ve come up with a motto for the project: "Just because you can, doesn’t mean you should!" This seems to fit for about 90% of the software projects I like to work on.
00:13:07.080 How do I know whether I can do something unless I actually try it? By the time I finish a project, usually I’m like, "Oh, I probably shouldn’t have done this!" But it’s too late to change now! Honestly, this tendency led to the development of my high-profile product, the Analog Terminal Bell. I’m not here to sell you on my business prowess — I pitched this product at the last RailsConf. This product has been quite a success; I’ve been raking in tons of clicks!
00:14:01.020 However, I should tell you, I haven’t sold any units yet. The reason for this, I think, is that I’m trying to figure out if there is some online store I can use. If anyone knows how to build an online shop, please let me know!
00:15:04.680 Now, before we dive into the professional software topics, I actually prefer to talk about some amateur software development. I want to bring this mindset of "Just because you can, doesn’t mean you should" to this conference. I have seen so many wonderful talks here that present things you should consider for production, like working with JRuby and other technologies.
00:15:46.920 However, I want to talk about things you shouldn’t run in production, which is a hack that I’m very proud of. This year I finally upgraded to an Apple M1, and I couldn't be more thrilled! It’s such a fantastic machine! But there's a massive issue with it — it's an ARM processor! Unfortunately, both Wide and TenderJIT only work on x86 machines.
00:16:30.640 This works fine if you’re running TenderJIT in production on an x86 machine, which I know many of you are. However, I wanted to differentiate Tender from Wide, so I sought to add an ARM backend to it. At present, I must admit that both of these JITs are indeed legitimate JITs.
00:17:17.640 As such, I developed a Ruby gem called AR264, which you can also check out! AR264 is an ARM64 assembler that is written in pure Ruby. I wrote this gem because I needed a way to generate ARM64 machine code for TenderJIT, but I also wrote it because I feel a lot like many of you in the audience — I’m tired of writing Rails apps in Ruby! I would prefer to write Rails applications in assembly in Ruby!
00:17:56.760 So here’s an example of some code; you don’t need to read it too closely, but essentially, this code example assembles machine code that returns a number. That number happens to be in HEX, and if we zoom in on the actual machine code, you’ll see it puts a value into a register and then returns it. Here, it puts Food Cafe into the x0 register and returns it.
00:18:35.760 But that’s not all I wanted to discuss! Yes, we are effectively writing machine code in Ruby and executing it, but I believe this needs to be something you should really refrain from doing; it’s not suitable. The idea is to express that this work should take on an amateurish tone, like something so silly we’d look back at and say, 'Wow, that’s a brilliant disaster!'
00:19:48.460 Let’s talk about some supporting code. The line here simply says, 'JIT Buffer.new.' The JIT Buffer is an object I created to provide executable memory, because when you are generating and executing machine code at runtime, you need executable memory to hold that code.
00:20:27.720 Therefore, I wanted a generic interface for managing this type of executable code, so the JIT Buffer gem was born. This gem is cross-platform, working on both Linux and macOS, and that wasn’t a big deal! All I had to do was swap out a few system calls to configure it. It also works on any platform; we can leverage it on each machine without any issues.
00:21:07.260 Of course, I had to write tests for this code! Here, we have an example of using the JIT Buffer; we create a new buffer, ensure it’s writable, write some instructions to it, and then we actually call into it. However, I wanted to ensure I could test this on ARM platforms and x86 platforms. To do this, how would I structure my test case?
00:21:54.360 Initially, one might think to use conditionals like, 'If I’m on an ARM64 machine, then I’ll write ARM64 bytes. Otherwise, if I’m running on an x86, I'll write the x86 bytes.' What I really dislike about this method is the complexity of those conditional statements!
00:22:30.120 As professional software engineers know, if statements lead to complexity. Besides, writing these conditionals isn’t exactly ideal. So I kept pondering: Is there a way to ask the CPU what architecture it’s on? What if we posed the question, 'Is it x86 or ARM?'
00:23:07.200 I realized machine code is just bytes and ran a few tests, before discovering that there are indeed valid bytes for both architectures. This means I might smash them together; if I told the CPU, 'Hey, start executing instructions here,' what do you think will happen?
00:23:47.320 Let’s say we run this on an x86 machine — it would interpret the first two bytes as a jump and execute those instructions, moving the corresponding bytes and then the ‘RET’ instruction. Now, if we attempted to do the same thing on an ARM machine, it would unknowingly write some garbage value to X11 that we wouldn’t care about and ultimately return the value stored in X0.
00:24:17.960 So, both of these resulting code paths return the same value: 0x2B. Consequently, I devised a very cool program utilizing this concept; I constructed a table of bytes and wrote them into the JIT buffer, instructing it to start executing from position eight. When invoked, this code results in calling the function, yielding the same result regardless of whether it runs on ARM or x86!
00:24:59.240 What's key about this code is that there are absolutely no if statements present! This logically means that the complexity is effectively zero! It’s that simple, and so these experiments fit my idea of what constitutes fun programming!
00:25:35.800 Sadly, I feel if I wrote code like this at work, I’d get a mixed reception. About ten percent of my colleagues would think it’s genius, while the remaining ninety percent would likely despise it! Not that I'm against writing this type of code in a professional setting; I still want to find enjoyment in what I create.
00:26:18.500 Upon reflecting, Javier’s keynote this morning resonated with me because he addressed solving problems just for the fun of it, which is precisely what I am trying to do here. I am not going to discard this code; it’s sticking around forever. Ultimately, I want to foster the same spirit of enjoyment when developing applications!
00:27:01.200 Now let's talk about Rails — I mean, we’re at RailsConf, so I think we should focus on Rails for a bit. But before jumping into that, I’d like you all to take a look at the anatomy of a Tender Love talk.
00:27:45.720 Here’s my TED talk about Tender Love talks: My talks usually follow this format. I start with jokes about local businesses, then showcase some pictures of my cat and life updates, followed up by some bizarre code that's highly enjoyable but not necessarily relevant to our primary topic.
00:28:06.860 This leads into a main topic where I discuss some essential things, and finally, end with an abrupt conclusion after running out of time. Without further ado, we are now at this crucial moment in time! Recently, I noticed that this particular section has been dragging a bit, and that’s because I want to dive into two topics: new features in Rails 7 and an overview of Rack.
00:29:06.540 I can discuss Rack all day; no problem there! However, I am somewhat worried about talking about the new features in Rails because the first thing I want to delve into is my absolute favorite feature of Rails 7, which is the fact that there’s no more Spring! While deleting old code might not necessarily count as a new feature, I decided to check out this fantastic blog post that provides a comprehensive list of all the new features present in Rails 7.
00:30:10.300 So, I compiled this entire list. Here are all the enhancements made in Rails 7: import maps, Hotwire, default Turbo, and Stimulus 3, JS bundling, and more. However, before discussing these highlights, we must address the rather large elephant in the room, and this is why I have been stalling on this presentation.
00:30:45.620 I know this statement will be controversial, but the fact of the matter is — I am not a front-end developer! I have no idea what any of these things are. But that’s okay because these tools are actually designed for folks like me, who aren’t very proficient with front-end development, to simplify that process within Rails applications.
00:31:28.740 In fact, I am extremely excited about one particular feature: import maps and ES modules. Even though I’m a back-end developer, I can still appreciate how import maps offer us three different methods to include JavaScript files in our applications. Yay!
00:32:01.440 So, I want to go through an example of using import maps in a newer application. Upon creating a new Rails 7 application, you will see an additional tag in your application HTML layout, which is the JavaScript import tag. Within this context, we also have a new configuration file called importmap.rb, which defines all that’s going to be included in the import map for the application.
00:32:39.920 Furthermore, if we make a request and examine the application’s source code, we’ll see that there’s now an import map rendered with all these features, which Rails automatically generates for you. One of the great things about the import maps Rails gem is that it allows us to pin libraries. For someone like me who might not know much about what pinning entails—it simply means adding things to the hash!
00:33:31.560 As for the command line, it allows you to run a command to add a library to the import map, hence adding more functionality. I’m demonstrating how to add lodash to the import map, where you enter a version and, when you navigate the webpage again, it accurately reflects that change in the source. Reload the page, and you’ll see it outwardly references an external JavaScript file, allowing you to import and utilize it! So I put this to the test and ran the code, and yes! It worked!
00:34:25.160 Cool! I'm now a front-end developer! Thank you for your support! So, import maps are incredibly easy to use, and Rails makes them even simpler; however, there's even more to enjoy as a developer. Even as a back-end developer not involved in front-end tasks, I appreciate that we can import modules by a specific name instead of referring to the asset file itself, which includes some hashes at the end for caching purposes.
00:35:14.240 You might remember Rails 2 when it would append a timestamp at the end of queries. However, this methodology proved problematic, necessitating the migration of the hash into the file's name. It's intriguing to think that these import maps allow us to access files without worrying about the hashes, as we simply need to refer to the names!
00:35:54.840 Additionally, using import maps means that we’re no longer bundling JavaScript, which can create complications. However, by referring to these standalone JavaScript files, this approach actually improves caching, as the web browser can download only the broken parts rather than the entire JavaScript. Of course, it does introduce a problem — we end up with more requests to our server! This isn’t necessarily an issue if you are using HTTP 2 for concurrent requests.
00:36:40.480 This transition brings me to discussing rack. Yes, I transitioned away from JavaScript to speak about rack! I want to outline what rack is, where it came from, and the future it holds, as I believe there are many new Rails developers amongst you who may not understand its significance.
00:37:22.440 Rack is a library that defines a specific interface. For instance, our scenario includes a web server and a Rails application. Rack essentially outlines how these two entities communicate. Moreover, rack doesn’t have to be integrated directly into the application; it mainly defines the interface. If both the web server and the app agree to utilize this interface, you swap them out without any hassle.
00:38:45.600 Consider this as a practical example: we can substitute out the web server being used today for a completely different one tomorrow. The interface remains unchanged, which is a huge benefit! Let’s take a closer look at the actual structure of rack interface—this example represents a rack application interacting with a test web server.
00:39:58.760 The web server gathers the request data, encapsulates it in hash form, and passes this hash to your application. In turn, your application must accurately respond to the method call and return the proper triplet: status, headers, and some type of body to print out.
00:40:43.600 I want to talk about rack as it pertains to HTTP today. HTTP is an extraordinary stateless protocol – the client doesn’t need to track the server, and the server doesn’t need to remember the client. We can pass cookies around seamlessly! Of course, numerous hacks have arisen from this primary structure.
00:41:30.840 Let’s analyze the timeline of HTTP. We can review significant dates correlated to the various RFCs that have been released throughout the years. Beginning with HTTP 0.9, we create a TCP connection, and in essence, execute our HTTP request, leading to the output that returns to the client.
00:42:27.480 When that's done, the browser tears down the TCP connection. The web server transmits data to the CGI script via environment variables! Therefore, the reason we refer to this hash in rack as 'env' is due to those environment variables that were originally utilized for CGI scripts.
00:43:21.920 Now we enter HTTP 1.0, which highlights some existing problems: connections are costly to manage, and due to the nature of serial requests, each new one had to be queued until the current request completed. Couldn’t we download images in parallel alongside the HTML while it’s processing? Step in HTTP 1.1, which introduced keep-alive connections — allowing multiple requests from a single connection!
00:44:12.580 Initially, connections aren’t simultaneous; however, once the browser has received the HTML, it can leverage the second connection to pull through images or additional resources at once. Nevertheless, this prompted many developers to bundle assets together to prevent excessive requests, hence the popular use of sprite files.
00:44:59.700 Ten years later, we release Rack 0.1, based on PEP 333, a Python benchmark for the WSGI framework. Rack serves as an HTTP translator, detailing how to convert HTTP requests into Ruby data structures and to relay responses back to clients. Put simply, using hashes instead of environment variables made it easy to support switching between different web servers.
00:45:46.160 With this newfound flexibility, new web servers emerged, including Passenger and Mongrel, which were compliant with Rack. As time progressed, in 2011, websockets were also introduced! These allowed for a bidirectional communication pathway between clients and servers, contrasting the previous standard where applications would conclude once they dispatched requests.
00:46:34.120 Although websockets were not technically a part of the HTTP standard, they functioned seamlessly alongside it. Therefore, in 2013, Rack 1.5 was released to accommodate websockets while adhering to the same structure present in prior web servers.
00:47:20.360 These modifications expanded rack’s role from merely an HTTP translator to a seamless provider of sockets along with improving server communication. Now let’s leap to 2015; HTTP 2 has now joined us! It’s truly remarkable! Moving forward, it’s essential to recognize that our interactions are now conducted over SSL, which is effectively a requirement to unlock the abilities of HTTP 2.
00:48:12.580 Moreover, HTTP 2 allows for compressed headers and acts as a binary protocol, clearing the effective request/response multiplexing dilemma. We no longer have to wait for each connection’s prior request to finalize as we can perform multiple requests in tandem. This connectivity works harmoniously with the relaxed import maps.
00:48:59.180 Now we arrive at an existential question: Do we truly need H2 servers? Numerous features can be acquired through proxies. Do we genuinely require technology inherently rooted in Ruby for specific pathways? While it can indeed present necessities in certain scenarios, for example, when you can’t utilize proxies, there are times where it makes sense. All of this contemplation leads us back to rack.
00:49:47.440 What does this all mean? Are there additional API updates required to accommodate H2 or simplify hijacking — especially considering that H2 utilizes the same socket for all requests and responses? As I reflect on the use of rubberizing lambdas in hash formats, I question whether this is sustainable considering what I’ve seen previously in other projects where developers pass around promiscuous hashes.
00:50:30.360 Finally, as I near the end of my keynote, I want to mention one last aspect: this entire conversation could be “moot.” Ruby 3.1 has been shipped with WASM support, enabling Ruby to execute natively within your browser! Take a moment to examine this website, rubysyntax3.github.io, that one of my colleagues, Kevin Newton, created. It’s honestly incredible!
00:51:11.680 Imagine that just around the corner from now, we may very well end up running Rails in the browser while having React all handled on the server side. Thank you, everybody! I look forward to seeing you all next year!
Explore all talks recorded at RailsConf 2022
+68