Aaron Patterson on Ractors, Faster Gem Installs, and Why He Can't Fully Trust AI-Written Code
Ruby on RailsIn this episode of On Rails, host Robby Russell talks with Aaron Patterson, known online as Tenderlove, a senior staff engineer on Shopify's Ruby infrastructure team and a longtime member of both Ruby and Rails core. The conversation covers the low-level work Patterson's team does on the Ruby interpreter, including true multi-core parallelism with Ractors, a JIT compiler, and garbage collection. It then moves to a proposal to make gem installation much faster by changing how gems are named and addressed, a trick for letting a JIT compiler see through C extensions, and how Patterson uses AI day to day. Across the whole conversation, Patterson's stated goal is to make Ruby and Rails faster and easier to start with, without application developers having to change anything.
Why Rails, after all these years
Asked what keeps him on Rails, Patterson gives two reasons. First, he says Rails is still the easiest way to build a website and get an app built. Second, Rails keeps up with advances in web technology. It is not a framework that was built once and then left frozen. He adds, half-jokingly, that he is "not good at building websites at all," and that Rails makes it easy even for someone like him.
His path into web development began in 1999, straight out of high school. A friend working at a car dealership needed a website, so Patterson built one. It was dynamic: Perl CGI scripts plus JavaScript, deployed by uploading files over FTP, with CVS for version control. He stayed about a year, but web development became his career. He was already writing Ruby as a hobby when he saw David Heinemeier Hansson's original "build a blog" Rails demo, and he remembers thinking, "This is it. This is what I got to do."
Patterson admits he is heavily biased, because he works almost entirely in Ruby and Rails. He has tried other stacks. Building apps with Node felt to him like "the ergonomics are absolutely not the same." He first tried Django, amusingly, at Rails World, and found it nice but missing many of the bells and whistles Rails includes. He hears PHP has improved a lot recently. His underlying preference is that he does not want to make these choices himself: "I really want somebody to just tell me like no this is what you got to do."
The Ruby infrastructure team's mandate
At Shopify, Patterson rarely works on the web applications themselves. His team focuses on the Ruby interpreter. He mainly works on the JIT compiler, and the team also works on concurrency, parallelism, and garbage collection. He estimates the group at roughly 40 people, covering Ruby and Rails internals as well as developer productivity. He also works with infrastructure engineers and application developers.
He describes the mandate as helping Shopify's applications make better use of its production infrastructure, which he admits is a vague goal. In practice it means fitting more requests onto each machine. That is less about hunting individual bottlenecks and more about architecture. He breaks the big picture into three parts:
- Ractors address multi-core utilization: how to use every CPU on the machine.
- The garbage collector addresses memory: how to use less of it.
- The JIT compiler addresses single-core speed: when code runs on one core, how to make it run as fast as possible.
What he enjoys most about this work is making a system better without anyone having to do anything. "You upgrade your application, you didn't touch anything, and it's just faster and better." Breaking an API gets complaints, he notes, but nobody complains that an app became too fast. He likes seeing graphs move in the right direction. But he finds the constraint itself more exciting: improve performance while breaking zero people's code.
Ractors: true parallelism, and where they don't belong
Patterson explains Ractors as being like threads, except they really run in parallel. Two Ractors use two different cores. With ordinary threads, no matter how many you create, you are still effectively limited to one core. Ractors have existed for quite a while, but he says hardly anyone used them because they crashed a lot. Some workloads were also slower. He recalls a bug report where parsing a queue of JSON documents one at a time was faster than parsing them in parallel with Ractors, which he calls "clearly bad." Fixing problems like that has been a focus for his team. He now recommends that people start using Ractors, especially with Ruby 4.0, where he says they are fast and allow real parallel work.
He compares the model to Erlang or Elixir: a message-passing system in which you can send whatever you like, typically in a producer-consumer pattern such as a set of Ractors pulling JSON documents off a queue.
He is clear about where Ractors do not belong. He recommends never using them in the request/response cycle. In his view, it should be very uncommon for anyone to write Ractor.new, or even Thread.new, in a controller, view, or model, because a typical request just processes some data, renders a view, and sends a response. For database concurrency he points to Active Record's async queries, which already do that work in the background. Background jobs are a more plausible place for Ractors, but even there he expects the job processor to handle it for you.
The one strong use case he offers is OpenTelemetry. Collecting and logging application statistics usually happens in a background thread created with Thread.new. Because only one thread can use the CPU at a time, he explains, the app stalls while that thread runs. A Ractor would avoid this. Even so, he stresses that application developers would not be typing Ractor.new themselves.
Making Rails Ractor-safe
The Rails codebase itself does not use Ractors much. One of the team's current projects is making Rails Ractor-safe. The goal Patterson describes is that you can run rails new and run the resulting app inside a Ractor-based web server. Today, with any Ruby web server, multi-core parallelism requires multiple processes: 20 cores means 20 Ruby processes. With a Ractor-based server, one process could use all 20 cores. He thinks the server could detect the core count automatically, with an option to limit it.
He says this work is driven by Shopify's needs, and part of the demand comes from infrastructure engineers, who want a Ractor-based server because it would simplify their deployment strategy. His description of how projects get assigned is: "I have an idea, like okay, you have to do it now… own that, great."
Testing on edge Ruby with shadow traffic
The team always tests against edge Ruby. Sometimes that means working with application developers whose code does not run on edge Ruby and getting it fixed. The team has an on-call rotation, but Patterson says the load is manageable, largely because they have to be very confident before anything reaches production. If something fails there, it fails right away.
A key tool is Shopify's Storefront Renderer (SFR), which renders all Shopify storefronts and is read-only. The team deploys its own experimental build of SFR and replays production traffic through it, which Shopify calls "shadow traffic." Real customer requests still go to normal production servers. Because the app is read-only, replaying traffic cannot affect customers. The team can also compare the experimental output against the known-correct output. Patterson says anyone at Shopify can use this, not only for Ruby or Rails changes, whenever they want a layer of protection beyond tests.
The team rarely loads Shopify's applications locally for feature work. They do it to test the JIT, GC, or parallelism, and usually only after a lot of development on the JIT itself. Shopify's development environments are highly automated. Patterson calls the setup "pretty magic" for normal app developers, although his team has the unusual problem of having to modify Ruby's internals inside those environments. He does not know whether any of that environment tooling has been open-sourced; that belongs to a different team. Similarly, he runs rails new often, but only to create throwaway apps for testing Rails itself ("test app one, test app two"), not real projects.
Asked for the best database in the world, he improvises a tier list: SQLite is S-tier ("convenient, easy to use, deployed everywhere"), Postgres is A-tier with cool features, and MySQL gets a B. He does not hate it but thinks it has "weird quirks." When Robby asks whether those quirks still hold, Patterson admits he is disconnected. He used MySQL at GitHub and has no real complaints.
The goal: zero to Rails app, fast
The ecosystem friction Patterson cares most about right now is how quickly someone can go from nothing to a running Rails app. He reasons that faster setup means more people using Rails, and in a "TikTok culture," a slow install means "somebody's going to scroll."
He walks through the steps on a fresh laptop. You install Ruby, possibly compiling it along with dependencies such as OpenSSL, usually through a tool like mise, chruby, ruby-install, or RVM. Then gem install rails, then rails new, which runs bundle install. That is a lot of time spent installing. One improvement is shipping precompiled Ruby binaries, which he believes mise already does, although it does not help him because he always compiles edge Ruby. The other improvement is distributing Rails' native-extension dependencies as precompiled binary gems. His colleague Edward has been working on this and presented it at RubyKaigi. Patterson does not remember the exact percentage but calls the reduction "enormous." With every gem provided as a binary, he says, installation takes something like one or two seconds.
As for why this was not always the approach, Patterson thinks that in the past Rails simply depended on fewer native extensions, so it mattered less. Robby brings up long Nokogiri install times. Patterson jokes about who wrote Nokogiri and credits Mike's hard work shipping binary builds of Nokogiri, after which installs got much faster.
Why binary gems are hard: paths, fat binaries, and gRPC
Patterson describes several obstacles. The first is Ruby itself: compiling Ruby bakes absolute paths into the binary. If you compile Ruby into /foo and move it to /bar, it will work only sometimes. Since usernames and home directories differ between machines, a distributed binary Ruby has to cope with this. He believes mise handles it but is not sure how.
The second concerns the gems. A binary gem's filename has the form name, version, platform, for example Nokogiri for x86 Linux. The compiled .so file inside has to be linked against a specific Ruby version, but authors want one gem to work across Ruby 3.3, 3.4, and 4.0, and users only download one file. The current solution is the "fat binary": the gem contains one .so per supported Ruby version, and Ruby code in the gem picks the right one at require time. Patterson sees two drawbacks. Gems get bigger, so someone on Ruby 3.4 still downloads binaries for every other version. And when a new Ruby release comes out after a gem version has shipped, that gem version has no binary for it, and there is no way to add support to the already-published version.
Shopify runs into this constantly with gRPC. When a new Ruby version comes out, Shopify wants to upgrade but has to wait for Google to publish gRPC binaries for it. Patterson calls this "a huge problem that we have to overcome."
The proposal: content-addressable gems
Patterson says the team plans to tackle these problems one at a time, starting with the multiple-Ruby-version issue. In his view it "all boils down to literally the name of the gem file itself," because RubyGems and Bundler overload the filename with meaning, namely the platform. He wants the filename to carry no meaning and to work more like an address. Instead of addressing a gem by name, version, and platform, he proposes addressing it by content: name, version, and the SHA of the gem file.
Under that scheme, a gem author could publish one package containing only the Ruby 3.4 build, another for 4.0, and later one for 4.1. Each would be a distinct artifact containing only what that Ruby version needs. RubyGems.org would compute the SHA at publish time. Its version metadata, which already lists fields such as dependencies and required Ruby versions, could state that a given artifact requires exactly Ruby 4.0, so clients fetch the right one.
Patterson has pitched this to the RubyGems.org team. He says they seem to like it, and he thinks they will do it. The plan is a V2 API: old clients keep using V1, new clients use V2 and download the new artifacts. He expects it to be completely invisible to users: "hopefully, you just like upgrade Bundler and then it works." Asked about precedent, he says other ecosystems use content-addressable data, possibly Nix, but he is unsure of the details.
On containers, he does not expect much impact beyond faster builds, since a container image is built once anyway. The people he cares most about here are new users. Teams that already have container-based deployment have the resources to handle this, and he says those cases can be supported fine. New-user experience, he argues, keeps the Ruby and Rails ecosystems going and should be a high priority. (He also mentions that macOS still ships an old Ruby that warns you not to use it, and that it no longer includes Rails.)
Matz's Spinel and the bootstrapping problem
Patterson is excited about something Matz announced in a RubyKaigi keynote: Spinel, an ahead-of-time compiler that turns Ruby code into portable binaries. He imagines building RubyGems and Bundler, possibly combined into one tool, as a single precompiled binary, so installation becomes "download this package" with nothing to compile. He frames the core issue as a bootstrapping problem.
He says he still needs to dig into the project. As he understands it, Spinel removes the hard parts of Ruby. For example, it does not support eval, so metaprogramming that depends on eval will not work. He thinks that is probably an acceptable restriction for tools like RubyGems or Bundler. He sees Spinel as a separate project from Ruby's regular releases. More broadly, he notes that people have long switched to Rust or Zig ("I'm going to say Zig cuz I like Zig") for command-line tools, because distributing a Ruby CLI means making users install Ruby and deal with version mismatches. Shipping Ruby programs as executables would, in his view, "be awesome."
Why gems use native extensions, and "itch cases"
Patterson gives two real reasons gems use C extensions: speed, which he considers debatable, and the need to call a library written in another language. His cynical third reason is that authors "don't know any better."
Robby recalls writing Postgres functions in PL/Ruby that loaded RedCloth to render Textile directly from a query, as an example of using Ruby somewhere it doesn't belong just to see if it works. Patterson shares two of his own. SQLite lets you supply a virtual file system through function pointers that replace system calls like open and close. Patterson exposed that API to Ruby, so every time SQLite wanted to open a file, it called Ruby code. He used this first to build a self-contained script that stored its SQLite database in the __END__ data section of its own source file, modifying itself as data changed. The second, inspired by a suggestion from Chad Fowler, stored database data in HTML tables: rows in <tr> tags, cells in <td> tags. He says these are possible but not useful, and hesitates to call them "use cases." The two settle on "itch case" instead.
FFI, and letting the JIT see through C extensions
FFI is what Patterson calls one of his favorite itches, and it ties back to the JIT. His team's JIT compiler can only speed up Ruby code. Native code is opaque to it. So he wants people to write Ruby wherever possible, while acknowledging that calling an existing library like SQLite is a legitimate reason for native code.
FFI lets you call C libraries without writing C. You describe the function in Ruby (for example, a function named foo that takes an integer and returns an integer), and libffi sets up the call and connects the two sides. The drawback, Patterson says, is that it is very slow because it does a lot of work per call, which is why he has never used it in his own native extensions. He gave a whole talk on why FFI is slow, delivered in Japanese.
His project takes FFI declarations written in Ruby and generates a C extension from them, which gets compiled and is faster. That puts things back in C-extension territory, which he wants to avoid. The key step is that the generated C includes hints for the JIT compiler. Patterson says a hint is just metadata, such as "this function is named foo, it takes an int, it returns an int." When the JIT compiles code that calls these functions, it reads the hints, generates the native calls itself, and stops using the C extension.
He explains the motivation in terms of boxing and unboxing. Converting a Ruby integer to a C integer is unboxing, and the reverse is boxing. He wants the JIT to handle that type translation so it can profile and specialize its machine code for the actual types. A normal C extension is a black box: the JIT does not know what types go in or come out or what the extension does. The hints solve that. As for who should use FFI, Patterson's answer is only gem authors. As with Thread.new or Fiber.new, application developers shouldn't be writing it.
Should that even be a gem?
Asked when code should become a gem instead of living in the app, Patterson says the question is harder now because of LLMs. You can just ask Claude to build an integration instead of depending on someone's gem. His older answer still holds, though: anything outside your core business, such as a third-party API integration, is a good candidate to pull into a library. He frames this as architecture and maintainability rather than open source. A separate library can be tested independently and iterated on without moving in lockstep with the main app. Whether to publish it is a separate question.
How Patterson uses AI
Patterson uses AI "every day… all the time." Robby notes that the conversation was recorded in the second half of May 2026. Patterson's favorite use is exploring unfamiliar code. At a company with thousands of developers and many huge apps he has never seen, his work often requires jumping into one and figuring out what is going on, and he calls AI "the bee's knees" for that.
He also uses it heavily for hobby projects. He has small displays with an HTTP API that only accepts posted JPEGs. He wanted to generate images programmatically and found no suitable JPEG library, so he had Claude write a JPEG encoder, which he says he needs to release as an open-source gem. He also bought a small photo printer and suspected his computer's print path was altering colors, because prints didn't match his monitor. He had Claude build a small tool that uploads JPEGs directly to the printer over a socket, so he knows the exact bytes on his computer are what the printer receives. The prints still don't match. He says the real issues are that he needs an ICC calibration profile and has to map colors into the printer's narrower dynamic range.
The trust problem
The part of AI Patterson dislikes is something he is thinking about writing a blog post on, though he says his thoughts aren't fully formed. With a human teammate, he reviews the first pull requests carefully, then reviews less as he learns their work and comes to trust them. He says he has personally fallen into the same pattern with AI: it does the right thing, he checks carefully, it does the right thing again, and gradually he checks less, until it produces something bad that he doesn't notice. "You cannot treat it like a human," he says, but it is "close enough to trick you into thinking it can do a good job," and in some cases it just can't, with no signal beforehand.
Robby points out that human code quality can also decline, for example when someone is on the way out of a job. Patterson answers that with a person, you can talk to them and learn the context. With AI, the error rate seems to him essentially random, and the model is equally confident every time: "Oh, yeah, I totally did it. For sure." After one experience where AI got something badly wrong, he says he has "relegated" it to work he just doesn't want to do. Robby responds that those may be exactly the tasks that need the most attention. Patterson's rule for himself is that he must understand every line he submits, because he has to be able to defend and explain it.
AI in open source and the security-report flood
Patterson applies the same standard to contributors. He doesn't care whether a pull request was written with AI and doesn't ask for disclosure. Once a PR is merged, maintaining it becomes the maintainers' responsibility anyway. But he will ask questions about it, and if the author can't answer them, the PR probably won't land. He is fine with normal AI-assisted PRs: "You wanted a feature, you used… Claude to do it, seems good." He acknowledges that no policy will satisfy everyone, and points out that the line was already blurry when Copilot was just smart tab completion.
Security reports are harder. The Rails security team worked with the Internet Bug Bounty (IBB), which paid bounties to reporters of open-source vulnerabilities. Patterson says he was skeptical from the start because paying for reports attracts people looking for free money. Even before AI, there were low-quality reports and haggling over severity, since payouts scaled with severity. The reports he hated most claimed that writing control characters through the logger to a terminal "that hasn't been updated since 1996" could overwrite characters and hide log entries, and insisted this was the most critical bug imaginable. When AI arrived, a flood of low-effort reports followed. The IBB's response was to stop paying bounties, which Patterson says greatly reduced the number of reports. He doesn't consider that a good solution, because he wants security researchers to be paid. The team also uses AI to process reports. Robby notes that flooding a project's security address with realistic-looking reports is effectively a denial-of-service attack on the maintainers, and Patterson agrees. He calls the situation "damned if you do, damned if you don't" and says he has no good answer.
Both are wary of workflows where bots review bots' pull requests. Patterson predicts a new generation of AI-generated code patterns that will eventually get their own names, much like the design-pattern and anti-pattern vocabulary of the '90s and early 2000s ("big ball of mud"), and that we will need a way to tell a human-made ball of mud from an AI-made one.
What's exciting in Rails, and learning its internals
Patterson's favorite Rails work is low-level, and right now that means router performance. He has been looking into it and hopes to ship improvements that, like his other work, users get just by upgrading. On AI-oriented tooling, he mentions Ruby Dex as "very cool" though not Rails-specific, and says he loves tools that help people get into an application and start developing. He is a big fan of Marco Roth's work, especially Herb, and would like to see more of that built into Rails.
For developers who want to read Rails source, he suggests following their interests: Active Record for databases, Action View or Action Controller for views and controllers. When he started, he would pick something like link_to, ask how it worked, and read the code, hunting down where each method was defined. He says he is jealous of people starting today, because they can open Rails with Claude, ask how link_to works, and have it walk them through the code.
Book recommendations and where to find him
Patterson recommends Ruby Under a Microscope by Pat Shaughnessy, which he calls the best introduction to Ruby internals, covering introductory through advanced material. Shaughnessy is writing a second edition, which Patterson is technically reviewing. He thinks it may already be available as a preview and believes No Starch is publishing it, though he isn't sure. For anyone who wants to learn how JIT compilers or compilers in general work, he recommends Engineering a Compiler. He calls it very advanced and says it contains many of the techniques his team uses in their JIT.
He can be found on Bluesky as tenderlove and says he is trying to write more on his blog at tenderlovemaking.com. Several of the threads he raised were still in progress at the time of recording: making Rails Ractor-safe, the content-addressable gem proposal, which RubyGems.org seems receptive to but has not shipped, his planned router performance work, and his unfinished thinking about how far to trust code written by AI.
Welcome to On Rails, the podcast where we dig into the technical decisions behind building and maintaining production Ruby on Rails apps. I'm your host, Robby Russell, and I run Planet Argon. For over 21 years, we've helped teams maintain and evolve long-lived Rails apps. So, I tend to approach these conversations through that lens.
In this episode, I'm joined by Aaron Patterson, also known online as Tenderlove. Aaron is a senior staff engineer at Shopify and a long-time contributor to both Ruby and Rails core. He's spent years helping improve performance, tooling, and developer experience across the Ruby ecosystem.
Recently, he's been exploring faster gem installs, higher performance FFI, whatever that is, and other low-level improvements that many Rails developers may already be benefiting from, even if they don't fully realize it yet. Aaron joins us from Seattle, Washington, in the United States. All right, check for your belongings. All aboard.
Aaron Patterson, welcome to On Rails.
Hi, Robby. Thanks for having me.
So good to get to catch up with you again. So, Aaron, let's start with this. What keeps you on Rails after all these years?
What keeps me on Rails? It's a very good, very good question.
Thanks.
I would have to say that my significant other keeps me grounded. She keeps me on the rails.
No, I'm kidding. Well, I'm not kidding about that. But to answer the question seriously, I've been using Rails for like many, many, many years. And the thing that keeps me on it is, first off, it's the easiest way to build a website, like get something done, get an app built. Like still, it is the easiest way.
But the other thing that I really like about using Rails is that it keeps up with advancements in web technologies and stuff. So, it's not like there was like, "Oh, we just made this one framework and then it just like stuck there, and then now we're forever done with that." That's just not the case with Rails. We're keeping up with all the latest web technologies and stuff and still making it easy even for someone like me.
Tell me more.
I am not good at building websites at all.
So, and then Rails makes it really easy for even knuckleheads like you.
Yes, exactly.
All right, that's great. Well, I mean, I know you're a very sophisticated software developer. So, out of curiosity, how did you get into building web apps in the first place?
Oh, in the very, very first place? Like from the very beginning? Forever and ever ago.
Sure.
Sure. I just got a job, dude. Like this is in 1999, was my first web job. It wasn't on Rails, though. And I needed a job out of high school, and a friend of mine was working at, funny enough, a car dealership and was like, "Our car dealership needs a website. Can you help with it?" And I was like, "Yeah, sure. I'll do that."
Was any of that dynamic, or was that all pretty much static sites back at that point?
No, it was dynamic. Like I had to do JavaScript programming then. So, like I was doing JavaScript programming in like around 1999, 2000. It's crazy.
Okay.
Yeah.
Out of curiosity, what other tech stacks were involved in that? Or is that like pushing out through... And if this is going down a rabbit hole that you would like to forget and compartmentalize that part of your life.
It's good to know where we've come from, so we know where we're going.
Something like that. It was all just CGI scripts, like Perl CGI, with JavaScript, and I don't know that I ever deployed the website, but if I remember correctly, it was basically just like FTP it to a thing and run it.
It's like a CGI bin directory or something.
Yep. Exactly.
Sounds familiar. And then maybe some Apache in front of that or something.
Yes, I don't even know. I think we used CVS at the time as our version control system. But I mean, I only worked at that job for like maybe a year-ish.
So, fast forward to somehow between then and
Yes.
getting acclimated or introduced to Ruby and Ruby on Rails, was that your introduction into Ruby and Ruby on Rails website development at that point then?
Yeah, so like I mean, since then I had just always done web development. Like it started off as a job, and then it turned into a career, I guess. I'm not sure when that happens, like when you go from job to career or something, but it
I'm still trying to figure that out.
Maybe it's still just a job, I don't know. Anyway, I was just a web developer ever since then, and then I learned about Ruby and Ruby on Rails in... Well, I learned about Ruby on Rails from the original build a blog thing that David did. And that was like, whoa. But I was doing Ruby before that, not as a job though, just as a hobby project or hobby programming. And then when I saw Ruby on Rails, I was like, "Oh my god. This is it. This is what I got to do."
Earlier on you touched on how that is still one of the easiest ways, in your opinion, to build web apps and websites. What was your perspective on what developer experience looked like back then versus where we're at now with web development? And I don't know if you actually get to spend much time working with other tech stacks very often or get exposed to them. So, are you super biased because you're in this bubble or
Of course, I am absolutely super biased. I only really work in Ruby and Ruby on Rails, so I'm not sure. I know PHP has made a lot of changes recently and improved a lot of stuff. Node was very popular for... I mean, I guess it's still popular. I don't know. But I looked into building apps with Node and it's like, no, no, this is not the same. The ergonomics are absolutely not the same. I tried out Django a couple years... Actually, this is funny. The first time I tried out Django was at Rails World.
Oh, really?
Yes. I was like, okay, I'm going to give Django a try, and so I tried it and it was, I mean, it was nice, but it didn't seem to have all the same features that we have, just didn't have all the same bells and whistles included. So I really don't want to pick these things. Like I said, I'm a bad web developer. I really want somebody to just tell me, no, this is what you got to do.
Sure. For those listening, I mentioned it in the intro, but you work at Shopify. So from what I can tell, it doesn't seem like you probably spend a lot of time working directly on the web apps themselves though, right?
No.
What does your typical day-to-day look like for you now?
So I'm on a... I'm not sure what to call it exactly. I'm on the Ruby infrastructure team, and we focus mainly on the Ruby interpreter itself. So currently we're working on a JIT compiler. I'm working mostly on the JIT compiler, and then we're also working on concurrency and garbage collection. So we're improving concurrency and parallelism, GC, as well as JIT compilation. So that's what our team is mostly focused on.
For me, as, I'm saying, the village idiot, I want to ask these basic questions about some of these things on behalf of listeners that might be like, I hear these words or things that come up, like what is, you know, a JIT compiler? What are Ractors? What is Aaron actually talking about out there? Cuz as a web developer, when do I potentially need to invoke some of these tools? Are these helping more so on running Shopify in production, or is a lot of this actually helping just developer ergonomics and experience when you're locally developing and working on your application?
Well, if we're doing it correctly, it should help everybody regardless. I love working on performance. I also love refactoring code. I love working on internals, things like that. But my favorite thing to do is if I can make a system better and nobody notices. I mean, they notice that it's better, but you upgrade your application, you didn't touch anything, and it's just faster and better. Right? Like if you break an API, everybody complains about that. But if you make an app faster, zero people complain about that. Nobody's like, "Oh my goodness. This is too fast."
Do you think there's something about those types of problems? Does it kind of feed a part of your brain in the sense that those are tangible measurables? Whereas when you're working on a web app and you're like, "We're going to add a couple new features and maybe we're improving our conversions or more sign-ups or retention," those data points can maybe feel a little bit more abstract, where you might get the endorphin kick of, "Look, it's faster by 3%."
Yeah, I see what you're saying. I do like being able to see the numbers and be like, "Ah, we made the graph go down or up or whatever the good direction is." You know, cuz there's always a good direction. That's exciting, but I think what's more exciting for me is the problem-solving aspect of it, because the goal is to make an app better without changing the app at all. So, it's these constraints that I have to work within, like, "Okay, we're constrained to break zero people's code and yet somehow improve performance with that thing." So, how do we do that? And that's, I think, a really exciting, I mean, for me
Sure.
for me, it's exciting and fun to work on.
What sort of things have you been working on more recently, and what types of bottlenecks typically show up at Shopify scale?
I mean, we have so much code that any and every bottleneck can show up. There's no one... I mean, we have memory constraints, we have performance constraints. I think if you think about it from a big picture, our team's mandate is basically to make our applications utilize our infrastructure better. So, better utilization of our production machines is essentially our mandate, which is a pretty vague goal.
Sure.
But it's kind of what our mandate is. So, we say, "Hey, well, we want to send more requests to a particular machine. We need to fit more requests on a particular machine. What do we need to do that? How do we scale the application to do that?" It's not really a bottleneck. It's more like architectural problems and then how to solve that particular problem.
So, we're looking at the web server, GC. Actually, let me spell out the big picture for you. So, we're looking at Ractors as multi-core utilization. So, how do we use all CPUs on the machine? How do we decrease memory? That's where the garbage collector fits in. And then when we have code running on one particular core, how do we make that code run as fast as possible on that one particular core? And that's where the JIT compiler fits in.
I see. So, okay, it's coming from all these different perspectives. So, are these things that developers need to refactor some parts of their Rails app itself to take advantage of, these features that are being added to Ruby? Or are there actual scenarios where those things could come into play?
That's a really good question. I think there's always kind of a tension. I mean, there are some things that do need to change. So, for example, Ractors is a new type of... Actually, it's not that new. It's been around for quite a while. Just nobody used it. So, Ractors are like threads except they run truly in parallel. So, if you have two Ractors, they're really using two different cores. Whereas people probably remember, previously, if you used threads, you're still stuck on one core. It doesn't matter how many threads you use, you're still only utilizing one core. So, Ractors let us truly use multiple cores in parallel. But nobody really used them because they crashed a lot.
And also, it's really funny. For some workloads, they were actually slower. Quite a while ago, somebody reported a bug. They were like, "Hey, if I process JSON, all I'm doing is processing JSON documents. If I'm parsing some JSON and I do it serially, that's faster than if I try to do it in parallel with Ractors. So, if I try to do it in parallel with Ractors, it's slower," which is clearly bad. So, we've been working on fixing those types of things. So, those are places where your app might need to change. But hopefully not. Hopefully it's just a web server. So, you install a new web server, and now all of a sudden you have multi-core utilization.
Using that JSON example, just break that down a little bit more. If that's someone just running one of the methods on the JSON library and saying parse this, does that already in Ruby get split up into multiple processes and chunked up or something, or is it just one thing?
Yeah, it depends on how you write it. So imagine you were doing it with threads, you might have a queue of JSON documents that you want to parse. So you've got a bunch of threads that are popping off of that queue. It's the same deal with Ractors. You may have a bunch of Ractors that are just popping off of the queue and then processing, like parsing, the JSON. So the bug that the person reported was like, "Hey, if I do this one at a time, it's actually faster than trying to pop off a queue and do it multi-core with Ractors." And one of the things our team has really been focusing on is making sure that Ractors are fast and usable. I highly recommend people start using Ractors, especially with Ruby 4.0. They're fast now, and you can do things in parallel with them.
Can you think of some examples, maybe aside from the JSON one, where someone with a typical Rails app... is this more like a background job type of scenario, versus would you use that in a standard web request-response cycle?
Yeah, really great question. I recommend that you just never use it in a request-response. I don't expect anybody to be... I think when I'm thinking about web applications, it should be very uncommon for somebody to write Ractor.new or even Thread.new inside of their controller or view or whatever, or even your model, cuz typically you're just processing some data, sending it to a view, getting the response, sending that off to somebody. There's nothing necessarily that you're doing in parallel in that case.
And one thing I'd recommend: if you're using Rails and Active Record, you should be using the async queries with Active Record. You can get async queries already, and it'll do that stuff in the background for you. So, you're never actually typing Thread.new in your app. Where I do see somebody typing Ractor.new, for example, or Thread.new would be background jobs. But even then, the background job processor would already be implementing that.
One really good use case I can see for Ractors is OpenTelemetry, where you're getting a bunch of statistics about your application and then trying to log those statistics somewhere. A bummer about OTel is that you'll try to log stuff and it'll happen in a background thread, a Thread.new thread, and because of that your app will actually stall when the thread is executing. Cuz remember, only one thread can use a CPU at a time. So, in that case you would want to be using a Ractor. But again, you're not typing Ractor.new in your app. That's just, you don't.
So, it's pretty rare that a developer would need to do that. Is Ractor something that's found in other
programming languages?
I think probably the closest analogy might be Erlang or Elixir. It's basically a message passing system just like Elixir. I think that's the closest thing.
And what kind of messages, for the dumb idiot question, what kind of messages are they passing between them? It's just
Really any thing that you want to. So, like anything you'd queue up for processing in parallel, any type of producer consumer pattern that you might have. For example, maybe you're taking a bunch of JSON documents and you need to parse them in parallel. I don't know.
Is there a lot of Ractor.new in the Rails codebase itself?
No. No. One of the things that our team is working on is making Rails Ractor safe. That's one of the projects that we have in flight at the moment. We want to make it so that you can create a new Rails app, or the current goal is you'll be able to do rails new and then run that app inside of a Ractor-based web server. So, you'll have a Ractor-based web server with your app, the new Rails app, running inside of it. And what that buys you is you can have one process, which is your web server process, using all, I don't know, 16 cores, however many cores you have on the machine.
Is that then something like in a Puma or something that you would be configuring the number of CPUs to be using in that scenario, or is it just automatically figure that out?
I think we can automatically figure it out, but you could also specify, like if you didn't want to use all of them for some reason.
What does that actually end up looking like on the server that's running it? Is this running just one Ruby process at that point, whereas you might have eight or 16 historically running on your server?
Yep. So, like right now today, if you're running, well, any web server really, if you want to have multi-core parallelism, you have to be running multi-process. This is true for any web server today. So, like if you have 20 cores, you need to be running 20 Ruby processes. Whereas with a Ractor-based web server, you run one process and you can use all 20 cores at the same time.
Interesting. That's cool. How did you find yourself into working on these types of performance type problems?
These particular ones are, I'd say that they're really, really driven by the needs we have at work, pretty much.
Can someone make this better, please?
Yes.
Someone nominated you?
Yeah, pretty much. Like I have an idea, like okay, you have to do it now. Like yeah, okay, own that, great.
How many people are you typically collaborating with right now on these types of projects?
Oh my gosh.
Approximation.
That's a good question. I think our team is something like 40 people.
Okay.
Something like that. There's a lot of people. And that's not counting infrastructure people I got to work with, cuz our team is really focused on Ruby and Rails internals as well as developer productivity. But that's just those things. I mean, I got to work with infrastructure folks and app developers, a whole bunch of different people because of this particular work. The infrastructure folks really want a Ractor-based web server because it simplifies their deployment strategies. So that's that aspect of it. But then we have issues like, oh, we want to test edge Ruby. So we're always testing with edge Ruby. And sometimes I have to work with application developers because they might write code that doesn't work with edge Ruby, and so I got to, you know, get that fixed. So there's those folks as well.
Interesting. So about 40 people, and are you typically, in your role, on call to some degree? Do you get called in very often for weird quirky things, or is it pretty manageable in a typical 9-5?
I'd say it's fairly manageable. I mean, we have an on-call rotation. We have to be very confident that it actually works before we put it into production. If there's any failures, it's going to fail, like, now. Right?
Yeah. That's fair. And I guess part of that is because of the shape or the type of business that Shopify is, there's constantly transactions happening. So I would imagine that things would happen pretty quickly if there was something broken.
Yes. We also have really, really nice ways to test. One of our applications is a read-only app. One thing we do is we deploy our own custom version, like our team's custom version of that app, and then we run traffic through it. And since we know it's read-only, we know it's not going to impact any customers or anything. So, we have a really good way of testing.
Interesting. Can you speak a little bit to what that read-only app does there?
Yeah, it's called SFR. It stands for storefront renderer. It just renders all of our storefronts.
So, then everything else is separated into different services or something, I'm guessing.
Yeah.
So, is my Commit Goods shop being rendered through that then?
No. What we do is we replay traffic on this thing. So, real production traffic will always be hitting our normal production servers, but we'll replay traffic, we call it shadow traffic, we'll replay traffic through our experimental one. And we can even do stuff like compare the output of the experimental one to the known correct one so we can make sure that everything is working properly.
How different is that from a QA workflow then? And is that like an automated QA type thing, or just being able to have that replay everything?
It's basically the same. I mean, we can do this for any reason we want to. It doesn't have to be Ruby changes or Rails changes. People can just do it. They're like, "Well, I changed, I don't know, something that's risky." And they want to have an extra layer of protection besides just tests.
Is that just running on some internal servers that your team has access to that's playing there? Are people actually logging in and clicking it, or is it just some magic, or you don't know? We just know that we deploy over here and some magic happens.
Yes.
Okay. It's nice to have magic.
Yes.
Are you often then needing to load up the Rails apps themselves very often in your local development environment, or
Not very often, but we do it for testing, of course. We're not loading the app to do development work on it necessarily, but we're testing, like testing the JIT compiler with it, testing GC, testing parallelism, different stuff. But it's pretty rare, because we have to do a lot of development work on the JIT compiler before we even get to the point where it's like, "Ah, let's test our real application, right?"
And is it as simple as running your test suite locally in that type of scenario, or
Yeah, I mean, it depends on what we're testing and it depends on the problem, but yeah, pretty much. So, our development environments are very, very automated, I guess. So, there's a lot of developers at Shopify and we have very good tools to ensure that their development environments are set up nicely, so they're not running into any problems.
They're not needing to debug the bin/setup script every time.
Yeah, exactly. So, an issue with that that is unique to our team is that since we're working on Ruby itself, we have to start mucking with internal stuff. So, that's kind of a challenge. And it's fine, but, you know, that's what we do for a living, so.
Yeah.
For those listening, not everybody works at an organization as large as something like Shopify, where they have access to teams that are doing these types of things. But I think it's always interesting to get a sense of how those large organizations can spend time to invest in that. Do you feel like there are many tools that you've been able to open source that speak to the kind of developer experience of just the local environment, developer perspective, or
I have no idea.
Okay, great.
I have no idea.
Whole different team, a whole different department, dude.
Different team.
Not my problem. That's someone else's job.
I mean, if they open source it, it's great, cuz honestly the way that it sets up our development environments is like
pretty magic.
It's great. If you're just doing normal app development stuff, it does everything for you. It sets it all up for you. Okay.
This episode is sponsored by Gemshine, a gem polishing and resetting service. Got gems that are dull, scratched, not catching the light like they used to? Gemshine restores brilliance. Clean, cut, polish, then we reset your gem into a fresh piece of jewelry. A new ring, a new pendant, a whole new you. Wait. Oh, no.
No, no, no, no, no. I think they mean actual gems. Like jewelry gems, for jewel- like, these are not Ruby gems. Oh my god, what have I done? I read this like this was for Rails developers. Like polish your gems, but not reset them into new jewelry. And now I'm picturing someone mailing a Gemfile to a jeweler. No, please do not do that. But if you're a jeweler, hobbyist, maybe Gemshine sounds kind of incredible. But if you're a Rails developer, please just ignore this. I have a few calls to make.
Host's message was read. Obligation was technically fulfilled. Host did not verify the audience. Host is now aware. Host deeply regrets this. Gemshine.
How often do you feel like you run Rails new?
Not as often as I should. But when I run Rails new, I'm mainly just testing Rails itself, right? I'm not making a new app. I can't remember the last time that I ran Rails new to make a new app for real, like that's not a me mucking around thing. You know what I mean? Like
More recently, you've started a Django app more recently.
Oh, no, no, I mean, are you kidding? I do Rails new many times. It's just that it's always like test app one, test app two.
Yeah.
Test app three.
What is the best database in the world, Aaron? Can you answer the question?
What is the best database in the world? Nobody's ever asked me that. I mean, how do you quantify best database? I mean, I like SQLite a lot.
It's convenient.
Yeah. Convenient, easy to use, deployed everywhere. It's great. I like PG. You know what we should do? We should do a tier list. And I would put SQLite as S-class. It is an S-class database. I'll put Postgres at like A-class, A-tier database. Though it's got cool features. MySQL, that's going to have to be a B. I don't hate it, but it's got weird quirks. So. Yeah.
Do you feel like that rings true now? I mean, I feel like 20 years ago if you would have asked me, I'm like, "Oh, yeah, MySQL has all these weird issues with data validation." And then it still became the default in Rails. And I can disagree with DHH about that all we want, but do you feel like a lot of those quirks still ring true in the MySQL world? Or do you feel like maybe you're a little disconnected?
Disconnected, dude. No idea. I have no idea. We use MySQL at work. I mean, I used it at GitHub. It's fine. I don't have any complaints, man. They're all good.
Why such tiny hands? I'm asking on behalf of our audience. Someone said that that should be a question. I said
That is a great question. I should have some on my desk, but I don't. I don't know. I thought they were funny, and I was like, "I got to get these." And then pet my cat with it. And then I got to take photos with them so that everything... So, I like taking forced perspective photos with them and then posting them online, and I'll be like, "Oh, this tomato is huge." But the thing is, whenever I do that, it's truly because, like, one time I found a giant onion at the grocery store. It was a huge onion. I bought it. And I'm like, "This onion's huge." And then I put the little finger next to it, or the little hand next to it. And it's truly a large onion, but the tiny hand is also tiny. And then people are like, "Oh, it's just a normal-size onion." No, it's actually big.
Well, thanks for digging into that with us. Someone suggested that I ask you that question.
Well, I got to hand it to you, or hand it to them.
Yeah. So, when you think about, you know, the type of work you do with performance and things in the Ruby ecosystem, what types of friction do you feel like in the Ruby ecosystem on a technical level have been bothering you lately?
It's really weird, like since I work on edge Ruby a lot, I encounter a lot of problems where I'm like, "Is this just a me problem, or is this a problem that everybody has?" You know what I mean? Cuz you're running edge Ruby and maybe something changed in it. And not all the gems in the ecosystem know about edge Ruby. How would they? So, I get all these weird problems.
One of the things I've really cared about recently is how quickly can you make a new Rails application? Like when you do Rails new, how fast is it from zero to Rails app? That's something that I've been really interested in lately. It's important to me because the faster you can make a new Rails app, I think more people will be using Rails. I mean, Robby, we live in the TikTok culture. You got to be able to install, or otherwise somebody's going to scroll. You know what I mean? So, looking at things like that, that's one of the things that's really been interesting me lately.
What types of steps go into that? You know, when you run Rails new, you've already installed the Rails gem, am I correct? So, is that installing other additional steps at that point?
Yeah, so you
And what about even the process of having to install the... I mean, in an ideal world, from my perspective as a developer, I'm like, "Ah, you have to install Ruby."
Yep.
Then you got to install Bundler? Does that come with it now? I forget. And then there's multiple steps involved as a developer before you can even get to the point of running Rails new. And then you potentially have to install more things at that point. So, what can we do about that?
Yes. Let's say you're at zero, you got nothing right now. Yeah, brand new laptop. You got to install Ruby, of course. And then maybe if you're compiling Ruby, you got to install all the dependencies, too. So, maybe that means you need to install, I don't know, some mise.
OpenSSL.
Oh, yeah, exactly. OpenSSL. But I think typically people are using stuff like mise, or, I don't know, I use chruby, or, you know, ruby-install or whatever.
RVM.
Yes. And you got to get Ruby installed. And then once you do that, you got to do gem install Rails. And then once you do that, you got to do Rails new. And once you do Rails new, it's got to do a bundle install. So, you're spending all this time installing crap.
And I think one of the things we can do to speed up the process is providing binary versions of Ruby, which I think mise is already doing. Though, as I said, since I'm working on edge all the time, it doesn't help me, cuz I have to compile mine all the time. But that's very helpful. Another thing is, we depend on a lot of... when I say we, I'm talking about Rails. It depends on a lot of binary, or not binary, gems, C native extensions. And if we can get those distributed as binary gems, I think it would be very
very, very helpful. One of my colleagues, Edward, has been doing a lot of good work on that, like delivering that specifically. And he gave a presentation about it at RubyKaigi, and I don't remember what the percentage decrease was, but it's enormous. Like if you can provide all the gems as binary gems, installation speeds are like, I don't know, a second, two seconds, something like that. So
Wow.
I'm hoping that we can have that in our future.
For those listening, why has that not already always been how that would be done? Like what sort of obstacles would have prevented that in the past, and is the tooling and stacks and the hardware we have that much different than we did 10, 15 years ago?
No, it's just, I think, there are a few things that get in the way. Boy. Trying to think. There's a lot of aspects to this problem. Like in the past I think we just didn't depend on that many native extensions, so it wasn't as big a deal.
We can wait for Nokogiri data.
Yes. Yeah, yeah. People like... So that's the thing. You remember Nokogiri? Remember Nokogiri installations? Who wrote that anyway? Who was that guy?
And like Mike did very hard work to start distributing binary versions of Nokogiri, and then all of a sudden installation speeds got way better.
There are a few things, a few hurdles that we have to overcome in order to have binary gems like that. One is starting with Ruby itself. When you compile Ruby, it adds a bunch of stuff baked in that has absolute paths baked into the binary. So, let's say you compile Ruby and install it into /foo. You can't just move it to /bar and have it work all the time. Like it'll work sometimes, but not all the time. And this is obviously a problem, 'cause your username on your computer is probably different than my username on my computer. So, if you install a binary version of Ruby, it needs to work in both scenarios. Which I think mise dealt with, but I'm not sure. I don't know how exactly. But that's one problem. Another problem is... I'm sorry, Robby. We're getting in the weeds here.
If I... That's, do it.
Ready?
Let's get into the weeds.
Okay. We're going to get into the weeds. So, when you install a gem, the gem name, like the file name itself... So we're going to pretend we're installing Nokogiri, the binary version. The name of the .gem file itself is going to be Nokogiri dash the version number dash some platform. So, let's say we're on Linux on x86, it's going to be x86 Linux. Okay?
Yep.
Now, the problem is that the precompiled gem, like the .so file inside of the .gem file, that has to be linked against a particular version of Ruby. So, maybe it's linked against Ruby 3.4. But you want that gem to work on 3.4, 4.0, various versions of Ruby. So, how do you accomplish this? And then remember, you only get to download that one file. So, how do you do this? The way that people do it is through a technique called a fat binary.
And what they do is they'll compile Nokogiri, and the Nokogiri gem file will actually contain multiple .so files, one for each version of Ruby that it supports. So, if you support, I don't know, 4.0, 3.4, and 3.3, if you go unpack that gem, there will be three .so files inside of the gem file itself. And then, when you require Nokogiri, there's some Ruby code inside of that that looks at the version you're on, and then it goes and requires the correct .so file depending on what version of Ruby that you're on.
So, this is a bummer because it means the gem files are larger. You had to ship a whole bunch of different .so files. That's one problem. So, this impacts installation time because you have to download all that. And if you're on Ruby 3.4, you got to download the binaries for Ruby 4.0 as well as blah blah blah blah blah, right?
The other problem is, let's say you ship Nokogiri version two, and it supports Ruby 3.4 or 4.0, but then Ruby 4.1 comes out. What do you do? So, it can't use the binary version either. And you can't ship a new version of Nokogiri 2.0 that supports Ruby 4.1, so you're kind of stuck there. So, we encounter this problem all the time with gRPC in our applications. Google will ship a gRPC version, and then whenever a new Ruby version comes out, we want to upgrade to the new Ruby version, but we can't because we got to wait for Google to ship binary versions of gRPC. That's a huge problem that we have to overcome.
Are there some directions you think the team, that we can get around that then, or
Yes.
Is it... 'cause I feel like this is not that unlike, I guess if you're working on, say, a Red Hat operating system and you install your Red Hat packages or your Debian .deb file packages when you want to install things, and it's kind of like the pre-compiled versus compiling yourself. And I don't know if you use like rbenv, historically it would basically download it and then compile it against your local thing and install it to make sure you had all the appropriate other dependencies you needed to install before that. So, which is why Homebrew can be really helpful, but it's trying to at least standardize that to some degree, but it sounds like it's still kind of a complicated thing. Unless, are there different ways about how this stuff is approachable going forward where you can reduce that need to do all that extra work?
Sure. We have a couple things in the pipeline at the moment. I mean, we got to tackle these problems one at a time, I think. And the first one I want to tackle is the multiple Ruby version issue. So,
No new version.
No, no new version. Great idea. This, I think this all boils down... It's very, very funny, but this all boils down to literally the name of the gem file itself. Like it all boils down to that.
And it's because Bundler and RubyGems, I would say, overload the file name. So, the file name has meaning to it. And that meaning is the platform that you're on. I think the first thing we need to do is get rid of that meaning. So, I think that the file name should be meaningless. We can kind of call the file name like an address. So, we address the gem by its name, its version, and then the platform. I think what we want to do is start addressing the gem by its content. So, we should have content-addressable gems. So, rather than, you know, name-version-platform, it would just be name-version-SHA. And the SHA is the SHA of the gem file itself.
And if we do that, then we can say, "Hey, I'm going to package only Ruby 3.4 inside this one. And then I'll package Ruby 4.0 in one. And then, you know, maybe 4.1 comes out, we do that one," and we're able to ship all these with different actual gem names, and they'll contain only the content required for that particular version of Ruby.
So, this is going to require some changes on the rubygems.org side. So, when you publish the gem, it's going to have to calculate that SHA. Like if you take a look at the data that comes back from rubygems.org, like if you go say, "Tell me the versions you have," it's got a bunch of fields, like what it depends on, Ruby versions it depends on, and we can bake in like, "Hey, this one depends on Ruby version exactly 4.0, get this particular one for the Ruby that you're on." So, that solves that problem.
Sounds easy.
I mean... Do you feel like that's going to require much of a change from the end user perspective? Like just a typical developer, or is that all kind of fairly seamless behind the scenes?
I think this is going to be something that's completely behind the scenes. Like you don't need to do anything. So, presumably, yeah, the way we can do this is, I made this proposal to the RubyGems team, the rubygems.org team, and they seem to like it. So, I think they're going to do it. We introduce like a V2 API on rubygems.org, and older clients will still hit the V1 APIs. Newer clients will hit the V2 APIs and they'll just go download the new stuff. So, hopefully, you just upgrade Bundler and then it works.
Are there similar patterns we've seen in other programming languages or frameworks that kind of follow that approach, or is this kind of like Aaron's crazy wild hair idea that we're going to be talking to somebody 10 years from now and be like, "What was Aaron thinking?"
No, there's other ecosystems. I remember off the top of my head who else does this, but other folks absolutely do content-addressable data as well. It's just, I mean, I think it's a really big thing in like the Nix world or something. I don't know, man. I'm not good at this stuff.
But I love the proposal though. You know what I'm curious about is how will this help or change how we think about containers in the future. Do you think that's still going to be a useful construct for us to be working in? Do you feel like everybody should be working in containers, or have much of a thought on that?
I'll tell you my... I would tell you my thoughts on containers, but I keep a lid on it.
Okay.
I'm kidding.
I withdraw the question. Editor, you can please just dismiss that.
I don't know. I mean, I like using containers. I don't know that this change will ever really impact containers at all, but it should make building containers faster. But if you're deploying with containers, it probably doesn't matter anyway 'cause you just made the container once. I think this is mostly end user development for folks who are just getting started. Like I think that the new user experience is the thing I'm concerned with the most. Like if you're already building containers and you already have this deployment solution and you have teams that can figure out this stuff, I mean, of course I care about you, but, you know, you have resources to put into this and we can support those use cases just fine. It's really new user experience that I want to encourage. I think this new user experience helps keep the Ruby ecosystem and the Rails ecosystem running and going, and it should be high priority for us.
You know, like if you're thinking about these people that have yet to ever build their first Rails app and they're trying to get started, and you have to start putting together this mental model and be like, all right, I need Ruby. What are my requirements even to install Ruby? Do I need to install Git? What is that? You know, some of that I guess gets preloaded on computers these days. Maybe even Ruby's already installed on maybe... I don't know. Does Ruby still get shipped on Apple macOS?
It does, but it's an old version and it gives you a warning. It's like, "Don't use this. It's going to go away."
But it's here.
Yeah, it's here.
it to you.
Use it.
Who are these people that are using the provided Ruby version? Does it still include Rails anymore? I remember it did.
No. No, it used to, yeah.
Yeah. That was kind of a big deal, didn't it? Like, comes shipped with Rails. You're like, "Great, that's outdated." All right, but do you feel like there's other tooling that could optimize the overall experience of installing Ruby and Rails? It's like this one... Is this a dream, like download or just run this one command and it handles those several steps really, really fast, and if you're that new developer that doesn't need to worry about "I already have three different versions of Ruby installed on this computer." I have zero Ruby. I have zero Rails or any Bundler. I don't even know what that is yet.
I mean, hopefully... One thing that was really interesting to me is, so at RubyKaigi Matz gave a keynote, and his announcement was this thing he built called Spinel, and it is a Ruby compiler. Like an AOT compiler. So it could take Ruby code and produce a binary for you, and you could build portable binaries from Ruby.
So imagine like, okay, we're able to build Ruby, build RubyGems as a binary, or build Bundler as a binary, or if we combine the two, like maybe put the two together, turn it into one tool, we could distribute just that. It's like, "Oh, okay. Well, now installing it just becomes download this package and you have it all already. You don't need to compile anything 'cause we've precompiled everything for you." That's something I'm really looking forward to. It seems like a good, interesting future.
Do you think that's likely to be a thing that's shipped by the next version of Ruby, or is that even required? Is that a completely separate thing, or doesn't need to be?
Totally. I think it's a totally separate thing. I need to dig into the project more 'cause it works with... the project is Ruby, but he eliminated the hard parts. So, for example, it doesn't support eval. So you can't do any metaprogramming. Well, you can do some metaprogramming. You can't do any metaprogramming that requires eval. But honestly that's probably a fine restriction. Like I imagine you could build a RubyGems or a Bundler without those particular features, and then precompile that and give that binary to people, and it automatically bootstraps for them, right? 'Cause it's really a bootstrapping problem we need to solve.
Do you feel like, from what you know, is Matz just scratching some personal itch there, or do you see some interesting use cases like that, or is it just a personal
I think RubyGems and Bundler are a perfect use case for something like this. There've been people out there for a long time who are like, "Ah, I switched to Rust," or whatever. I'm going to say Zig 'cause I like Zig. "I switched to Zig because I needed to build a command line tool and I want to be able to distribute the command line tool." If you build a command line tool with Ruby, it's kind of a pain because anybody who wants to install it, they're going to have to install Ruby as well, and then of course it might depend on the version of Ruby that you're using. If you chruby to a different one, then it might mess it up, and blah blah blah blah blah. So if we could have a system where we can start distributing Ruby code as executable binaries, I think that's going to be awesome.
Can I pivot back a little bit to why do some Ruby gems tend to lean on native code in the first place?
Two reasons.
Can we just make Ruby faster?
Yeah. We can't... We can. I'll give you the two real reasons and then my cynical reason. So, I think the two real reasons are, one is speed, which could maybe be debatable. The other one is they need to use a library that's implemented in a different language.
I see.
So, those are the two real reasons. Then my cynical reason is because they don't know any better.
Well, they knew enough to do it. I mean... Yeah. That's
I mean, you can know enough to be dangerous, right?
Yeah, that's true.
Like I can learn enough Spanish to get myself in trouble, in big trouble.
You know, earlier we touched on databases, and I just want to... I was kind of curious if you've ever got to do this. I don't know if you can do this in MySQL or not, but I come from the Postgres background, where a previous boss of mine wrote an O'Reilly book for Postgres. So, I was kind of indoctrinated really early on, in the early 2000s. But one of the things I thought was really cool about Postgres was that you could write basically custom functions or procedure type things in many languages, and you could do it with PHP, and there was even like a PL/Ruby. You can write Ruby code and
do fun experiments like maybe have I always think back to this stupid experiment that I had where I had, I don't know why am I talking right now about this? This is my interview with you, Aaron, but more importantly about me. But I thought it would be fun to experiment with the idea of like having a Postgres function that would then load up Ruby gems and then call Ruby gem methods on like some text. So, if you did like a select RedCloth, because that was like a Textile thing back in the day, you could do that on a blob of Textile code in a field and it would just return HTML. You could have just done this in Ruby obviously.
>> Yeah.
>> But I like that you could do things like that. I knew enough to be dangerous and do silly stuff like that and take Ruby places that it wouldn't normally belong. But yeah, I could have done that with C as well. All that to say is people like to experiment as well. Do you recall any interesting experiments you've been able to do with Ruby where you've used Ruby in a non-typical fashion just because you wanted to see if you could?
>> I mean, hmm. Yes, I'm trying to think of which one
>> Which one?
>> which one to highlight.
>> The person whose keynotes are all like, "Look what I shouldn't have done that I did."
>> Yeah, yeah, yes. Actually one I did was
>> [laughter]
>> So, SQLite has an API that lets you implement a virtual file system. So, you can say like, "Hey, instead of using fopen or open and close and all those system calls, you give it function pointers and it's like, 'Okay, I'm going to call those instead of the system ones.'" So, what I did was I exposed that to Ruby. So, every time SQLite wanted to open a file, it would call back into Ruby code and be like, "Hey, please open a file for me." I did two things with this.
The first one was, you know how when you write a Ruby script, you can
>> put
>> under __END__ at the bottom and then you just have like data, any kind of data that you want at the bottom of the file. So, I made this script so it was self-contained. So, SQLite would store the database in
>> the file.
>> in the file. Yes.
>> Okay.
>> [laughter]
>> Like you could run the program and there's no database file anywhere else. It would modify itself and then store all the data there.
The other use case I did, I hate to say use case because there's got to be a better word. Like use case implies that there's like use.
>> [laughter]
>> You know what I mean? Like utility.
>> Yeah.
>> This is more just to see if I could. The other case that I did was I wanted to store data in HTML tables. I actually got this idea from Chad Fowler. He's like, I think it would be cool if we had a database that stored all the data in tables. So your table is a table tag.
>> Yeah.
>> Right?
>> Right. Yeah. All right. Which column is this in or what?
>> Yeah, you got to look at the TR for the row and then you got your TD.
>> [laughter]
>> So I did that because I thought it would be fun. And yes, you can do those things. They're just not useful, I think.
>> Can we workshop coining a term for this? If we can't figure out, can we make up one? Is this like an itch case?
>> Yes, edge case. Yeah, not a use case. It's an edge case.
>> Itch case.
>> Itch case. Ah, itch case. Yeah.
>> Scratching an itch case.
>> Yeah. Yeah, I like that. Yeah.
>> It's short. It's only four letters. Itch case. There you go. All right. I'm going to go trademark that later. itchcase.com. Can you tell us a little bit about what is FFI?
>> Ah, yes. Let's talk about FFI. This is a favorite, top fifth favorite itch, yes. This is a great transition since we're on the topic of native extensions. We should talk about FFI. This is kind of a long winding story, but since I work on a JIT compiler team, I really really really really want people to write their code in Ruby. And the reason I want that is because our JIT compiler can't speed up anything but Ruby. It can only speed up your Ruby code. It can't speed up native code at all because it doesn't understand it. So, I really want people to write things in Ruby.
But that said, we were talking about legit use cases of native extensions, and one of those cases is like, hey, I got a library, SQLite for example, and I want to call into that thing. So, I'm going to write a C extension to do it. And you can do that. FFI is a library that allows us to call into C extensions without writing any C code.
>> Oh.
>> So, you describe to it in Ruby the function that you're going to call. You say, "Hey, I want to call a function named, I don't know, foo, and it's going to take an integer and it's going to return another integer." And you tell that to libffi and libffi is like, "Great. Thanks for telling me." And then it sets up the call for you and then you're able to make that call. You can call into it. So, it does that connection. It takes the Ruby side and the native side and it connects them together.
>> [clears throat]
>> For all the podcast listeners, I'm putting my hands together like it's
>> Yep.
>> a connection.
>> They're interlocking. Yeah, they're
>> They're interlocking. They're connecting. And that's great. So, what that means is you can write Ruby code. You write pure Ruby code and then that pure Ruby code is able to execute native extension code. The problem though is it's very slow. So, I've written many native extensions and I have not used FFI, and the reason is because it's slow. When you make those calls, it's very slow. I gave a whole talk about why it's slow. So, you should, I gave the talk in Japanese though. So, maybe don't go watch it.
>> [laughter]
>> There might be translations.
>> There might be translations.
>> But there's many reasons why it's slow, but it's basically doing a lot of work. So, one of the things I would really like to do is, I built a project that takes your FFI code, so you write in Ruby, and it generates a C extension from it. So, it takes your Ruby code and then translates it to C. And then we compile the C extension, and all of a sudden your code is faster because it's a C extension. That's nice, except that we're back in C extension land, which I said I don't want C extensions, I want you to write
>> Yeah.
>> I want you to write Ruby code. But you did write Ruby code. You wrote Ruby code, and then you got C code out, it turned into C code. Where this fits with the JIT compiler though is I made it so that when it converts it to C code, the C code includes hints that the JIT compiler knows how to read. So, when the JIT compiler comes in and starts compiling these functions, like it's saying, "Hey, we're going to do a new SQLite database," it reads the hints that are inside of the C extension, and it uses those hints to generate its own function calls. And then it doesn't use the C extension anymore.
>> Explain that to me again.
>> It is a very very magic trick. So,
>> That makes more sense.
>> we, so, typically you call from
>> What does a hint look like?
>> The hint is just some metadata. It's like
>> Okay.
>> It's literally just like, "Oh, the function is named foo. It takes an int. It returns another int." So, the reason we want to do this is because, I'm going to throw some terminology at you, but I'll explain it. We want to be doing boxing and unboxing of values inside of the JIT compiler. Boxing and unboxing, what that means is taking like a Ruby integer, for example, and converting that into a C integer. So, that would be unboxing it. And then taking the C integer and converting that into a Ruby integer, that would be boxing it. So, we want the JIT compiler to be in charge of doing all that type translation. The reason we want to do that is because we're able to profile and specialize all the machine code that we generate to those types. The issue with the C extension is it's totally opaque. We don't know what types it's going to take and what types it's going to return and what it's going to do with that stuff. So, that's the problem with C extensions and JIT compilers. This idea here solves the issue.
>> Can you think of some scenarios where a typical Rails developer might feel like they would want to take advantage of FFI and these tools?
>> Only if you're writing gems. Just like writing Thread.new or Fiber.new, don't do it.
>> [laughter]
>> Don't do it. Okay. So, if you're writing a gem.
>> Yep.
>> When developers are working on gems, what are some things that you wish, if anyone out there is listening and they've never released a gem or even written one, what are a few tips that you would recommend before they were to do that? When do you think it even is appropriate to have a gem versus just having something in your Rails app?
>> Boy, I don't know. I think it's a really tough question, especially these days with LLMs and stuff.
>> Mhm.
>> Because you could just be like, "Yo, Claude, make a thing for me." Right? And we can all just do that. Like, I don't need your gem. I can just be like, "Claude, I need you to
>> integrate with this third-party
>> Yeah, do this thing. So, it's getting to be kind of a tougher question to answer these days. Because I think before AI I'd be like, "Okay, anything that doesn't have to do with your..." So, well, actually, I think some of these answers even apply to AI. If it doesn't have to do with your core business, like, I don't know, if you do a third-party API integration, since it's not really part of your core business, that's something you probably ought to pull out into a gem. And it's not necessarily about being a gem in terms of being open source or whatever. It's more about architecting your application such that it's more maintainable. Because if you're integrating with a third party, maybe you want to run tests on it independently of your main application. Maybe you need to add new features and iterate on that, and you don't have to iterate on it in tandem with your main app. So, that's the main reason to put things in libraries versus just keep it inside of your application. Whether or not you choose to open source it, that's a different question, I guess.
>> Yeah, I think about the scenario with AI and LLMs now, where you can collaborate with it and have it generate a client interface to some API or something, and there's probably pros and cons to even doing that. Are you, out of curiosity, using these AI and LLMs really much in your work?
>> Dude, every day. Oh my god, all the time. Yes. Yes.
>> What types of scenarios do you find it to be... I mean, we're recording this, it's the second half of May 2026, so I know that by the time this gets published, the whole world could be drastically different. But where do you find it to be really, really helpful for you right now?
>> That's a great question. I'll share some helpful stuff and then maybe not so helpful stuff. I really, really like it for searching through code that I don't understand or I've never seen before. Working at a company with thousands of developers, we've got a lot of huge apps that I've never seen, and due to the nature of my work, I need to be able to hop into it and figure out what the heck is going on, and I'll tell you AI is just the bee's knees for doing work like that. Really really enjoy it.
I love using it for hobby projects. I need to release this as an open-source gem. Well, I've built several things. I built a JPEG encoder with it, which is very cool. And it's because I got these signs. Okay, sorry, we're going to go... Yeah. Okay. Okay, sorry, you won't be able to see this on the podcast, but I got these things here, these little displays. You see that?
>> Yeah, yeah.
>> Yeah, so I've got these little mini displays, and funny enough, they have like a web API, basically, like an HTTP API, but you have to post JPEGs to them.
>> Oh.
>> Yeah.
>> Okay, sure, but I want to programmatically generate JPEGs, right? I want to make the JPEG, I want to make stuff and then post it to the thing. So, there weren't any JPEG libraries. So, I had Claude make one for me.
>> Mhm.
>> And then posted that there. So, I really like it for that. I also made, oh, a printer. Okay, I bought a printer. And it's just like a little photo printer, right?
>> Sure.
>> And I want to send images to it. But I was worried that when I do print from Preview, whatever, I was worried that it's doing some processing on the image before it sends it to the printer. Yeah, I'm like, is this changing my colors? Because I look at the photo and it doesn't look as good as the monitor.
>> Sure.
>> And it turns out the real reason is because I need an ICC calibration file for the thing.
>> [laughter]
>> I'm getting in way too deep here, okay? But I had Claude build a little printer thing for me, so it would connect to the printer and then upload the JPEG, and I know that there is no
>> It's going to
>> Yeah, nobody's doing... the data that was on my computer is the same data that got sent over the socket to the printer. So, I love it for that stuff.
>> Yep. And are the photos coming out a lot more consistent now or
>> No. No.
>> [laughter]
>> It just looks so much better on my screen, but why doesn't it look like that on my
>> Yeah, the
>> piece of paper?
>> I'll tell you the reason. The reason is because the dynamic range on the printer is, and what I have to do is, no, well, no, I'm not going to do that. What I have to do is I have to map the colors to the ones that the printer can actually support, so
>> I
>> That's the problem.
>> So, you'll just fine tune it in your processing and then it'll match.
>> Yeah. I'll tell you the thing I don't like about AIs. We're going to get into it. I told you I'd get into that.
>> Yeah, you did.
>> I'm worried that, I kind of want to write a blog post about this, but I haven't fully 100% formed my thoughts on it, is that if you and I are working together, we're both on the same team working together. And when we first start working together, you're sending PRs, I'm going to be reviewing your PRs very carefully. And after a while though, I kind of get to know you and I know your work and, depending on your work, whatever, I might review your PRs less and less because I'm like, well, you know, Robby knows what's up. Like, hey, I trust his work. Ship it.
And I think that we can fall, I have personally fallen into this trap with AI where it's like, hey, I asked it to do a thing. I reviewed it very carefully. It did the right thing. Great. Do it again. Did the right thing. Great. So, eventually I start reviewing it less and less and then you fall into this trap where it generated some and you didn't realize it. So, I don't know how to
>> reconcile
>> Yeah, yeah. How do you reconcile that exactly? You cannot treat it like a human. It is not, but it is close. It's close enough to trick you into thinking it can do a good job, but in some cases it just can't and there's no, you know, there's no signal.
>> Yeah, you can't really apply the same, build up that same sort of
long-term confidence in your whatever your agents, your AI friend and as you can with humans. To be fair, I mean, I've also worked with humans where their code has deteriorated over time cuz they didn't care as much as they used to or they were on the way out of a job or something, but those were less frequent, I think.
Well, also I mean, in that case too, you're able to talk to the person. You can find out like what the context is. Yeah, like what's going on with that? Whereas it seems, I don't know for sure, but it seems like the rate is basically random when it comes to an AI. So, you don't know necessarily. It's like Claude's not going to be like, oh, I'm, you know, I'm hungover. [laughter]
Sorry about that.
Yeah, you know what I mean?
Oops, my bad.
Yeah.
Yeah.
It's going to be just as confident on every single time you ask it to do something. It's like, "Oh, yeah, I totally did it. For sure."
Yeah.
I hadn't thought of bringing this up, but I know that when it comes to navigating, dealing with open source in particular, so you're involved in several open source projects and a gatekeeper in a lot of ways. And I mean that in the best sense. Someone's going to clip this. Oh, no, TikTok is coming for me. Aaron gatekeeps everybody. No. I'm sure people might accuse people on Ruby on Rails core of that as well. But aside from that, when it comes to protecting, especially security concerns, I think you had posted not too long ago that you're getting PRs from people that might be security type situations and they may or may not even fully understand what they're submitting a PR for, but they used an AI tool to help them
Yeah.
try to contribute. As someone that works on open source projects as well, that's an interesting challenge where it's like, well, how do we navigate this, cuz there's more of a flood of them at times, more PR volume, and then the security ones tend to catch our attention the most, especially if they write to your security email address or whatever your team might have set up. You're like, "Hey, this is a thing. Do we need" cuz it requires you to have a conversation. It's like, "Is this real or not?"
Yeah.
And I mean, just anyone listening, if you wanted to disrupt an open source project, start hitting their security thing with seemingly realistic security threats, they're going to get bogged down in just dealing with that, and that kind of sucks.
Yeah, it's a great way to do a denial of service attack on an open source team, yeah.
I'm done. [laughter] I don't want to look at any of this stuff.
So, please don't do that, everybody.
Yeah, we
But how do you navigate that?
Well, the very first thing, like I mentioned this on my blog. Yeah, I made a short blog post about this. So, on the Rails security team, we were working with the IBB, the Internet Bug Bounty.
Yeah, yeah.
What they would do is they worked with different open source teams to give paid bounties to security reporters. And that was fine. I mentioned I wasn't sure about this program from the start cuz when you start paying bug bounties, of course there's going to be people out there who are like, "Woah, I want some free money, right?" So they're going to start sending, I don't know, crap basically. And they dealt with that at first. This was before the AI era.
Yeah, yeah.
The other issue we would run into is people who haggle, cuz the IBB would pay more depending on the severity of the bug. So if it's more severe they would pay more. So then you get people who are like, "Oh, this bug" Oh my God, the ones that I hated the most were like, "If I write this control character to your terminal, like if it comes through your logger and it shows up in this terminal that hasn't been updated since 1996, it could possibly overwrite some characters. So then I'm able to hide stuff that's in the logs." And I'm like, "Oh my God." And they're like, "This is obviously the most critical bug that there is." And you're like, "No, please. This is not a critical bug, please." But people would haggle over that. But then when AI came around, we just got this flood of low effort security issues because they could get free money basically.
Yeah.
So the very first thing that IBB did was just shut off bounties. So they stopped paying bounties and I got to tell you, that really decreased the number of security reports that we get. [laughter]
There's your solution. Just don't solicit them.
Yeah.
But I mean, you know, that's not
It's not a good solution cuz I really want security researchers to get paid, right?
Yeah.
But this is apparently not the way to do it. I mean, of course we also started using AI to process reports. I know people have asked that, like, "Well, did you use AI to process them?" We do. Still do. I don't know. I don't have a good solution for it. I mean, it just feels like a damned if you do, damned if you don't type of situation.
Have you seen much of an increase in just general PR contributions to the tools that you work on?
I mean, we get a lot of AI contributions. To be honest, people sending normal PRs using AI, I don't really have a problem with that. That's fine. I think that's like, whatever. More power to you. You wanted a feature, you used whatever. I keep saying Claude. Claude's my favorite one. I know there are others, but you know, you used Claude to do it, seems good. Whatever. So I kind of like that.
Do you ask that they disclose that or is that even really that important to you?
Is it important to me? I don't think it's important to me. I mean, when the PR comes in, if we accept the PR, it's now on us to maintain it. We can't ask anything from you.
Mhm.
Right? Doesn't really have any impact per se.
Sure. I can appreciate that take. I've definitely talked to people that fall very differently on the spectrum. Do you feel like that would have been a very different response six months ago from you?
Maybe, I don't know. I don't really think about it that much. Where it really does impact me is, I don't care how other people use AI, but I care very deeply about how I personally use AI. I need to understand the code. I found after that one experience with AI effing up real bad, I'm like, all right. Sorry, bud. You're now regulated, or relegated, to stuff that I just don't want to do. [laughter]
Which
But somebody might argue those could be the things that need the most attention though, Aaron.
Yes. But the main thing is I personally need to understand every single line of code that is coming out of this thing. If I submit a patch, I need to understand all of it cuz I need to be able to defend it and explain it. And I ask that of people who send PRs to me. I'm going to ask questions about it and if they can't answer the questions, the PR is probably not going to land, you know?
Yeah.
But there's no judgment about whether or not they used AI. If you used AI and you understand everything it did, great.
But it's hard to tell.
Yeah.
And it has been an interesting thing navigating the last several months. I don't know where everybody's going to fall on this. For some of the projects that I've been involved in, the fact that we even said you can maybe disclose it, some people are like, I don't want to use your tool anymore because you're allowing AI to infect it. And I'm like, but it's all the spectrums and everybody's
Yeah, I mean, nobody's going to be happy. Remember when Copilot first came around, it was very much, you know, intelligent tab completion. It's like, well, is that I mean
Yeah. That's the example I always bring up, like how do I know where AI stops and starts in some of the tooling that we're using? Is this an editor tool? Or if I'm just passing a GitHub issue, I'm like, "Hey, can you just submit me a PR for this?" You can have it do that as well. You should probably review it. But then some people are like, "Well, I just have another bot review the PR. And if it approves it, then great. We'll just ship stuff that way." There are people trying to figure out how to make that work with their organizations and
Yeah.
Yeah.
That part seems somewhat risky to me at the moment. I'm kind of worried it will get into a situation where it's bots reviewing bots reviewing bots. And then we're going to end up with a giant mess. I think what we'll have is, oh, what is it? You remember there were tons of software patterns coming out of the '90s and early 2000s where it's like, "Okay, design patterns." And then we had all these names for things like the giant ball of mud and all those different names. I think there's going to be a new generation of code that's generated by AIs. And we're going to have names for those things, too.
We'll have to do another episode where we can work on brainstorming names for these patterns then. That could be fun.
Yeah, cuz there's got to be a way to differentiate between a giant ball of mud that was human-made, like a man-made one, versus an AI-made one. So funny I say man-made now cuz that's not typically good. But now you say a human-made
That's not how mud is usually made, either.
Yeah. I mean, I don't know.
I guess I've made mud. If I poured water in dirt,
Yeah. I guess so. I did that the other day. I was watering the garden.
Are we artificially creating mud?
Yes.
Are we? Or I guess we are part of nature.
Mhm.
Where does Hmm. [laughter]
Getting into the weeds on this one.
Mhm.
Well, I've kept you long enough, Aaron, but a couple of quick questions for you. What areas of Ruby on Rails right now are you most excited about?
What areas?
Specifically within the Rails framework itself.
Oh my gosh. This is a tough question for me. My favorite things are all low-level stuff. I can't give you any good high-level things, but one of the things I'm excited about is looking into router performance. That is very interesting to me and something that I've been poking at lately. So, I'm hoping that we can ship some performance improvements to the Rails router. But again, it's stuff you don't know about. Just upgrade and then you get it.
Yeah. Yeah.
Right.
Magic stuff.
Yeah.
Are you involved at all or see murmurs of those that are working on more tooling within Rails that will be useful with other LLM tools?
Yeah, I think
Rails query, I think, was a new thing that just got released or
Rails query. Ruby Dex is very cool, but I know it's not Rails specific. I really love the AI tooling that folks are coming up with. Anything that can help folks get in and get developing on the application is very interesting and fun to me. I'm hoping that we get more features integrated like, you know Marco Roth? His stuff is so amazing. I want more of that stuff built into Rails.
Is that Herb?
Yeah, Herb is very cool. Extremely cool technology. I'm a huge fan, so.
I'm with you on that one as well. I'm curious, Aaron, is there a part of Rails that you think the typical Ruby on Rails developer would benefit from going to look at the source code, acclimating themselves
Good question. I say good question a lot. Maybe I should say that that was immediate cuz
Immediately a bad question. I actually thought you meant that it was a bad question.
It's a good question. I just feel like I'm saying that a lot.
Give them a homework assignment.
Yeah, go figure it out yourself. No, I think it depends on what you're interested in. Are you interested in the database? You should dive into Active Record stuff. Are you interested in view stuff? You should dive into Action View. Also Action Controller. It really depends on what you're interested in. One of the things I did when I first got started looking at Rails internals is I'd be like, okay, how does link_to work? Like how? And then I just went and read the source code for it. I am jealous of people getting started today, mainly because of AI stuff. Can you imagine? You're like, hey, I would like to get started understanding how Rails internals work. You could just go into Rails itself with Claude or whoever and be like, tell me how link_to works. And then it's going to walk you through the freaking code. Incredible.
You could probably have it build a little tutorial that's custom tailored to your way of learning and
Yes.
learning things as well. That could be kind of exciting.
Like me, I had to do the slow path. Like, where is this defined? Where do I find this?
Oh, nothing. Yeah.
Yeah.
Follow the method. Follow the thing. I'm like, okay, it goes to this and
Yes.
this other method_missing thing, or what is this thing?
Yes. Yes.
What does that even mean?
And now today you've got a little buddy that's going to walk through it with you. So I like that.
Hold your hand.
Yeah.
Do you have a technical book that you find yourself recommending recently to peers?
I do. I'm very glad that you asked this question.
I'm not sure if I'm supposed to, I think I can tell people. There's a new book.
Oh.
Well, not new. I recommend Ruby Under a Microscope. Pat is working on an update to it, like a V2, and I know this because I'm doing the technical review for it.
Ah.
So, I recommend that book when it comes out. I think they're going to be putting it in, it may already be in a preview or whatever, so you can read chapters from it and stuff, but I really recommend it because I think it is the best introduction to Ruby internals that you can get. Well, not even introduction, it's intro plus intermediate, probably advanced stuff, too. Also, I'm reviewing it, so
It's going to be excellent.
Yes, it's got to be.
He's full of itches.
Yes.
So, Ruby Under a Microscope, and that's by, how do you pronounce this last name? Is it
I think.
Shaughnessy.
I think.
Who's publishing that? Is that self-published or
No. I think it's No Starch. I'm not sure.
Okay. I'll definitely include links to that in the show notes so people can check on that and find out when the next new version's coming.
I have a second one if you're interested. Okay, I have a second one. This one's very, very advanced.
We're out of time, Aaron.
Oh, shoot. Okay.
All right.
Go away. So, I have a second one, but this one's very advanced. So, if you want to learn about JIT compilers or any compilers, I recommend a book called Engineering a Compiler.
Hm.
And it's very good. It's got a lot of the techniques that we use in ZJIT in it. So, if you want to learn how it works, there you go.
Excellent. I'll definitely include links to both of those books in the show notes for our listeners. And where can listeners best follow your thoughts and ruminations about Ruby, Rails, and software engineering online?
You can follow me on Bluesky at tenderlove. Also, I'm trying to make more blog posts at tenderlovemaking.com.
Excellent. I'll include links for all of that as well. And with that, thank you so much for stopping by to talk shop with us, Aaron.
Yes. Thank you, Robby. It was a pleasure.
It's been such a delight to get to see you and hopefully get to see you again at an upcoming conference or something.
Of course.
That's it for this episode of On Rails. This podcast is produced by the Rails Foundation with support from its core and contributing members. If you enjoyed the ride, leave a quick review on Apple Podcasts, Spotify, or YouTube. It helps more folks find the show. Again, I'm Robby Russell. Thanks for riding along. See you next time.
Article published
