Hey, welcome back to the Ruby Dev Summit. I'm so excited. I
am here with Samuel Williams. Now Samuel lives on the upside down part of
the world, you know, where it curves curves under. Uh he's he's
from New Zealand and he he's working on some really really interesting projects. Maybe
I'll let him tell about it a little bit more, but the projects are
a sink and Falcon. And Falcon in particular is interesting because it's like an
HTTP server or something that it's like, oh, you're writ in that and
Ruby. That's that's wild. Reminds me of Mongrel with what's his name z
right Mongrel anyway, So uh yeah, excited to talk about it. And
I think we're going to get a different perspective here because I've either been talking
to people who build Ruby engines, right like Opal or you know, I'm
trying to get Truffle Ruby or somebody on. But you know, people who
work on c Ruby. And then you know, I had Amir Rajon who
works on Dragon Ruby, which is a Ruby engine but it's built for video
games, which that was a fun talk, you know. And then I've
got people who work out there in the ecosystem building open source. But you
know, again it's mostly web like web development, so you know web frameworks
are working in Rails, and so yeah, the perspective here is different.
I'm gonna stop talking and let Samuel talk. Samuel welcome. I'm just gonna
throw the question at you and you can kind of take it from here.
But what is what is the future of Ruby? Gosh, that is a
really good question. I think that for me, Ruby is a great environment
for expressing yourself as a programmer. Uh huh. A lot of programming languages
I feel get bogged down in the detail of the language, and I always
felt like with Ruby didn't take There wasn't too much like ped entry in the
code. Like it was it was straightforward to write the programs that I wanted
to create. Many years ago, I was working on a property management application
written objective C and I started hacking on a web version of this and I
started using Rails, and I felt like it was a really great platform,
but it was kind of there were some pieces missing for me. HM.
When I was working on that particular problem, I was interested in scalability and
how you build applications that can handle as of requests. And one area where
I came about this problem was actually a DNS server. And so in my
home network, I wanted to make a custom DNS server to back in the
had old days with ADSL modems, if you wanted to host a website inside
your network and still have the domain name resolved, you would have to have
a DNS server that would return the local IPA dress inside your home network for
the webs wow locally. And if you were like on the Internet, you
would have to have a DNIS server that would return your ADSL modems ipadriss so
you could do port fording like poor ad or whatever, right, And so
I was trying to build this website, like, well, this is kind
of an interesting problem, and so I kind of switchedcars a little bit,
and I wanted to build a DNS server that could do this for me.
And I thought this, you know, Ruby seems like a reasonable language.
Is it's basically just pan matching on the host name and then returning a different
DNS How hard could it be? And so I created a probably one of
my first gyms. It was called Ruby DNS and it was a a DNIS
server for Ruby. And the first time I ran this my whole network like
crash. Yeah, running single three to DNS service isn't you know, very
practical. Essentially, every computer in your network is doing DNS queries like multiple
queries second, and if your DNS server can't handle the incoming load will stop
working, like your web browser will stop working time, you know, into
stop everything, just like cries to a whole So I started, you know,
it was my first real experience of concurrency and scalability problems because it's just
like, well, this is an easy problem, like, you know,
it's a well defined problem. You know, message comes in, do some
kind of computation, you respond, you know, it's really straightforward. And
I felt like really didn't provide the right tools to solve it, and that
that to me was a little disappointing because it's like, well, the code
itself is clear. You know, I can write down what I want,
which is I want to pay and match this host name and return this IP
address if ther comes from inside the network. Otherwise like pass the request down
you know, to the to the I s p's so so so to me,
like it was a straightforward problem. But the way that Ruby, the
tools that Ruby provided to solve that problem, weren't weren't necessarily convenient or scalable,
or it wasn't even maybe obvious even if Ruby at the time could do
that, like how you would go about doing it. So in that first
instance, I started trying to work on the multi thread of DNIS server,
and that was difficult because it's still has scalability issues. And I started learning
about like new texts and and parallelism and all these like sort of challenges associated
with using threads, and that those challenges they weren't insurmountable. But I felt
like, now my code is much less clear. I'm writing this code,
I have to deal with these concerns around concurrency that in PARALYSM they didn't really
want to. I just want to say, basically like here's a request block
of code that handles the request, and here's the response, and then we'll
deal with anything else. So at this time specifically, I started working on
an interesting test case for this, which was called Wikipedia DNS, which is
a DNS server which it basically doesn't HGP request to Wikipedia to get the summary
for a topic, and so you can get Wikipedia summaries through DNS, and
so what was interesting that this problem was that I had to do an HTPP
request and so as you can imagine, doing hp request is kind of slow,
and so it was an interesting test case for me because I was like,
how do you make a DNS server that's doing this more efficient and scale
better? This problem is the same problem as you see applications and in other
types of response systems. And so at that time, Tony Tony rc Area,
I think it's how he pronounce his last name. He was working on
celluloid and he was working on actor based concurrency. So active based concurrencies where
you define essentially a unit of work and that unit of work happens independently of
other units of work, and it uses the actor model, which is message
passing. So you have these different light systems. You have like a every
connection that comes in could be its own actor, and then when it needs
to do an HTV request, goes and talks to another actor, and the
actor itself is then responsible for doing the ht requests, and once that request
is furnished, it comes back to the original beas is, Hey, you
can keep on going. Yeah, And then a lot of those systems,
those actors are separate processes. They can be or separate threads, and so
at that time I was like, well, this is seems like a neat
idea, Like maybe this is the right approach, And so I started working
down, you know, going down that pathway and building that and so I
built celluloid. Danis and I worked on the cellulord gym quite a bit.
But the biggest disappointment there, I think was the fact that celluloid was so
complex that it kind of collapsed under its own Weightman complexity was just to agree.
And I think the actor model, when you start trying to build a
practical actor model, does get extremely complex, like supervisors linking actors together.
One particular piece of code that really bothered me was this concept of linking actors
together. And so the linked actors, where one actor crashes, the other
will get informed of late restarts. Kind of forms a supervisor relationship. So
if you have like say a web server, and that web server blows up,
you have another actor whose sole purpose it is to restart that server for
example. Right, this is this is how a lot of the ear laying
and elixir stuff works. That's correct, Yeah, yeah, And I'm not
really like criticizing earl and elixir I think they're great systems for the problems they
solved. But for me personally in Ruby with Sally Lloyd, the piece of
code that bothered me the most was this one piece of code which basically has
like a five second time out where it basically tries to talk to another actor
and if it doesn't respond in five seconds, it just blows up basically,
And I was just like, why is it five seconds? Like and the
whole, the whole like semantic building like building block above. It was all
based on this kind of like implementation detail that really bothered me, and it
the challenge there is there were too many choices to be made and the semantic
complexity just got out of control. And so as a consequence, Sally Lloyd
never really reached a one point over release. There was never a point where
we could say, hey, this is what Sallyloyd is and and this is
the foundation of what you can build other things. So I basically built like
a version of Ruby DNIS that worked on Stellulod. All the way to the
end point I was just like this is I just can't I don't want to
release this, and so at that point I made the decision to release to
work on, like to do this myself. I kind of got sick of
depending on other people's ideas, was like, and I kind of know what
I want to do this right. And that was the birth of ASIN,
the gym that I created for doing Ruby's concurrency concurrency within Rubius, and so
asink was was born out of frustration. I suppose you could call it frustration
development. That's frustration development. You know, there are a lot of very
great things that came out of frustration driven development. Absolutely, and I knew
like for me, like one of the key goals was having a specific,
a well specified interface and having that well specified interface as quickly as possible,
and and and not not trying to and not let the scope of the problem
and Samandis create beyond what was manageable, because ultimately, when you start doing
that, it's the it's actually the engineers who pay the price of complexity.
As a as a person who is trying to solve and build a foundation for
the engineers, every decision you make is at least I personally think, if
this is not complexity, I can solve and hide from the user. Am
I am I comfortable with exposing that complexity to the interface that the engine is
ultimately you have to build the applications on, because when you start doing that,
then instead of you paying the price, you're basically just passing it on
and saying, hey, I can't solve this problem. Yere you deal with
it and then what you deal with Instead of you solving that complexity in one
place, you're basically forcing every engineer who interacts with your interface to solve their
complexity. And they spoke buggy an incomplete way, right, So I think
it was really important to me to say, hey, look, this is
the interface I'm going to have, you know, and for me, there
was a task based interface where tasks run concurrently, a well defined way of
starting them, a well defined life cycle, and essentially being able to say,
hey, this is this is the whole interface. The implementation will probably
get better, but this is the interface. This is the fundamental foundation which
I think concurrency should work. And so there was a stable flag built that
and released it I think in like three months, Like I can't miss you
remember the exec details, but I think we got to a one point of
release of facing pretty quick and that was that's you know, that was you
know, the rest is history I suppose so, so yeah, So the
question was what is the future Ruby? Do you think concurrency is the future
Ruby? Then this kind of concurrency. So look, I suppose my mental
model has always been Ruby is is a language and instead of tooling and frameworks
that as well utilized across the work ecosystem, like lots there's lots of big
companies using Ruby, right. And one of the things I've talked about often
in my in my presentations in conference talks is I try and give like a
few minutes on climate change and talk about the nature of it and technology and
how we're I don't plan to be an expert on this topic, but like
being a parent, is kind of concerning like what's happening right now. And
I think technology, I think that I have to say I'm probably like a
technologist in terms of like what solutions we're looking towards. I think it's just
because that's who I am, right, and it's Ruby as being a technology
which is widely adopted, but that the models and technologies that we use with
then Ruby to achieve scalability are less efficient than they than they could be.
Ok. And so I think that my goal has always been to provide more
efficient primitives to build web applications with Ruby, and in particular to retrofit existing
applications with minimal changes to take advantage of that increase concurrency and scalability. So
give you like a really practical example of this. We had one of my
friends had an application that was running on like, I don't know, up
to eight instances of Perma and it still had like ladies issues when there was
a spike and load and it wasn't it was mostly ir that they were doing.
And they migrated to Falcon and they got it down to like one instance
and I think one more instance for worse or something like that. Oh wow,
So like this the kind of like success story in a way, I
suppose, because for me, you know, someone could take an existing application
with minimal changes, run on Falcon and then reduce their carbon footprint of the
application. I suppose you could call it so like the future of Ruby in
my mind, Like for me personally, you know, apart from all the
great work that people are doing, because there's a lot of it is more
about how do we take all that. That's what I'm looking for velocity.
You know, all of this lines of source code and make them more efficient
and work efficient. And so I think for me, the future of Ruby
is all about efficiency and doing more with less and that's pretty much what underpins
the async model. You know, we can do more IO with less CPU
cause basically, well it's it's funny too because you know you're talking about this
in terms of like climate change, and you know how well we're using the
resources we have. But the reality is is that it's actually if you can
run it on less cores, maybe with less memory, it's cheaper anyway,
right, It's a way saves money. Yeah, absolutely, Like then,
since I gave before the example I gave before, it was saving money.
So yeah, I think that there is Look, everyone has their own use
cases and in their applications. Sometimes the CPU be sometimes that I hev.
It really depends, But I wouldn't want to say my experience with real replications
across large companies as extensive. I've worked with a handful of them, and
I get to see people with the internals of people's applications and look at tracing
and and APMs and whatnot, and they looked at the data. There's only
so much you can achieve in one lifetime. But from my experience, a
lot of applications are iobou they are. You know, anytime you have a
web request, you know the h GDP or something like that, you potentially
significantly I abound. And I suppose there's lots of strategies to deal with that.
Sometimes people use background jobs, sometimes they will use background threads. There's
all sorts of strategies you can use to deal with improving the efficiency and performance
of this type of code. But I think, like a lot of it,
a lot of the time you have the trade off of code complexity versus
efficiency. And there was a talk that really inspired me initially, h I
don't the talk really inspired me. I think the conclusion of the talk,
like many years later, was ultimately not as good as I hoped it would
be. But there's a talk C plus plus courroutines and negative overhead abstraction which
really inspired me when I was looking at curroutines and fibers. This talk basically
starts right from the beginning and looks at how traditional punch card computers work and
how you have like a stack of punch cards and you basically step by stick
to build like a compiler. You take your punch cards, and they go
from one machine to the next, and they go to the next machine,
and you're taking these whole stacks of cards. And they were basically saying,
well, how do we like that If every step takes ten seconds, then
the total processing time there's going to be like ten seconds times a number of
steps. So how do we make this faster? And their their solution was
to when one punch card is finished from one machine, you put it to
the next machine. Basically, so instead of every step taking ten seconds,
you can kind of combine them all together because the punch card is flowing to
end. And but traditional programs don't work there, like a function call.
When you make a function call basically saying hey, here is a bunch of
inputs and then give me give me some result hm. And there's there's no
easy you know, if you if you feed in ten gigabytes of data,
it's going to churn away on that data and then come back and say here's
your team gigabytes or whatever. And so this is kind of the same problem
as the punch cards. You know, if you have a whole bunch of
functions you want to chain together, then the total lazy of the system is
all the individual steps added together, right, and you can't really avoid that.
So the whole idea of a co routine is to kind of short circuit
there so that when one function is finished with one data point, that can
just pass it onto the next function. And so this instead of being like
running and they're very manular level, they're running kind of almost and lockstep on
one data point at a time to hold through the whole pipeline. So this
talk that I watched about C plus plus curatoons and negative overhead abstraction really inspired
me because I never thought about negative negative overhead abstraction. You know what I
mean about this is when you look at languages like jazzascript for like pulling this
one out, but you see things like a single waight the keywords, and
everyone is like, wow, you know now we can do like a single
weight, And I'm just like, so you have to add these keywords everywhere
and like we write all the code and yeah, I'm like, this is
really problem. I want to spend my time doing, you know, like
I want to go through my whole code base and rewrite everything. You know,
imagine if if multi process or multiple threads were like that kind of cooperative
concurrency with explicit keywords for yielding. At every point that you thought yielding would
makes sense, it would be another year. And you see this in the
very practical terms. You see like JavaScript libraries which have both synchronous and asynchronous
interfaces for the same Yeah, and a really common example of where I think
this is a huge problem is logging. Now, and probably there's other ways
of solving this at the core of JavaScript, but if you have a log
function and the log function is doing some kind of ir I you always get
to go through the entire source curtain and change your log function from like a
synchronous log function to an asynchronous one, just because like maybe the back end
change from standard through like an HQP to an APM or something. I don't
like. It has always struck me as odd that people would want to go
through and retarget them and rebuilt interfaces and make concurrency and explicit part of the
interface when actually it's much more convenient when it's implicit. I do give these
arguments for both sides there, but for me, I'm lying firmly on the
implicit side. Right. So I suppose with JavaScript being so explicit, has
some advantages, but it also has some big disadvantages. And so with with
curroutines, I felt it's a great model because at less you hide a lot
of the scheduling, and so with acing, I was like, okay,
i' many of use fibers to do this to try and hide the scheduling,
and it's a kind of green thread model. So with acink one point zero,
I wanted to show the proof of concept. I wanted to show I
want to give interface correct, but I also wanted to show like this was
feasible, and so acin one used a lot of rappers internally to do IO
and make sure that I was not blocking and it didn't necessarily pick up every
single operation. There were a couple of like outstanding ones like waiting on a
process to exit or DNS resolution would be like another one that that acink one
pointer didn't handle concurrently. So after I felt like ACNC like it seemed successful,
like I could build like a web server and I could run applications on
and it basically just worked as I hoped it would. So I went to
Matt's at Ruby World conference I think in twenty nineteen or sometimes around there,
and I said to Matt's, Look, we've got a perfectly like I've built
this proof of concept, like it works. It gives you insane scalability.
And I think I demonstrated the Ruby comf Taiwan and a talk called the Journey
to one Million where we did one million simultaneous web sockets and a single Ruby
process, which oh wow, yeah, it's a fun demo. Yeah sorry,
go ahead, No, I'm just saying that that's amazing. Yeah,
Matt, Matt's pressed the button on the keyboard to do the final connection.
So it was great, and I think, uh that that whole experience.
I started looking at the performance because you know, now we've got the proof
of concept, we've kind of proven the interface. What's the next step,
So I said, to Matt's, we need to make it possible to hook
into Ruby's internal schedule operations so that we can redirect those operations to the some
kind of scheduler that can then manage the fibers and have some kind of event.
Look, so a schedulist job in Ruby is to basically take an operation
like a web request, and if that request is going to take some time
to completely, say one hundred milliseconds, maybe you're talking to an external API
and it's it's slow. Then the schedulists job is to say, hey,
I'm going to pause the code executing right now until the operation can continue.
And then when the operation can continue, we will resume execution. And so
you have all these like little chunks like in a RAG application or a DNS
server for that matter. You basically have like a request coming, you're going
to do some like IR operations, and you're going to run and you have
a whole bunch of these operating all concurrently. So the schedulest job is to
basically say, well, I'm doing this request and I can't go any further
right now, so I'll go and do one at some other requests. I
can't go anyether, and I'm going to do some other requests. Now their
responses come back from their website, so I can keep on going, like
Wikipedia DNIS for example, where it was doing an API called a Wikipedia to
get the summary. So now I've got the summary, I can and procese
it and see the response. So the schedulest job is to do all that
work. And so what we do is you talk about this and this sounds
like how my friends who switched from Ruby to no JS explained why no JS
was better. Well, we have it all in Ruby now, so yeah,
we have it all in Ruby. I tried to explain that to people.
But anyway, so I think one point I was the proof of concept.
I talked to me and I said, look, MAT's we need the
hooks and Ruby so that we can redo it these operations to a scheduler and
efficiently scheduled that. And so that's what we did. And it took a
took a couple of releases of Ruby to kind of iron out all the tanks.
So we had pretty normal. Yeah, it's normal. In fact,
it's I wrote a book a blog post that two years ago, like for
the release of Ruby three point one or something. I never I never published
the blog post because as I was writing the blog post, I found a
bug. It was like, oh, no, I have to wait a
whole year to like fix this bag before I can like never came back to
it. But so we implement the scheduler hooks. So Ruby now has something
called the fiber scheduler, and the fiber scheduler is providing a whole bunch of
hooks, a couple of like io weight for dealing with like reads and rights
that are blocking. Address resolve, which deals with danais so I concurrent danis
resolution process weight, which deals of waiting on a child process to Except there
are a bunch of specific ones like io read and io right, and I'll
talk a little bit about them in the moment. And so there's all these
hooks, and so the Ruby interpreter, when it's running code that the user
wrote, if that code executes an operation that would block it gets redirected to
the fiber schedule, and the fiber scheduler will then manage the concurrency of of
multiple tasks so they can be executed most efficiently. The benchmark I have for
that is actually like going into this whole problem even with Ruby DNS, was
like, how do we run the most lines of Ruby code as efficiently as
possible? Is the fiber schedule is conduct switching between between fibers and tasks and
basically trying to execute lines as quickly as possible. I suppose you can look
at it that way. So I think two point zero was the first release
of ACNC that took advantage full advantage of the fiber scheduler, and it was
really like a major milestone. I suppose Ruby, even if it's not publicly
obvious, why you can take an existing roomy program run it on top of
acinc and gain significant advantages to I concurrency and like pinch, like other forms
of concurrency like DNIS resolution, waiting on child process and whatnot. And so
it's all well and good heaving this foundation, I suppose, But maybe that
leads us to the big topic like Falcon and how that works and why that's
important. So as we know, like Ruby, it's a great environment for
an age applications for for lots of reasons, Rails probably being like the biggest
one. Yeah, I felt like my Denis server wasn't was was one like
for me it was my proof of concept. But then I was like,
well surely we can write a web server, like can it be famous?
Right? Yeah, exactly totally. So basically I built Falcon as a proof
of concept to see, like, you know how good it is it you
know what kind of performance can we get? And so Falcon was was born
out of that kind of curiosity, I suppose. Obviously we wanted to use
rag Rack is the standard interface for between web servers and replications in the Ruby
world. Yeah, and if you optimize for RACK, you optimize not just
for rails but for Sinatra and Rhoda and all the others because it is that
core piece the HTTP interface to Ruby. That's right. Yeah, And so
it's like a volcane of worms, like oh, rack two point zero.
When I when I started building building Falcon, I was like, I want
to how RACK works. And I've done I built my own framework for Reck
in the past, but it was really just like, as a consumer of
the interface, I wasn't really considering what it's like to be on the other
side of right equation, on the service side. So when I went to
the RACK issue tracker, like it was many years ago now, there were
like hundreds of open issues. No one was really maintaining RACK, and I
was like, wow, this is a little said, this really critical piece
of infrastructure. It's kind of I suppose it's a little hidden from view because
most people wouldn't really need to know why RE exists or why it's important.
But right, so RACK is essentially a CGI gateway between It's basically using the
CGI specification as an interface applications, and so every web server that talks to
a RACK application with a request and then gets a response from their application.
Is essentially using the guts of of the CGI specification, like so as path
info is one of the more common like CGI fields, and it's it's defined
either c g I or it's used by RANK. So I was really interested.
I was really interested in HB two at the time. It's like,
there weren't many good implementations of HP two for Ruby, and so I went
and created one. There's a gym called an h pop does h P one,
HP two and hopefully H three, and and I thought, well,
why can't we support HP two directly from web service? It's pretty it's a
pretty good protocol in lots of regards, like it's a bit of a HP
one is text based, line based. H B two is using binary framing,
and so it's it's harder to stuff up HUP two, so it's a
bit more secure, and it has other advantages as well. So it's like,
what, you know, why can't I run a RAC application HB two.
Well, as it turns out there's e g I specification that that RACK
was sort of implementing. Well, semantically, you can always write proxies between
HP one HB two and HP. They've tried to have the same semandix between
all the different versions. It's just the protocol itself on the why that differs.
But but Rack itself didn't really expose a good model for that, in
my opinion, and so I started working on that problem. And so one
of the biggest most important changes that I feel like I made to Rank was
the ability to stream requests and responses. So this means that there was a
I had a conversation with the engineer many years ago and they were like,
we're generating CSV, like a lot of CSV from a RAILS air and it
gets buffered the whole lot, and it's like multi ugabytes, and we're killing
servers because because they came the whole response. How do we start streaming this?
And it's interesting that that's even a complicated question to answer, in my
opinion, because I don't think it should be. And so Falcon and Rack
the changes that I made, I was sort of trying to change to make
it easier to stream responses. And another piece of this is like web citeits
even today, rails still uses a hijack mechanism, which is where it basically
the request comes in and rails basically steals the whole connection and plucks it in
its own event loop, separate to the server itself, and then starts talking
to the website protocol on that. But the biggest issue with that is,
like, because it's hijacking the whole connection, it doesn't work with HDB two,
which supports multiplexing on a single connection, because with HB one you have
one connection per request response, and it's okay to take that whole connection and
hijack that. With HB two you have lots of individual connections running on one
TCP connection. So I worked on RACK and I solved this problem. We
released RAP three three, three point whatever. There was quite a lot of
shown as we figured out a few compatibility details, and so now it's possible
to run web socits natively on a rat compatible server that includes perma Falcon.
I think even webrook is supported with you know, you can just run a
web soce straight on the request. Yeah. Yeah. And so I was
really pleased about this because it's sort of kind of bait to the question,
which what is the future of Ruby. Actually, I suppose as an engineer,
I was really disappointed at how badly web socits were handled in Ruby.
It was like websites were vented? How many years ago? And how long
has it taken us to get to the point where applications can just like native
And then I think that I don't want to be too critical, but I
think that's how Ruby back in some regards. You will look at that and
go, well, Ruby can't do this, and it's like, well,
yeah, and how we're going to solve that problem? And so I think
the future of Ruby in some regards there is catching up to do the technology
side, but I hope that things like Falcon and as provide the right foundation
for building those applications and going forward with improved concurrency and scalability. Right,
cool, Well we've spent It's so funny because I usually have to prompt people
as I interview them, and you know, to clarify more things and you
know, and then it's like, oh, we went for you know,
however long and yeah, I mean I feel like I maybe added some color
commentary, but for the most part. It was really fascinating though, to
have you kind of walked through that whole process, because yeah, I mean,
concurrency is one of the things that I hear a lot of people talk
about and it's some of it is down to, yeah, am I making
efficient use of the hardware? And do I get the performance gains out of
right? It has four cores? So why am I not using four cores?
But the other end of it is is that and we all want that
kind of efficiency. But but the other side of it is is, yeah,
you know there's some capabilities that come along with it that that, right,
it changes Actually it's not just about making things more efficient. It actually
changes applications, right, And so just looking at that, it's it's very
interesting to look at Okay, you know now that I've got these things working
for me, Yeah, I've got I've got these options, and so that
that's very very exciting. I'm wondering too, because some people have left Ruby
because of the concurrency or other concerns. Do you think we'll pull some of
those back or do you think they're just going to stay in whatever land they
went to to find that? Gosh, that's a good question. Look,
I don't presume to know what people do or don't want as engineers. I've
always just felt like I want to scratch my own note. Right, Look,
I suppose yeah, the biggest elephant in the room. There will be
something like Alixa and yeah, look it's a great technology, and crystals as
well. From my point of view, just look at as the biggest thing
for the buck, Like if I went to work on Crystal or Elixir and
solve or improve their concurrency. It's sort of like if at times like the
size of the market or impact, And so for me, like the size
of the impact for Ruby is just so much bigger, right, So it's
even the same amount of effort because it's multiplied by the size of the market,
has so much more total impact, right, And so for me personally,
that's the equation I work from. I'm like Ruby is a low hanging
for it is such a great scope for making existing applications work better and more
efficiently. And that's what I personally find exciting and seeing the early adopters take
Falcon, use Falcon, you know, use acing HP and derive those in
credible benefits and build and and and and Finitially, that the the nature of
the kind of application that can build the web sockets and service and against and
all those other kinds of technologies that are now very easy to use. We've
we've lowered the bar and like on accessing that level of interactivity and so it's
exciting to see what people do with that. So to answer your question,
like I suppose it doesn't really matter because people will use the technology of the
most comfortable with and that's okay. Yeah, And like I suppose at least
if someone's arguing that Ruby's not capable of doing like concurrency, we now have
a counterpoint, which is, hey, actually it can, and it's really
good and it works really well. And the only the only argument I would
really say that that works against that is like it's still early days, but
like I don't expect someone like this to be adopted overnight. Like it's already
been six years and we've got our early adopters, which is amazing, but
it takes time for companies to Companies are extremely slow on adopting new technologies,
and so we're going to be I said, look, I know these major
companies using anything. I can't really talk to them, but you know,
it's hittening and I think that that's a good you know, make it as
good as we can for the engineers. If it solves an engineering problem,
they will do like people will use them, and I think that's yep,
absolutely well. And it's interesting too because as I've done these interviews and it
kind of goes back to the point you were making earlier, and the point
that several others have made is that Ruby, it is so expressive. It
just gives you so much in the way of how do I put it,
So people are adopting things like Python. Python seems to be, you know,
having a renaissance these days because it has powerful math and science libraries that
and it's approachable enough so that people in academia can go and they can do
their thing with it. Right. So that's It's not the expressiveness of the
language, right, It's not you know, any of the things that in
my opinion draw me to Ruby, right, And so as long as it's
fast enough, it has enough of the right either libraries or capabilities to solve
my problems and things like that, right, I'm happy to use Ruby.
And the thing that draws me in is the way that the language is put
together. And then if you expand that into things like Rails or a lot
of the other libraries, really what you find is you find that it's those
have adopted the same expressible approach as Ruby. Right. So when I was
learning rails, I learned rails and then I learned Ruby to learn rails,
right, and I learned Ruby through rails. But you know, it was
all very intuitive, and you know, kind of it got out of the
way of me having to really deeply know the technology, and I could really
think about the problem space I was in. And so yeah, to the
extent that, hey, it gets better and better and better and better.
That that's the thing that excites me, right, is that it's already good
enough. But to see some of these advances, that that's exciting. And
yeah, like you said, we've got some early adopters. We've got people
out there, you know, trying out Falcon and acinc and things like that.
And what I found is that these things is they tend to make a
difference for more and more people. Then then the word spreads, and then
what happens is now the state of the art is not Puma, it's or
maybe Puma adopts some of the things from Falcon and it is Puma, but
it's a Puma that's way better, or it's Falcon, or it's Yeah.
I have a close working relationship with Nate and a couple of others and which
are cross cliberate all the time. One. Oh yeah, well I also
because if you do something brilliant, right and I'm using Puma, I still
want it. Yeah, yeah, absolutely, Well you can use acink inside
Perma. It works fine, Yeah, you just if you have So this
is just a fun aside. I suppose Puma is using a thread for each
request. There's no reason why you can't put like a block, an ACNC
block in their thread and then multiplex out multiple work requests. So let's say
you're we're working on a service as to talk to like say, maybe you're
doing like a you know, identity checking system or something you need to talk
to like three different remote systems to validate someone's bank details, address or something
else, and you want to talk do that as quickly as possible, even
inside Perma. Well, I guess you have two options. You can use
ah is it called ethon, There's like a there's something called Hydra. There's
a gem which works on top of lib curl. I think unless you do
like comparency multiple requests simultaneously, or you can just drop in an ACNC block
and just do you is XGP and it will work as well or it's not
probably better and so like you can't embed as and consider perm and derived significant
benefit if you know, if you have explicit ioconcurrency that you want to solve
for. So, yeah, it's pretty neck like it's it's it is very
composable in networkun cool. I'll check that out too, all right, Well,
are there any other things coming in the Ruby or the Ruby community eco
system core length you're jazzed about. Yeah. One of the thingsures I've been
working on in Ruby tangentially is io buffer, which is an alternative to using
strings for network io. Okay, it's currently markets experimental, it's been in
like the last two or three releases of Ruby, and it's used by the
fiber scheduler too. Have an efficient zero copy mechanism for basically saying we have
a string and we want to read into a part of that string, like
someone's trying to read data from the network into the string. We don't want
to like just read data and then copy it in there. And so io
buffer can be a slice of that string and we can efficiently pass that into
the Rubies fiber scheduler and then the five responsible for reading into that piece the
buffer. The surprisingly, I've had bug reports from like lots of people in
a bad way, like people trying to do stuff and finding inconsistencies or all
things together. And I was surprised because I didn't think people would be using
it as much, even as marked as experiments. But this is one of
my goals that things get better, So that's fine, Yeah, exactly right.
One of my goals is to try and tam zero copy networking, and
Ruby Ruby right now does because of the way strings are designed can be each
cases for networking, IO can be quite complex to avoid copying data. Copying
data isn't exactly the worst thing you can do, but CPUs only have a
bandwidth of like between fifteen hundred gigabytes per second of memory bandwidth, and so
like the less of that you consume just copying data because you do it,
the better. And there's another I said earlier. I had mentioned something specifically
about the IO reading. I wrote five schedule looks andy bit, it's a
good opportunity to touch that. So then Ruby, there are operations like reading
and writing from a socket or a file or something, and you want that
to be a concurrent and it turns out that some of those operations are quite
hard to do it concurrently, like reading from a file concurrently, there's no
good API for that and general Unix, if you try to say is the
file readable, it will always say yeah, it's readable, and it's unlike
I, say a network socket, which if the data hasn't come into the
network card, then the socket is not readable. But a file is always
available to read, and so there's no good mechanism for basically detecting their case.
And so you get APIs like what's called AIO, which lets your schedule
operation be say I would like you to read the data from this file and
then tell me when it's done. But these APIs have always been slightly plunky
to use, and often that don't work as effectively as you'd like. So
there's a great new API called iouring and ieuring actually is an asynchronous system called
for Linux. So there's a whole bunch of light system calls that by default
synchronous, like the operating system will take some time to do the operation,
and there was no easy way to do their operation in a non walking fashion.
There was no API. There's no way to say, can you start
doing this? And then tell me when it's done. There was no easy
way to do that at the system call level, and so what the ie
you ring is is it's it's a buffer, a submission buffer and a completion
buffer. And what you do is when you want to do like a system
calls specific system call, you basically write all the details of that system call
into the submission buffer and then the operating system will basically just read along that
submission buffer, taking out the operations and then doing them. And when the
operation is completed, it will put the result of the operation into the completion
buffer. And so you have instead of having synchronous system calls, you now
have asynchronous system calls right And as time goes on, more and more operations
are being added to URINE. So it's really exciting because it allows us to
do things like one of the ones, like a simple example of where there
was no asynchronous version if allocate, which basically allocates a file on disc and
this can take time and it's a blocking operation potentially. So if you want
to create like a thirty gigabyte file on disc, use if allocate to allocate
the spacefully start writing to it, otherwise you might get halfway through and you
can't writing more data out of mimerica or something. Now with I you ring,
you can schedule this operation into the ur ring and then you can wait
for it to complete in the background. And so this is really fantastic for
the fiber scheduler because the fiber scheduler can take more and more operations. And
in this particular case, I read and I writ are examples of those operations
where you can may see, hey, read from this file and when the
operation is complete, tell me that it's done right to the operating system instead
of trying to manage it itself exactly. And so I'm really excited by this
functionality and it works as off to day life. You use the last version
of acink, you get I support and links where it's where it's supported.
And again, like it's it's a complex system. There will be issues to
work out, but we are solving those problems and we're seeing significant advantages in
production with these types of interfaces. So I think, yeahs original question like
what is the future of Ruby, I think there's two pieces. There's the
catcher, which whereas like things like web sockets should have been better at earlier
on and I think basink solves part of those problems, and then there's just
adoption of like user adoption, but then there's also exciting things like have Ruby
actually interfaces with the operating system to do things more efficiently, and the low
level interfaces and hooks and just like design required to do that, and hopefully
like most of that's hidden from the end user, so you just install a
new version of Ruby and things work better. And so for me personally,
that's what I'm focused on and where I think I want to spend more of
my time. Very cool. Well, we're over the forty five minutes that
we have scheduled, and I have a whole bunch here at tew on.
Plus we're also scheduled to do a Ruby Rogues episode coming up soon, so
you know, we can go into more detail there. But this has been
really fascinating. Thanks for coming and talking through this. It's a little bit
different angle on the future Ruby than kind of what I've gotten from other folks,
and so hopefully some people dive in and go, oh, well,
maybe I can help with that, or oh I'd really like to understand that
more if they do want to reach out to you on that stuff. How
do they find you online? The best way to do it is get have
discussions. So I'm good, I'm good. Any of the projects you're interested
in, just find the discussions and if it's not enabled, just pring me
on, bring me on the other discussions. Most of the major projects have
discussions enabled, and it's a great place because there's a bunch of people who
get involved and have experienced using it and can help some questions. Yeah,
okay, sounds good. Well we'll go ahead and wrap up here. Thank
you so much time folks the opportunity to talk as well. Oh thanks for
coming. This is like I said, this has been really really fascinating and
yeah, until next time, folks. Max out