00:00:15.320
welcome we're so excited to have you
00:00:17.920
here with us for this talk let me give
00:00:20.840
this to AB thank you we're so excited to
00:00:23.920
have you here we're really excited about
00:00:25.880
this topic uh thank you to Jenny for the
00:00:28.000
introduction again I'm jamus buck um at
00:00:30.359
mongodb I've been at mongodb for almost
00:00:33.480
two years and I've been working with
00:00:35.040
Ruby professionally for about
00:00:37.360
20 hello I'm Aditi I've been working
00:00:40.280
with Ruby professionally for two months
00:00:42.440
which is not as much as 20 years uh but
00:00:45.960
I learned Ruby this past summer while
00:00:47.680
interning at mongodb while working on
00:00:50.079
this project flattening recushion with
00:00:51.879
fibos and I'm super excited to present
00:00:53.760
this with
00:00:54.640
jamus wonderful thank you thank you
00:01:01.120
so for about the next 20 minutes or so
00:01:04.280
we will be regaling you with a tale in
00:01:07.479
three acts of success and failure hope
00:01:11.880
and despair and ultimate Victory so
00:01:15.360
buckle your seat belts and hang on
00:01:16.960
because it's going to be a little bit of
00:01:18.600
a roller
00:01:19.680
coaster so let's start with our First
00:01:22.400
Act amongst our one index list of Acts
00:01:25.000
act one in which our hero encounters a
00:01:28.000
monster Once Upon a Time there was a
00:01:30.520
village of happy villagers some of the
00:01:33.479
villagers like this one in the middle
00:01:36.119
had four
00:01:37.320
children they wanted to live in an
00:01:39.439
egalitarian society where whenever the
00:01:42.520
children sorry whenever the parents
00:01:44.640
Prosper the children should have the
00:01:46.079
right to prosper as well in order to
00:01:48.360
codify their laws they hire Ruby doobie
00:01:51.799
a friendly neighborhood Ruby
00:01:56.079
developable so Ruby doobie is a bit of a
00:01:59.439
practical pragmatic fellow uh rather
00:02:02.759
than inventing everything from scratch
00:02:04.520
he reached for what was familiar and
00:02:06.560
already present and so he decided to use
00:02:09.599
active model as the basis for his
00:02:12.239
framework uh so this will look very
00:02:14.200
familiar to uh rails
00:02:17.519
programmers uh active model was mature
00:02:20.840
it's familiar and it does almost
00:02:23.480
everything that he needs one of the
00:02:25.519
things it did not do is it doesn't
00:02:28.120
support embedded documents embedded
00:02:31.800
documents are records that are actually
00:02:33.560
physically nested inside of other
00:02:35.360
records has anyone here played with
00:02:37.120
mongodb before raise of hands a few of
00:02:39.920
you that's awesome okay so those of you
00:02:41.599
who raise your hands you might be
00:02:43.040
familiar with embedded documents but
00:02:45.519
that is one of the things that uh Ruby
00:02:47.879
doie needed in his framework and so he
00:02:50.920
he knew he was going to have to
00:02:51.879
implement a little bit extra honestly
00:02:54.680
active model still did almost everything
00:02:56.680
that he needed the biggest special case
00:02:59.040
that he encountered was with callbacks
00:03:01.200
because the callbacks on these embedded
00:03:02.840
records there's there's a thing called
00:03:04.640
cascading callbacks which is a situation
00:03:07.799
where when an operation hits or when an
00:03:11.000
operation happens on the parent you want
00:03:13.799
the uh the callbacks to filter down
00:03:16.959
through to the children as well so in
00:03:18.760
this example when the parent is saved
00:03:21.680
Ruby doobie wants this do something call
00:03:24.040
back to also be invoked on each of the
00:03:26.120
children as
00:03:28.760
well so that's not too bad that wasn't
00:03:31.439
too bad but around callbacks make this a
00:03:33.840
little more complicated because they're
00:03:36.000
recursive in nature right you can't just
00:03:38.000
call them in sequence you have to Nest
00:03:40.040
them together and that gets a little
00:03:41.560
tricky if you're not familiar I suppose
00:03:43.959
most of you probably are but if you're
00:03:45.239
not familiar with around callbacks the
00:03:47.239
idea is that when something happens like
00:03:49.920
a save this around call back is called
00:03:53.280
and begins executing and then that yield
00:03:56.159
in the middle returns control back to
00:03:59.239
the calling operation so that it can
00:04:01.400
finish so for instance saving and when
00:04:04.079
the save is finished it comes back to
00:04:06.159
this method and completes so it's not as
00:04:09.040
straightforward as a simple before and
00:04:11.519
after call
00:04:14.879
back so this is Ruby Do's first attempt
00:04:18.680
right he's gonna we're going to deal
00:04:20.320
with just save for now but given a save
00:04:22.440
operation he's going to call this run
00:04:24.600
embedded callbacks method and it's going
00:04:27.800
to take a block that's going to encap
00:04:29.840
capsulate the the coree functionality of
00:04:32.160
the save in this case that really
00:04:34.400
actually save method is going to save
00:04:36.960
the top level record in this hierarchy
00:04:39.800
of embedded documents so run embedded
00:04:42.680
callbacks itself his first naive attempt
00:04:45.280
it just iterates over all of the
00:04:47.199
children in the list calls run callbacks
00:04:49.840
on each of them and yields to the
00:04:53.120
block except that's that's really not
00:04:55.720
what he wants for two
00:04:57.759
reasons the first reason
00:05:00.199
is that if there are no children nothing
00:05:03.360
happens right if there's no children
00:05:05.400
that block has never yielded to the
00:05:07.400
parent has never persisted chaos Reigns
00:05:10.280
everything falls apart world ends
00:05:12.759
Etc also because this is happening for
00:05:16.400
each child he's now invoking that block
00:05:19.759
if there's if there's 10 children he's
00:05:21.280
invoking that block 10 times there's
00:05:23.800
saving the top level document 10 times
00:05:25.800
and that is definitely not the intent so
00:05:29.479
yes to go back to the drawing board a
00:05:30.840
little bit this is this is what he came
00:05:33.520
up with then this is the recursive
00:05:35.880
implementation anyone that's done much
00:05:38.319
with like lisp or any of those uh
00:05:40.840
functional languages will be familiar
00:05:42.360
with this uh idiom for iterating over a
00:05:45.720
list if the list is empty if there's no
00:05:48.160
children he just immediately yields and
00:05:50.600
returns that ensures that the the meat
00:05:53.440
of the operation is accomplished
00:05:55.199
regardless of how many children there
00:05:56.560
are then he splits the list he takes the
00:06:00.120
head which is the first element of the
00:06:01.680
list and the tail which is the rest and
00:06:03.960
he runs the callbacks on the
00:06:06.080
head within that block that block is the
00:06:09.280
piece that will be invoked between
00:06:11.160
before and after callbacks and in the
00:06:13.280
middle of around
00:06:14.759
callbacks So within that block he's
00:06:17.120
going to check first to see are there
00:06:18.680
any more elements in the list or is the
00:06:20.560
tail empty if the Tail's empty that
00:06:22.639
means the list has finished processing
00:06:24.759
and there's nothing left to do so we
00:06:27.479
yield and that's the end
00:06:30.280
if there's more elements in that list if
00:06:32.560
the tail is not empty we're going to run
00:06:35.400
embedded callbacks again recursively on
00:06:38.199
the tail to ensure that everything gets
00:06:41.080
done so I'm going to pause for just a
00:06:43.160
second make sure that you can convince
00:06:46.280
yourselves that this truly does cover
00:06:48.880
the entire list and that it's recursive
00:06:51.120
does anyone have any questions right now
00:06:54.479
about what we're doing here
00:07:02.520
okay the hardest thing about public
00:07:04.160
speaking when you're asking a question
00:07:06.400
is the
00:07:07.720
waiting I've heard you're supposed to
00:07:09.639
count to seven after you ask a question
00:07:12.000
I tell you that is the longest seven
00:07:13.960
seconds you will ever
00:07:18.360
experience so it works Ruby doie takes a
00:07:22.280
deep breath sigh of relief basks in the
00:07:26.120
glow of the contentment of a job well
00:07:28.240
done watches as the villagers and the
00:07:30.560
children Prosper together life is
00:07:34.680
good inspired by Ruby Do's work one of
00:07:37.759
the villagers decides to adopt 1,000
00:07:40.280
children there's always that one guy I
00:07:43.599
know what you're thinking that's a lot
00:07:45.319
of
00:07:46.400
children surprisingly what happens is
00:07:49.080
that the villagers are encountered by a
00:07:51.280
terrible system stack error that arises
00:07:54.039
from the depths of the call stack
00:07:55.720
threatens the village and makes Ruby
00:07:57.759
doobie sweat and anxiety
00:08:00.840
now I would encourage all of you to take
00:08:02.400
a minute to think about why the system
00:08:04.479
stack error occurs or if you don't want
00:08:07.039
to think about that you can also
00:08:08.759
appreciate the jokes that I came up with
00:08:10.440
on the
00:08:13.599
slide here's the implementation as a
00:08:16.080
refresher and like jamus I'm also going
00:08:18.400
to count seven Mississippi
00:08:33.080
okay um as jamus explained this is a
00:08:36.200
recursive function where run embedded
00:08:38.320
call backs is called for each and every
00:08:39.959
child document when you have a lot of
00:08:42.760
child documents what happens is that the
00:08:44.800
call Stacks add up and lead to the stack
00:08:47.399
space being exhausted even though this
00:08:49.720
is technically not a case of infinite
00:08:53.640
recursion so with the system stack error
00:08:56.760
Beast looming over the village Ruby doie
00:08:59.959
desperately tries to build a wall to
00:09:01.640
keep it out to protect the villagers
00:09:04.360
he's building this wall he's panicking
00:09:06.839
children are screaming villagers are
00:09:08.839
screaming crying running mad running
00:09:11.399
madly around and all that Ruby Dobie can
00:09:14.760
think is how did everything go so
00:09:19.800
wrong we encountered this very situation
00:09:22.959
well minus the screaming villagers in
00:09:25.760
mongoid okay which is our active record
00:09:28.440
for mongodb
00:09:30.480
um with the embedded
00:09:32.279
children one of our users somehow had
00:09:35.560
more than a thousand embedded records
00:09:37.160
and a single record with callbacks with
00:09:40.440
around call actually it wasn't even with
00:09:42.240
around anyway with with callbacks and it
00:09:44.399
caused the stack to explode and so we
00:09:47.760
had to go and investigate that figure
00:09:49.920
out what was going on and ultimately
00:09:52.000
instead of a nice clean
00:09:53.560
solution and we we all know what it's
00:09:55.640
like to be under pressure with other
00:09:57.519
priorities we didn't have the time or
00:10:00.040
the resources available to research this
00:10:01.720
so we had to just backlog it we
00:10:04.200
implemented a flag that basically
00:10:06.440
disabled around callbacks for embedded
00:10:08.480
children not an elegant solution Ruby
00:10:11.320
doobie is obviously not happy with it
00:10:13.360
you can tell by that little Grimace on
00:10:15.680
his face this is not elegant the
00:10:18.000
villagers are safe the children are safe
00:10:21.160
but they've sacrificed some of their
00:10:23.160
freedoms
00:10:24.720
and the parents and the children can no
00:10:27.279
longer be guaranteed to prosper
00:10:32.160
equally the lack of time and resources
00:10:34.600
that jamus mentioned were provided by me
00:10:36.560
and intoo in this past summer dealing
00:10:38.600
with this project um but here's act two
00:10:41.720
in which our hero embarks on the side
00:10:43.639
quest to linearize the problematic
00:10:45.639
recursive callstack which is a really
00:10:47.360
long way of saying recursion doesn't
00:10:49.680
work fix
00:10:52.959
it on a quest to find an alternate
00:10:56.000
implementation Ruby duie encounters a
00:10:58.560
mysterious artifact made of long fibers
00:11:01.560
never forged for this specific battle
00:11:03.639
but carrying great hope with it inspired
00:11:06.399
to learn as much as he could about this
00:11:08.839
mysterious artifact he reads A
00:11:11.160
mysterious scripture accompanying it
00:11:13.320
titled dogs. Ruby
00:11:17.440
high.org while studying the scriptures
00:11:19.800
he learns that fibos are a concurrency
00:11:22.440
primitive where the programmers have
00:11:24.279
control over when a fiber can be paused
00:11:27.399
or resumed the fiber. new method is used
00:11:30.560
to instantiate a fiber with a code block
00:11:33.480
while the fiber. resume method is used
00:11:35.839
to resume the execution of the code
00:11:38.160
block that the fiber was instantiated
00:11:40.279
with in this example we create a fiber
00:11:43.399
instantiated with the code block that
00:11:45.279
prints dare we hope and calling fiber.
00:11:48.480
resume resumes the execution of this
00:11:50.839
code block thus printing dare we hope
00:11:55.000
for a more substantial example here we
00:11:57.440
create a fiber that's instantiated with
00:11:59.440
a code block that prints start calls
00:12:02.519
fiber. yield and prints finish the
00:12:05.320
fiber. yield method can be used to pause
00:12:07.760
the execution of a
00:12:09.519
block while we do some other work and
00:12:11.880
then resume the execution of the block
00:12:13.800
later on kind of like an around filter
00:12:16.680
so in this example the first fiber.
00:12:18.920
resume starts executing the code block
00:12:21.399
that prints start when fiber. yield is
00:12:24.120
encountered control is returned back to
00:12:27.120
the second fiber. resume the that again
00:12:29.600
resumes the execution of the code block
00:12:31.800
printing
00:12:33.720
finish now let's consider let's consider
00:12:36.600
even more involed example over here we
00:12:39.360
have four different functions Fu bar baz
00:12:42.399
and bank here we're creating four levels
00:12:45.079
of nested blocks and what happens is
00:12:47.399
that when fu is invoked it prints enter
00:12:50.000
Fu the yield statement yields to the
00:12:52.680
code block pass into it that calls bar
00:12:55.760
printing enter bar and so on so forth
00:12:58.440
until done is printed after that exit
00:13:02.000
bang Exit B exit bar and exit Fu are
00:13:05.079
printed these nested blocks simulate the
00:13:08.320
nested nature of the recursion that Ruby
00:13:11.000
doie encountered and his main goal was
00:13:13.920
to try and linearize this somehow using
00:13:17.639
fibos so what ruby doie did was that he
00:13:20.800
created a fibber for each and every
00:13:22.760
function and that's what the fibers
00:13:25.160
equals whatever do map function does um
00:13:28.839
it essentially creates a fiber for Fu
00:13:31.000
bar baz and bang where the code block
00:13:33.760
simply invokes the function passing into
00:13:36.440
it a code block that calls fiber. yield
00:13:39.519
so what fibers. each resume does is that
00:13:42.040
it first resumes the fiber for the fu
00:13:44.360
function that invokes Fu printing enter
00:13:47.680
Fu and once Fu yields to the code block
00:13:51.040
fiber. yield is invoked which returns
00:13:53.519
control to the fibers. each line that
00:13:56.240
goes on to do the same thing for bar
00:13:58.839
back and bang thus printing enter Fu
00:14:01.759
enter bar enter baz enter bang then puts
00:14:05.440
done is encountered which prints done
00:14:07.920
fibers are reverse each resume similarly
00:14:10.839
resumes all the fibers but from bang all
00:14:13.560
the way back to Fu thus printing exit
00:14:16.600
bang exit baz exit bar and exit Fu wow
00:14:20.720
that was difficult to say um and as you
00:14:23.639
can see the output on this slide was the
00:14:26.000
same as the output on the previous slide
00:14:28.440
and Ruby we kind of linearized the
00:14:31.399
recursive nature of nessed
00:14:34.480
blocks and the key ingredient was
00:14:36.920
obviously the fiber. yield that was
00:14:38.959
passed into the function that was
00:14:41.199
invoked for each of the four functions
00:14:43.800
um once again I'm going to pause for
00:14:46.680
maybe a minute for any questions you may
00:14:48.800
have um because we know this is a lot to
00:14:51.839
digest I did this over the course of two
00:14:54.160
months we have 20 minutes with you all
00:15:00.560
yes yes question right here hold on one
00:15:02.199
second let's get a mic to
00:15:06.680
you so that this approach linearizes
00:15:11.000
the um it linearizes the recursion but
00:15:14.320
it doesn't fix the problem it doesn't
00:15:16.920
fix the problem it does it not fix the
00:15:18.480
problem yeah because it sounds it
00:15:20.000
doesn't look like this would avoid the
00:15:21.920
stack space error that's the thing is
00:15:25.519
the fibers are no longer created on the
00:15:27.399
stack you're right there's still memory
00:15:29.519
use the use is still the same in fact
00:15:32.800
but now the the it's being put on the
00:15:35.079
Heap as separate fibers as opposed to
00:15:37.639
being pushed onto a single stack okay
00:15:40.079
good point good point that's a great
00:15:42.800
question thank
00:15:44.680
you uh one more question over here oh
00:15:51.959
sorry what about the previous recursion
00:15:54.600
was keeping something on the stack I
00:15:56.079
didn't understand that bit like like you
00:15:58.360
weren't assuming in place right so you
00:16:00.360
must have been keeping something on the
00:16:02.519
stack so you're asking how no go to the
00:16:07.000
the Fubar baz n in the original problem
00:16:10.759
Oh not here in the original one where
00:16:12.880
you were trying to save the children I
00:16:16.120
didn't understand because it it looked
00:16:17.279
to me like you were doing their cursive
00:16:18.480
call at the end and so naively I'm
00:16:19.920
trying to think of like what's being
00:16:21.120
kept on the stack that's
00:16:22.959
not go forward to the solution right
00:16:26.040
there y that one yes yeah yeah yeah
00:16:29.680
okay so yeah the key to the recursion is
00:16:32.360
that call inside the block to run
00:16:34.880
embedded
00:16:36.040
callbacks so it's calling itself and
00:16:38.480
every time it calls itself it pushes a
00:16:40.360
frame onto the stack to to keep track of
00:16:43.639
where it was when it needs to return
00:16:45.040
from that function does that make sense
00:16:47.959
yes okay and so if we have a thousand
00:16:50.519
children it's going to push onto that
00:16:53.040
stack each time we recurse on that okay
00:16:57.079
okay fair enough does that make sense am
00:16:59.160
I misunderstanding the question no you
00:17:00.959
you answered it I have more questions
00:17:02.600
but uh I'll follow up with them later or
00:17:04.160
something okay we'll do more questions
00:17:05.439
at the end of the presentation as well
00:17:07.439
okay great thank
00:17:15.640
you right there okay
00:17:18.280
so things are looking pretty good this
00:17:21.880
this recursive algorithm has been
00:17:24.120
flattened to a linear algorithm we've
00:17:27.880
taken care of the problem with the stack
00:17:29.720
space being exhausted it's all being put
00:17:31.720
on the Heap now so theoretically we can
00:17:35.280
go for as as deeply as we need to
00:17:39.520
without worrying about exhausting the
00:17:40.919
stack because the stack is no longer
00:17:43.200
being consumed for each child things
00:17:45.880
look good
00:17:48.440
unfortunately in was it in in theory
00:17:51.480
there's no difference between theory and
00:17:53.120
practice but in practice there
00:17:55.640
is um so Ruby does is armed with this
00:17:59.000
new weapon he's he's tried it out in a
00:18:02.440
sandbox and it looks really promising
00:18:04.400
but now here he is standing in front of
00:18:06.200
this Beast armed with this new weapon
00:18:09.320
and he's like where do I start what am I
00:18:12.480
supposed to do does does he need to put
00:18:17.000
this in active record the Callback
00:18:19.240
system if so where like I don't know if
00:18:22.159
any of you have actually looked at
00:18:24.159
active support callbacks but there's a
00:18:26.000
lot of code there and it's non-trivial
00:18:28.559
like it does a lot of optimizations
00:18:30.440
there's a lot of different pieces does
00:18:32.120
this need to go in call template method
00:18:34.000
call does this need to go in callbacks
00:18:36.240
run callbacks does it belong in rails at
00:18:39.440
all because again this was intended to
00:18:42.240
fix the problem with um embedded
00:18:45.679
children embedded documents which is not
00:18:47.760
something that active record even
00:18:49.600
supports so if it doesn't belong in
00:18:51.840
rails do we extract this as a plugin but
00:18:55.159
that still leaves us with the same
00:18:56.600
problem right even if it's a plugin we
00:18:58.400
still need to figure out what we patch
00:19:00.520
and where it
00:19:02.080
goes um it's terrible our hero is faced
00:19:06.360
with this new bug bear of complexity
00:19:09.320
that has snatched Victory right at the
00:19:11.880
moment when he felt like it was
00:19:13.960
there and he
00:19:16.080
desaires as someone who loaned Ruby and
00:19:18.480
Ruby own rails for two weeks before
00:19:20.159
diving into this project I can relate
00:19:22.320
with the fact that the hero did despair
00:19:24.080
a
00:19:25.480
lot and that brings us to act three in
00:19:28.159
which the Beast is finally vanquished
00:19:30.760
the hero's Melancholy was bottomless he
00:19:33.440
decides to go on the walk on the other
00:19:35.320
side of the village whose Hill looks
00:19:37.679
exactly like the hill on the first few
00:19:39.880
slides but symmetrically opposite
00:19:41.600
because again I'm in computer science
00:19:43.240
I'm not an
00:19:45.080
artist while going on this walk and
00:19:47.200
touching much needed grass he is struck
00:19:49.320
with the lightning of inspiration and he
00:19:51.840
realizes instead of touching rails why
00:19:54.720
don't we just drop fiber. yield within
00:19:57.200
mongoid itself
00:19:59.280
so this is what ruby duie came up with
00:20:02.000
what he does is that for each child
00:20:03.640
document he creates a fibber it's
00:20:05.799
instantiated with a code block that
00:20:07.880
calls run call backs on that child
00:20:09.880
document passing into it fiber. yield if
00:20:13.440
you make comparisons with the Fubar baz
00:20:15.799
example earlier this is structurally
00:20:18.320
similar to that what the fibers. each
00:20:21.400
resume line does is again it
00:20:23.559
sequentially goes through the fibos of
00:20:25.520
all the children all the child documents
00:20:28.400
and calls run call backs on it so for
00:20:30.960
the first child document the Run call
00:20:33.120
backs would run the before call backs
00:20:35.520
and the first part of the around
00:20:38.080
callbacks do that for all the children
00:20:40.320
in the list then yield to the code block
00:20:43.600
pass into run embedded callbacks and
00:20:46.240
then do the same thing in RoR so it
00:20:49.000
would for the last child execute it the
00:20:52.440
second half of its around call backs and
00:20:54.400
the after call backs all the way up to
00:20:56.480
the first child
00:21:00.840
and
00:21:01.720
miraculously it works what a wild crazy
00:21:05.760
idea something like it's not even
00:21:07.960
intended for this purpose it's a
00:21:09.400
concurrency primitive right and yet here
00:21:12.360
it actually works and our hero takes a
00:21:15.520
deep breath of relief
00:21:18.200
feels miraculously saved go ahead the
00:21:22.279
next one oh I don't know what Happ what
00:21:25.520
did you do
00:21:27.000
okay I got dad
00:21:30.480
thiso and now the villagers can have as
00:21:33.880
many children as they want right a
00:21:35.960
thousand 10,000 the only limit now is
00:21:38.919
the size of their house right or maybe
00:21:41.520
the village or whatever um but Ruby doie
00:21:44.880
gleefully tears down that wall the
00:21:47.360
villagers are now free to run about
00:21:49.799
they've regained all of their freedom
00:21:51.600
parents and children are able to prosper
00:21:54.320
together there's feasting and fireworks
00:21:57.039
there's celebration dance in the streets
00:22:00.279
everything is great and life is good and
00:22:02.760
they live happily ever after until the
00:22:06.039
next Beast eventually rears its ugly
00:22:08.520
head because as we all know there's
00:22:10.480
always another
00:22:12.120
Beast so thank you very
00:22:20.720
much find us off to Bo for free socks
00:22:23.480
and stickers the socks are really nice
00:22:26.320
we're wearing them right now um yeah and
00:22:29.279
we love to answer any questions you may
00:22:31.360
have you can also chat with us
00:22:36.080
thereafter yes yes question over
00:22:42.880
here so at a meta level this is
00:22:46.640
specifically an issue where you have
00:22:50.240
code that you need to call that you
00:22:51.480
don't control that yields in the middle
00:22:53.360
of it and that's the reason why so like
00:22:55.360
for example for like a before callbacks
00:22:57.200
thing this would be a non you could
00:22:59.080
stick lambdas around it and be fine um
00:23:01.760
so this is specifically for you need to
00:23:04.480
pass it a block and fibers allow you to
00:23:06.840
pause at any point in time in the middle
00:23:08.360
of the execution and then resume it
00:23:09.919
later and that's why you're using fibers
00:23:11.760
here right that is correct that was
00:23:13.960
almost not a question but you saved
00:23:15.480
yourself at the very end okay cool I
00:23:18.360
just wanted to make sure that I like
00:23:19.960
understood the the use of this pretty
00:23:23.120
cool use it's pretty Niche but it was
00:23:25.240
exactly what we needed here cool
00:23:31.000
we have two questions oh two questions
00:23:33.960
one and two arm wrestle wow I feel both
00:23:36.000
of those for
00:23:38.480
once I I a quick question was it is it
00:23:42.240
is it something about fibers or is it
00:23:44.919
just that fibers give you that ability
00:23:47.720
to um resume twice and and you know or
00:23:51.440
is it anything specific to fibers
00:23:54.200
honestly in this case it was just that
00:23:56.039
it allowed us to interrupt in the middle
00:23:59.320
and then resume them on our own schedule
00:24:01.960
so yes it it it could have been anything
00:24:04.320
it just happened to be a concurrency
00:24:05.919
primitive that did the job for
00:24:08.440
us yeah and I think like around call
00:24:11.320
callbacks is what makes us more
00:24:13.120
complicated because around callbacks
00:24:15.000
require like your run call backs to
00:24:17.120
yield to the code block pass in um and
00:24:19.640
so on so
00:24:21.000
forth that's a great
00:24:24.799
question the the uh the initial problem
00:24:28.520
statement looked like it could have been
00:24:30.640
solved by iterating over the
00:24:33.960
children um you want back I didn't see
00:24:37.399
in the in that original one code that
00:24:40.480
needed to be executed before and after
00:24:43.320
okay so yeah let's get back to that
00:24:45.720
statement
00:24:46.679
here uh this one this was the this was
00:24:49.520
the his this was Ruby doob's first try
00:24:51.919
iterating over the children right so
00:24:54.080
there were two problems
00:24:56.000
here the next one oh the next one next
00:24:58.600
one okay yes okay so again what's the uh
00:25:04.919
can you restate your question about this
00:25:06.200
one okay oh sorry
00:25:10.440
um this
00:25:12.880
looks it what would happen if you
00:25:15.919
iterated over each of the
00:25:19.840
children running
00:25:22.039
callbacks and then
00:25:24.240
yielding so if we go back to the
00:25:26.559
previous slide
00:25:29.760
oops we're chasing each other here ah
00:25:33.039
okay you go it I'll just do it okay so
00:25:37.240
that's kind of what we're doing
00:25:38.799
here but we can't yield outside of that
00:25:41.600
iteration because run callbacks has a
00:25:44.520
block that yields that's block the
00:25:46.840
constraint is the rails API that we're
00:25:49.240
dealing with here that we don't have a
00:25:50.679
lot of control over because the rails
00:25:52.799
API needs to support around callbacks
00:25:55.919
which are yield based that was the part
00:25:58.559
I was missing thank you that makes sense
00:25:59.799
okay great great uh right behind you
00:26:03.559
Jenny I'm curious about the creative
00:26:06.640
process behind arriving at this solution
00:26:09.840
um because it's so infrequently the case
00:26:12.240
that you know you you take a primitive
00:26:15.799
with a very that's like very
00:26:17.360
purpose-built and using it in different
00:26:19.360
application is like that's often a
00:26:20.919
disaster in this case I would say it's
00:26:23.279
you know completely the right choice so
00:26:25.840
how do you unlock your thinking and
00:26:27.720
reach
00:26:28.760
you know this right solution rarely the
00:26:32.480
case Jam do you want to talk about like
00:26:34.200
the proof of concept and then I can talk
00:26:36.000
about how it fit in perfect that's just
00:26:37.880
what I was thinking too so there were
00:26:39.279
two parts to this before adidi came on
00:26:41.720
for her internship I kind of had the
00:26:44.440
brainstorm that fibers might work and it
00:26:48.880
happened because I've played with fibers
00:26:51.840
I
00:26:52.480
knew conceptually what they were and how
00:26:55.200
they worked and I knew that fiber yield
00:26:57.039
basically let you pause in the middle
00:26:59.880
and so taking that knowledge and after
00:27:03.559
thinking deeply about the problem that
00:27:05.159
we had where I was like we need to
00:27:06.960
somehow linearize linearize this right
00:27:09.799
like remove the recursive aspects so
00:27:12.120
that we don't recurse and overflow the
00:27:15.080
stack and so as I was thinking about it
00:27:17.320
I was like I wish there was some way as
00:27:19.360
we're executing this to stop and save it
00:27:23.360
so that we can then put it aside and
00:27:24.840
then do the same thing for the next one
00:27:26.799
right so you're like going this far
00:27:28.559
putting it aside this far putting it
00:27:30.120
aside and that's where I was like well
00:27:31.840
that's kind of like stopping a block in
00:27:33.440
the middle which isn't that what fibers
00:27:35.520
do and so I wrote a simple proof of
00:27:38.799
concept which is equivalent to Ruby
00:27:41.039
doob's like wielding his weapon in
00:27:44.039
practice uh in theory um and it it
00:27:47.519
seemed to have promise it seemed like it
00:27:49.120
would work but again I didn't I didn't
00:27:51.960
have the time or the space to actually
00:27:54.200
work on it I had to
00:27:55.880
stop and then a video came for her
00:27:58.760
internship and I was like H I know what
00:28:01.799
we can make her
00:28:04.080
do um yeah working on this project was
00:28:06.399
incredibly fun um the way that I
00:28:08.399
approached it was I obviously was
00:28:10.240
exposed to Ruby for the first time so I
00:28:11.919
tried to get on boarded but then I tried
00:28:14.399
to understand how callbacks worked at
00:28:16.799
the level of active support in rails so
00:28:18.799
I went through like the entire file
00:28:20.440
function by function trying to
00:28:22.480
understand like key factors behind the
00:28:24.760
decision- making process behind the
00:28:26.279
design process and I did the same for
00:28:28.159
for mongoid as well and the and the key
00:28:31.480
part they had to figure out was where
00:28:33.120
exactly could fibos play a part it could
00:28:35.600
either play aart at some point within
00:28:37.880
the um within like the call back
00:28:40.399
implementation of Act of support or
00:28:42.320
within mongoid itself uh but jamus and I
00:28:44.640
were pretty confident that it would most
00:28:46.200
probably be in Ruby on Rails so for each
00:28:48.480
and every point I came up with like
00:28:50.039
multiple proofs of proof of Concepts
00:28:51.840
tried to figure it out on pen and paper
00:28:53.399
if it worked and ultimately I went all
00:28:55.480
the way up to mongoid and then realized
00:28:57.880
that solution lay there all along so it
00:29:00.080
was a very iterative process um and
00:29:03.120
another thing that helped me was taking
00:29:05.120
this leap of faith that we do that we
00:29:07.399
take in recursion where you trust that
00:29:09.200
calling the function Returns the right
00:29:10.720
answer I kind of trusted that Ruby on
00:29:13.440
Rails was implemented as efficiently as
00:29:16.000
possible given that the file was like
00:29:18.240
touched around 12 to 13 years ago um and
00:29:22.519
then we just like used whatever they had
00:29:24.919
and made changes on our end which let a
00:29:27.360
solution be right concise and she
00:29:29.720
actually touched grass to make to figure
00:29:31.679
it out so so I'm getting the signal
00:29:33.919
we're done thank you so much if you have
00:29:35.760
more questions please do find us
00:29:37.120
afterward and also please do come find
00:29:38.919
us for some socks and stickers thank you
00:29:40.799
very
00:29:42.360
much thank you