< Return to Video

RailsConf 2014 - Closing Keynote by Aaron Patterson

  • 0:18 - 0:22
    ??: Our final presenter - calling him simply
    a
  • 0:22 - 0:24
    speaker does his pants a disservice -
  • 0:24 - 0:30
    hardly, he hardly needs an introduction.
  • 0:30 - 0:32
    In addition to being a Rails core team member,
  • 0:32 - 0:37
    he's an avid beard grower and meat connoisseur.
  • 0:37 - 0:40
    In addition to 90s fashion hoarder.
  • 0:40 - 0:44
    He, he's here, I actually got the,
  • 0:44 - 0:45
    I actually have the slip of paper.
  • 0:45 - 0:47
    He's here with written permission
  • 0:47 - 0:49
    from Garby Puff. I had to get that,
  • 0:49 - 0:51
    I had to make sure that it was OK.
  • 0:51 - 0:53
    And with that, I'd like to welcome up on
  • 0:53 - 0:58
    stage, Aaron Patterson.
  • 0:58 - 1:05
    AARON PATTERSON: Thank you. Thank you.
  • 1:08 - 1:12
    [laughter - applause]
  • 1:12 - 1:17
    Thank you. Thank you. I am very excited to
  • 1:17 - 1:20
    be here today. May I be the first person
  • 1:20 - 1:24
    to welcome you to RailsConf. If you notice
    any
  • 1:24 - 1:29
    typos in my slides, please let me know. So.
  • 1:29 - 1:33
    Just Tweet it at me.
  • 1:33 - 1:35
    I want to start my talk off with a
  • 1:35 - 1:39
    couple of quotes. The first one is, "My mom
  • 1:39 - 1:44
    has the Ferrari of sewing machines." This
    is from
  • 1:44 - 1:47
    Kate Heddleson. We were talking about her
    awesomely embroidered
  • 1:47 - 1:49
    jacket last night. You should follow her.
  • 1:49 - 1:50
    And the other quote I want to start with
  • 1:50 - 1:55
    is, "Dad Gummit," by Bill Dance. That's actually
    why
  • 1:55 - 1:57
    I have this hat is because I am a
  • 1:57 - 2:02
    fan of his.
  • 2:02 - 2:06
    I love that animated gifs work in keynote
    now.
  • 2:06 - 2:12
    Anyway. So my name is Aaron Patterson. If
    you
  • 2:12 - 2:17
    don't recognize me, this might help. I, that
    is
  • 2:17 - 2:19
    what I look like on the internet. I learned
  • 2:19 - 2:21
    from the sketchnote talk that I should put
    my
  • 2:21 - 2:24
    Twitter handle there. So hopefully you can
    remember it.
  • 2:24 - 2:27
    I have a cat, and that's, that's him. This
  • 2:27 - 2:30
    is him from a different angle.
  • 2:30 - 2:34
    So, if you like this talk, or if you
  • 2:34 - 2:36
    like anything, you should give it Tenderlove's
    seal of
  • 2:36 - 2:46
    approval. So I'm on the Rails, or, Ruby core
  • 2:46 - 2:48
    team, and I'm also on the Rails core team.
  • 2:48 - 2:50
    I think I'm the only one on both teams.
  • 2:50 - 2:51
    That doesn't mean I know what I'm talking
    about.
  • 2:51 - 2:55
    It just means I'm really terrible at saying
    no.
  • 2:55 - 2:57
    So.
  • 2:57 - 3:01
    So, I work for a very tiny start up
  • 3:01 - 3:08
    that's based in Dallas, Texas. AT&T. I actually
    do
  • 3:09 - 3:15
    work for AT&T. So. I have to say, I
  • 3:15 - 3:17
    really have to say thanks to them for employing
  • 3:17 - 3:21
    me to do nothing all day basically. So, I'm
  • 3:21 - 3:23
    an open source developer for AT&T and we're
    gonna
  • 3:23 - 3:26
    talk about stuff that I do. Anyway, my job
  • 3:26 - 3:30
    titles in the past, 2011, my job title was
  • 3:30 - 3:34
    Carey Haines. 2012, Senior Facebook Integration
    Engineer Elect. I
  • 3:34 - 3:38
    lost that election, unfortunately. Then I
    became a Senior
  • 3:38 - 3:41
    Software Architect, so I got like a drafting
    table
  • 3:41 - 3:44
    and all that stuff. It was very cool.
  • 3:44 - 3:46
    This year, this year I'm a Thought Leader,
    In
  • 3:46 - 3:49
    Training. That's. So. I want to get out of
  • 3:49 - 3:52
    development, and I've heard that, like, thinking
    is on
  • 3:52 - 3:55
    the rise, possibly. So, like, somebody needs
    to lead
  • 3:55 - 3:58
    those thoughts, so, I figured, like, that,
    you know,
  • 3:58 - 4:01
    it's a great market for me.
  • 4:01 - 4:02
    So I noticed there were some people around
    here
  • 4:02 - 4:05
    with Google Glass. Like that's, that's pretty
    exciting. I
  • 4:05 - 4:07
    also have a Google Glass. I did not bring
  • 4:07 - 4:12
    it. This is my Google Glass. I saw there
  • 4:12 - 4:14
    was a talk about, like, someone was giving
    a
  • 4:14 - 4:18
    talk about doing twenty-seven thousand hours
    of, or, twenty-seven
  • 4:18 - 4:21
    million hours of pair programming or something,
    and like,
  • 4:21 - 4:23
    ask them anything. I thought that was really
    cool.
  • 4:23 - 4:27
    I also do pair programming. But not for as
  • 4:27 - 4:28
    long. Like, here's, I want to show you a
  • 4:28 - 4:31
    couple action shots of me pair programming.
    I'm pair
  • 4:31 - 4:35
    programming there. This is a very close-up
    pear, pear
  • 4:35 - 4:37
    programming shot. I can't do it for twenty-seven
    thousand
  • 4:37 - 4:43
    hours. My pear goes bad after a couple days.
  • 4:43 - 4:46
    So I don't know how, I don't know how
  • 4:46 - 4:49
    he did it. Anyway, this is, like, the USB
  • 4:49 - 4:51
    interface on this is terrible. I couldn't,
    it was
  • 4:51 - 4:54
    very hard to figure out.
  • 4:54 - 4:57
    Anyway, I have two cats. This is my lesser
  • 4:57 - 5:03
    famous, my not-as-famous cat. Her name isSeaTac
    Youtube FaceBook
  • 5:03 - 5:07
    Instagram. But we call her TooToo for short.
    And
  • 5:07 - 5:10
    then this is Gorbachev Puff Puff Thunderhorse
    the Third,
  • 5:10 - 5:12
    and you can follow him on Twitter at gorbypuff.
  • 5:12 - 5:16
    That is his Twitter name, for those of you
  • 5:16 - 5:18
    sketchnoting.
  • 5:18 - 5:22
    This is me with my cat. I love them.
  • 5:22 - 5:29
    So. It's a Christmas card in the works, right
  • 5:31 - 5:36
    here. So. I, like I said, on the internet,
  • 5:36 - 5:39
    I am @tenderlove. I write a lot of puns
  • 5:39 - 5:42
    on my Twitter and I also give people hugs
  • 5:42 - 5:45
    and stuff, cause I hug, I work from home
  • 5:45 - 5:47
    and I get kind of lonely working from home,
  • 5:47 - 5:50
    so I hug the internet on the weekends. That's
  • 5:50 - 5:52
    why we did that thing, although I'm extremely
    shy
  • 5:52 - 5:55
    so I would not make you all do that.
  • 5:55 - 5:56
    So, let me give you, I want to give
  • 5:56 - 5:58
    you a breakdown of my Tweets. These are my
  • 5:58 - 6:03
    Tweets. It's 90% puns, hugs, cat photos, and
    sometimes
  • 6:03 - 6:07
    tech stuff. I also brought a bunch of stickers
  • 6:07 - 6:08
    with me that look like this. This is my,
  • 6:08 - 6:11
    this is stickers of my cat. And the thing
  • 6:11 - 6:15
    is, like, so, it, it has come to my
  • 6:15 - 6:19
    attention that people might know who I am.
    And,
  • 6:19 - 6:21
    and this concerns me very greatly, because
    I am
  • 6:21 - 6:25
    very introverted. So I'm really, really shy,
    and I'm,
  • 6:25 - 6:27
    like, I'm, you know, you might be saying to
  • 6:27 - 6:29
    yourself, you're talking in front of many,
    many people.
  • 6:29 - 6:31
    How is it possible that you're doing that,
    and
  • 6:31 - 6:33
    really shy? Well, the thing is, I'm actually
    incredibly
  • 6:33 - 6:37
    scared and I'm using that fear to, to say
  • 6:37 - 6:39
    stuff in front of you. Also I'm wearing a
  • 6:39 - 6:42
    ridiculous outfit, so if I mess up, it's like,
  • 6:42 - 6:45
    ah, look at these! Distraction!
  • 6:45 - 6:50
    Anyway. So, people have said to me, like,
    people
  • 6:50 - 6:52
    have said to me, like, Aaron, you're very
    famous
  • 6:52 - 6:54
    and I'm afraid to talk to you and I
  • 6:54 - 6:56
    want you to know that, this is why I
  • 6:56 - 6:58
    carry around a whole bunch of stickers with
    me,
  • 6:58 - 7:00
    is because, I am also afraid to talk to
  • 7:00 - 7:03
    you. I don't know what to say. So, if
  • 7:03 - 7:04
    you want to come talk to me, this is
  • 7:04 - 7:06
    like, a totally easy thing to do is just
  • 7:06 - 7:08
    say, hey, Aaron. I heard you have stickers.
    Can
  • 7:08 - 7:10
    I have one? And I will say, yes, I
  • 7:10 - 7:12
    do. I love my cat. Here is a sticker
  • 7:12 - 7:15
    of my cat. So please, you know, don't, don't
  • 7:15 - 7:18
    be afraid to approach me.
  • 7:18 - 7:21
    Now let's talk about some Chicago stuff. We're
    in
  • 7:21 - 7:24
    Chicago. I, I noticed, like, so people have
    told
  • 7:24 - 7:26
    me, you need to connect with your audience.
    Like,
  • 7:26 - 7:28
    it's important to connect with the audience.
    And I
  • 7:28 - 7:30
    didn't, I noticed that nobody really did this
    so
  • 7:30 - 7:32
    much in their presentations, but I'm gonna
    do it
  • 7:32 - 7:34
    now. I'm just gonna say a bunch of Chicago
  • 7:34 - 7:38
    stuff to, like, connect with all of you. Like,
  • 7:38 - 7:42
    the Bears. Da Bulls. Mike Ditka.
  • 7:42 - 7:44
    So now we're all, now we're all connected
    on
  • 7:44 - 7:50
    Chicago, right? OK. Perfect. So, last year,
    I want
  • 7:50 - 7:51
    to talk a little bit about what I did
  • 7:51 - 7:53
    in my keynote last year and then we're gonna
  • 7:53 - 7:58
    go into this year. Last year, I introduced
    my
  • 7:58 - 8:05
    consulting company. Here it is. Drr drrr drrrr,
    drrr
  • 8:05 - 8:09
    drrrrr. Bum bum bum.
  • 8:09 - 8:13
    So, there. This is my consulting company,
    Adequate. Adequate
  • 8:13 - 8:17
    Industries. I, you know, I did the same joke
  • 8:17 - 8:19
    last year, but I figured this would be good
  • 8:19 - 8:26
    enough. Like. It should work.
  • 8:27 - 8:30
    Figured that would be adequate.
  • 8:30 - 8:34
    Anyway, I also dropped a lot of F-bombs. It
  • 8:34 - 8:37
    was pretty sweet.
  • 8:37 - 8:41
    I also got into a really awkward situation.
    So,
  • 8:41 - 8:44
    before my keynote last year, like, I always,
    before
  • 8:44 - 8:47
    I give a talk, I always do one thing.
  • 8:47 - 8:50
    This one weird trick that I do. Which is,
  • 8:50 - 8:52
    I go to the bathroom before I give a
  • 8:52 - 8:56
    talk. And unfortunately I was very, very nervous,
    and
  • 8:56 - 8:59
    I went into the women's bathroom. But there
    was
  • 8:59 - 9:01
    nobody in there so I didn't know. I was
  • 9:01 - 9:03
    like, wow, there's a lot of stalls in here.
  • 9:03 - 9:06
    That's OK, I need to use a stall anyway.
  • 9:06 - 9:08
    All right!
  • 9:08 - 9:11
    Use the stall, come out, and then I'm like,
  • 9:11 - 9:14
    OK, there is a, there is a women janitor.
  • 9:14 - 9:17
    I'm OK with that. I am, you know, I'm
  • 9:17 - 9:19
    a progressive person. It's fine. I don't mind
    if
  • 9:19 - 9:21
    there's a woman in the bathroom. And then
    I
  • 9:21 - 9:24
    see that there's another woman washing her
    hands, and
  • 9:24 - 9:26
    then I'm like. Oh shit.
  • 9:26 - 9:32
    And the janitor's like get out of here, and
  • 9:32 - 9:34
    I'm like, ahh! And, of course, the only thing
  • 9:34 - 9:37
    running through my head is like, do I wash
  • 9:37 - 9:42
    my hands? Do I wash my hands? Like.
  • 9:42 - 9:44
    Anyway, last time, so last time I was in
  • 9:44 - 9:46
    Chicago was about ten years ago. This was
    before
  • 9:46 - 9:49
    I had an iPhone or anything. And this, so
  • 9:49 - 9:53
    this story is rated PG-13. So, like, I know
  • 9:53 - 9:54
    we're not, we're not in Prime Time yet, it's
  • 9:54 - 9:59
    only like, 4:30, so hopefully you'll forgive
    me.
  • 9:59 - 10:02
    Last time I was here, I accidentally went
    to,
  • 10:02 - 10:05
    well, not accidentally. I guess it was accidentally.
    I
  • 10:05 - 10:08
    ended up at a party at Cynthia Plaster Caster's
  • 10:08 - 10:13
    house. OK, I see, not, none of you know
  • 10:13 - 10:15
    who this is. If you Google her, like, only
  • 10:15 - 10:19
    click on the Wikipedia link. Please. Like.
    That's the
  • 10:19 - 10:20
    only one you want to click on.
  • 10:20 - 10:22
    So my friends, I, I was staying with some
  • 10:22 - 10:24
    friends, and they're like, hey Aaron, let's,
    we're gonna
  • 10:24 - 10:26
    go, let's go to a party. We're gonna go
  • 10:26 - 10:28
    to a party at Cynthia Plaster Caster's house,
    and
  • 10:28 - 10:31
    I was like, that sounds great. I'm, I'm hip.
  • 10:31 - 10:34
    I know artists. People who like to do things
  • 10:34 - 10:36
    with plaster. That's cool.
  • 10:36 - 10:38
    So, I didn't. Like, I didn't want to seem
  • 10:38 - 10:42
    uncool, so I didn't ask who this person was.
  • 10:42 - 10:44
    And we went to, we went to this party.
  • 10:44 - 10:46
    Went to the party. And it turns out that
  • 10:46 - 10:50
    Cynthia Plaster Caster is famous for, in the
    70s
  • 10:50 - 10:54
    and 80s, making plaster casts of rock stars'
    penises.
  • 10:54 - 10:57
    And I did not know this in advanced.
  • 10:57 - 10:59
    So we go to this, we go to this
  • 10:59 - 11:02
    party, and at the time, a, a, an adult
  • 11:02 - 11:05
    video had just come out with Jimmy Hendricks
    in
  • 11:05 - 11:07
    it, but, allegedly Jimmy Hendricks. And they
    weren't sure
  • 11:07 - 11:10
    whether or not it was him. So she was
  • 11:10 - 11:12
    called in as an expert witness.
  • 11:12 - 11:15
    And, so she's there, and they had just come
  • 11:15 - 11:17
    out with the DVD, with her being the expert
  • 11:17 - 11:19
    witness, you know, and she, like, puts in
    the
  • 11:19 - 11:23
    DVD, and we're like, watching it. And I'm
    like,
  • 11:23 - 11:26
    what is going on? She's on the DVD, she's
  • 11:26 - 11:30
    like, yes, you see here and here. That's,
    that's
  • 11:30 - 11:32
    him. That's definitely him. And I lean over
    to
  • 11:32 - 11:35
    my friend and I'm like, who is this person?
  • 11:35 - 11:37
    Why are we here?
  • 11:37 - 11:38
    And so then she explains it to me and
  • 11:38 - 11:42
    I'm like, oh, I see. So it was incredibly
  • 11:42 - 11:46
    awkward and, like, the most, the most interesting
    part
  • 11:46 - 11:47
    of it to me was that there was a
  • 11:47 - 11:49
    guy there dressed in a hot dog costume, which
  • 11:49 - 11:52
    seemed most appropriate for the place where
    we were.
  • 11:52 - 11:55
    Anyway, so that was my last, my last encounter
  • 11:55 - 11:58
    in, in Chicago. And the moral of the story
  • 11:58 - 12:01
    is, like, if you don't know something, you
    shouldn't
  • 12:01 - 12:04
    be embarrassed to ask about it, because down
    the
  • 12:04 - 12:09
    line it could be potentially even more embarrassing.
    Anyway.
  • 12:09 - 12:13
    So, Rails is ten years old. And that's really
  • 12:13 - 12:15
    exciting. I was thinking about, like, OK,
    so Rails
  • 12:15 - 12:17
    is ten years old. What did I look like
  • 12:17 - 12:20
    when I was ten years old? And so I
  • 12:20 - 12:21
    decided to dress like that today. And that
    is
  • 12:21 - 12:25
    why, that is why I am dressed like this.
  • 12:25 - 12:27
    So, this is what, about what I looked like
  • 12:27 - 12:29
    when I was ten years old. Maybe twelve or
  • 12:29 - 12:31
    so. I'm not sure. Like, around in that ballpark.
  • 12:31 - 12:33
    And I know you, you probably can't see the
  • 12:33 - 12:35
    back of my t-shirt. I'll turn around here.
    It's
  • 12:35 - 12:37
    probably hard to read. But what it says is
  • 12:37 - 12:41
    this. It looks like this. It says, it says,
  • 12:41 - 12:43
    if you can't surf with the big dogs, stay
  • 12:43 - 12:48
    off the net.
  • 12:48 - 12:50
    And I love it. It's like, that's a dog
  • 12:50 - 12:53
    zooming, surfing by. It's like the literally
    interpretation of
  • 12:53 - 12:56
    the internet. And you know in the early 90s,
  • 12:56 - 12:58
    like, this is how most people thought the
    internet
  • 12:58 - 13:01
    worked. It was like these, these things going
    around
  • 13:01 - 13:03
    the globe with like, bubbles and stuff and
    there's
  • 13:03 - 13:07
    a dog flying by. And I'm just thinking to
  • 13:07 - 13:10
    myself, like, yeah, there's some guy sitting
    there clicking
  • 13:10 - 13:14
    his mouse, like, yeah. If you can't surf with
  • 13:14 - 13:18
    the big dogs you gotta get off the net.
  • 13:18 - 13:19
    Just kills me.
  • 13:19 - 13:21
    Anyway, so I think we, I think we've made
  • 13:21 - 13:23
    a lot of progress since then, because basically
    what
  • 13:23 - 13:26
    dogs look like on the internet now is this.
  • 13:26 - 13:29
    Like. I mean, this is surfing with the big
  • 13:29 - 13:31
    dogs right here.
  • 13:31 - 13:37
    Anyway. So ten years ago, ten years ago, like,
  • 13:37 - 13:41
    Rails, the Rails community started solving
    incredibly hard computer
  • 13:41 - 13:44
    science problems. So, ten years ago, we were
    able
  • 13:44 - 13:48
    to solve the problem of naming. Check. It's
    solved.
  • 13:48 - 13:52
    Say Rails generate new model or whatever.
    And we
  • 13:52 - 13:56
    got the names down. You use plural. Super
    exciting.
  • 13:56 - 13:59
    Last year, last year during DHH's keynote,
    it was
  • 13:59 - 14:03
    very exciting. Incredibly exciting. We solved
    caching. Boom. Russian
  • 14:03 - 14:06
    doll caching. Throw it in there. Don't worry
    about
  • 14:06 - 14:07
    it at all.
  • 14:07 - 14:10
    Also, in the last, in the previous year, like,
  • 14:10 - 14:14
    another insanely hard computer science problem
    solved was dependencies.
  • 14:14 - 14:16
    We solved that. In fact, I have a quote
  • 14:16 - 14:17
    about it here.
  • 14:17 - 14:20
    "The genius behind MPM is that it solves dependencies,
  • 14:20 - 14:23
    a long-time problem in computer science."
  • 14:23 - 14:25
    Boom. Solved.
  • 14:25 - 14:29
    Unfortunately, that was with MPM, so I just
    have
  • 14:29 - 14:31
    one thing to say. It's like, get your act
  • 14:31 - 14:33
    together, RubyGems. What is the deal? Why
    have we
  • 14:33 - 14:36
    not solved dependencies yet?
  • 14:36 - 14:38
    So this got me thinking, like, what's left
    in
  • 14:38 - 14:42
    computer science, right? I mean, we're doing,
    we're doing,
  • 14:42 - 14:45
    like, ground-breaking work here on the Rails
    core team.
  • 14:45 - 14:47
    It's, it's amazing. There's one thing left.
  • 14:47 - 14:50
    P equals NP. And you know what? I'm gonna
  • 14:50 - 14:53
    solve this one for you, on stage, tonight.
    I
  • 14:53 - 14:55
    don't even know why, I don't even know why
  • 14:55 - 14:56
    this is so hard.
  • 14:56 - 14:57
    You just divide both sides by P.
  • 14:57 - 15:04
    Done. We're done. Yeah!
  • 15:10 - 15:11
    I think we're done here. We can all go
  • 15:11 - 15:13
    home now.
  • 15:13 - 15:16
    Anyway, so this is my, this is my anti-keynote.
  • 15:16 - 15:20
    DHH opened. He gave the keynote. I am closing.
  • 15:20 - 15:22
    I will give the anti-keynote. Tonight we are
    going
  • 15:22 - 15:28
    to talk about coverage, speed, metrics, and
    hard effing
  • 15:28 - 15:31
    science.
  • 15:31 - 15:37
    So. So things I've learned at RailsConf. Yehuda
    taught
  • 15:37 - 15:39
    me that it is nearly five PM on a
  • 15:39 - 15:42
    Friday at the end of a very long conference,
  • 15:42 - 15:45
    so your batteries are, your cognitive batteries
    are probably
  • 15:45 - 15:52
    very low, which means that I am your default.
  • 15:52 - 15:54
    It means that you need to listen to me.
  • 15:54 - 16:01
    Science is good. TDD is great. Baratunde taught
    me
  • 16:08 - 16:13
    that I am white. I did not. Didn't realize
  • 16:13 - 16:17
    that until the other day.
  • 16:17 - 16:19
    Farrah taught me that I need to code hard
  • 16:19 - 16:23
    and code fast, so tonight I'm gonna troll
    fast
  • 16:23 - 16:25
    and troll furious.
  • 16:25 - 16:32
    So, DHH. DHH's presentation gave me a really
    awesome
  • 16:34 - 16:38
    workout for my eye muscles. You can see from
  • 16:38 - 16:40
    this diagram right here, this is the eye roll
  • 16:40 - 16:47
    muscle. I'm not. Had a lot of exercise back
  • 16:49 - 16:49
    there.
  • 16:49 - 16:51
    Super strong.
  • 16:51 - 16:56
    So, I'm like, OK, ah, man, we got this
  • 16:56 - 16:58
    person with a birth year on it. How do
  • 16:58 - 17:00
    we test this? Well, obviously we have to pass
  • 17:00 - 17:04
    in today. We modify the, we modify our API,
  • 17:04 - 17:06
    pass in today. And then we can test it,
  • 17:06 - 17:08
    and I just have to say one thing. Stop!
  • 17:08 - 17:11
    This is, this is not how you test it.
  • 17:11 - 17:14
    This is not dependency injection. I, like.
    So, let
  • 17:14 - 17:16
    me, let me show you the way I would
  • 17:16 - 17:17
    test this. The way I would test this is
  • 17:17 - 17:21
    I would use the API that we already have.
  • 17:21 - 17:23
    Your person has a constructor. You can give
    it
  • 17:23 - 17:25
    a birth year. So pass in the current year
  • 17:25 - 17:27
    and then test whether or not the current,
    birth
  • 17:27 - 17:29
    year is equal to that, and whether or not,
  • 17:29 - 17:31
    you know, then refute it as well.
  • 17:31 - 17:33
    What's really cool about this, what I think
    is
  • 17:33 - 17:36
    really, really awesome, is that there's now
    new API
  • 17:36 - 17:42
    necessary. Wow. Amazing. Constructors are
    pretty cool, I think.
  • 17:42 - 17:44
    I like constructors a lot. But the lesson
    from
  • 17:44 - 17:47
    this is that you need to make construction
    easy.
  • 17:47 - 17:49
    If you make construction of your objects easy
    than
  • 17:49 - 17:51
    they should be easier to test.
  • 17:51 - 17:54
    So, OK, we did, there was some trolling. I
  • 17:54 - 17:55
    want to start out, I want to start out
  • 17:55 - 17:59
    with my controversial opinions. These are
    my only, well
  • 17:59 - 18:01
    no. I'm gonna give you some controversial
    opinions now,
  • 18:01 - 18:03
    and then some at the end of the talk.
  • 18:03 - 18:05
    So I'm gonna start out with controversial
    opinions.
  • 18:05 - 18:09
    I am a software engineer. I am not a
  • 18:09 - 18:14
    software writer. I am sorry. I imagine, when
    I
  • 18:14 - 18:17
    hear, when I hear software writer, I imagine
    somebody
  • 18:17 - 18:21
    sitting in their villa in France at a winery.
  • 18:21 - 18:25
    Oh, look at how that brace lines up with
  • 18:25 - 18:29
    this other brace. It's beautiful.
  • 18:29 - 18:33
    So amazing. Look at how those methods are
    indented
  • 18:33 - 18:40
    just one underneath private. Oh, it's so readable.
    What
  • 18:42 - 18:44
    kills me about this is that beauty is in
  • 18:44 - 18:47
    the eye of the beholder. Like, if you, for
  • 18:47 - 18:50
    example, look at this ridiculous outfit I'm
    wearing. In
  • 18:50 - 18:57
    the 90s, this would have been acceptable.
  • 18:57 - 19:00
    Science is important. I can't believe I had
    to
  • 19:00 - 19:06
    say this. So, you may not have to be
  • 19:06 - 19:09
    a computer science, scientist to be a web
    developer,
  • 19:09 - 19:12
    but having some sort of scientific background
    might be
  • 19:12 - 19:17
    important for things like making money. Like,
    I mean,
  • 19:17 - 19:20
    sure any of us can sling out some html,
  • 19:20 - 19:21
    but can you make money with that? You need
  • 19:21 - 19:24
    to be able to measure things. Like, for example,
  • 19:24 - 19:29
    A/B testing. There is math. Money. More math.
  • 19:29 - 19:33
    I, it just. Anyway, yes. Science is important.
    To
  • 19:33 - 19:35
    me.
  • 19:35 - 19:37
    So I want to talk about mutable state. I
  • 19:37 - 19:38
    think I said in the title I was gonna
  • 19:38 - 19:40
    talk about mutable states, so I'm gonna do
    that.
  • 19:40 - 19:41
    I promised I would.
  • 19:41 - 19:45
    A. Matz sort of said in his talk, Rails
  • 19:45 - 19:48
    has many bugs. So we're gonna look at some,
  • 19:48 - 19:49
    we're gonna look at some bugs. These are my
  • 19:49 - 19:54
    favorite bugs recently. And I've actually,
    I've found two
  • 19:54 - 19:56
    of the three bugs we're gonna look at. And
  • 19:56 - 19:59
    all of these, all of these bugs have to
  • 19:59 - 20:01
    do with mutable state in one way or another,
  • 20:01 - 20:03
    and we're gonna see how.
  • 20:03 - 20:07
    The first one is inconsistent return values.
    Typically, I
  • 20:07 - 20:10
    assume that if I call a particular function
    twice,
  • 20:10 - 20:12
    it will return the same thing. I know this
  • 20:12 - 20:16
    is probably silly in Rails. SO I think that
  • 20:16 - 20:19
    those two, those two methods should return
    the same
  • 20:19 - 20:20
    thing. If you call that once, and this literally
  • 20:20 - 20:22
    happens today in your Rails code. If you do
  • 20:22 - 20:24
    these two particular lines of code, the first
    time
  • 20:24 - 20:26
    it'll return false and the second time it'll
    return
  • 20:26 - 20:26
    true.
  • 20:26 - 20:28
    And when I look at this, I, I feel
  • 20:28 - 20:31
    like this. I feel like I'm Bill Dance with
  • 20:31 - 20:38
    a dog going. Let me just watch that gif.
  • 20:41 - 20:42
    I love the dive.
  • 20:42 - 20:46
    Anyway. This, there's another problem with
    this too. It
  • 20:46 - 20:47
    also has a memory leak in it. Look at
  • 20:47 - 20:49
    that. So we actually, these are action control
    parameters.
  • 20:49 - 20:52
    This is the params thing that's in your controller.
  • 20:52 - 20:53
    That hash that you deal with in the controller.
  • 20:53 - 20:55
    There is a memory leak and if you do
  • 20:55 - 20:57
    this, if you do this particular code. Like,
    if
  • 20:57 - 20:59
    you write this, if you fetch a value and
  • 20:59 - 21:01
    then delete it and then assign a new one,
  • 21:01 - 21:04
    you'll get a memory leak and it'll look like
  • 21:04 - 21:04
    that.
  • 21:04 - 21:07
    So if you run that program, it'll just go
  • 21:07 - 21:11
    infinitely. And the reason is because we're
    doing a
  • 21:11 - 21:14
    conversion on the stuff that we pull out when
  • 21:14 - 21:17
    you do fetch. And that conversion gets shoved
    into
  • 21:17 - 21:21
    an array. And unfortunately, this parameter's
    hash, it allows
  • 21:21 - 21:24
    you to delete things from it. But when you
  • 21:24 - 21:27
    delete stuff from it, this internal array
    thing is
  • 21:27 - 21:30
    not updated. So it deletes from the hash but
  • 21:30 - 21:33
    doesn't delete from this other converted array
    value. And
  • 21:33 - 21:37
    this is something that was missed because
    the parameters
  • 21:37 - 21:42
    hash inherits from a hash with a different
    access,
  • 21:42 - 21:44
    and hash with a different access inherits
    from hash,
  • 21:44 - 21:47
    and hash implements a whole bunch of methods
    that
  • 21:47 - 21:49
    maybe you didn't think about.
  • 21:49 - 21:52
    For example, delete.
  • 21:52 - 21:56
    So, when you, when you inherit from something
    like
  • 21:56 - 21:58
    hash, you have to think about all these different
  • 21:58 - 22:01
    ways can, can interface with your code. And
    it's
  • 22:01 - 22:03
    similar to this. You're like, ah, oh, they,
    they
  • 22:03 - 22:06
    might call delete. They might update. They
    might replace.
  • 22:06 - 22:08
    What do we do about that?
  • 22:08 - 22:11
    So, this is one thing that is, I do
  • 22:11 - 22:13
    not like. It is not very fun, and I
  • 22:13 - 22:15
    mean, you can tell this is not done with
  • 22:15 - 22:19
    TDD, possibly. I'm just kidding. I'm just
    kidding. It
  • 22:19 - 22:20
    probably totally was.
  • 22:20 - 22:23
    So, another, another example here is an inconsistent
    return
  • 22:23 - 22:26
    value. So the first time we call size on
  • 22:26 - 22:28
    this one, on this relation, it'll return a
    hash.
  • 22:28 - 22:30
    And the second time, if you call to_a on
  • 22:30 - 22:33
    it, the second time it'll return a one. So
  • 22:33 - 22:35
    I, I would expect that both of these return
  • 22:35 - 22:38
    a hash or return a one. But they don't.
  • 22:38 - 22:42
    And the cause if because we have a mutated
  • 22:42 - 22:44
    state inside of the relation object, which
    is, if,
  • 22:44 - 22:46
    when we load the records from the database,
    we
  • 22:46 - 22:48
    shove that into an instance variable so that
    if
  • 22:48 - 22:50
    you try to reload them again, we don't actually
  • 22:50 - 22:51
    go hit the database.
  • 22:51 - 22:54
    So, if it's loaded, then we'll return the
    length
  • 22:54 - 22:57
    of the records that are in there, and if
  • 22:57 - 22:59
    it's not loaded then we'll actually do an,
    we'll
  • 22:59 - 23:03
    do a count on that. I'm not totally sure
  • 23:03 - 23:05
    how to fix that. These first two problems,
    I'm
  • 23:05 - 23:07
    not sure how to fix. I feel like, like
  • 23:07 - 23:07
    this one.
  • 23:07 - 23:10
    Another Bill Dance. Ah! I should probably
    tell you,
  • 23:10 - 23:15
    whenever we find issues like this, or mistakes,
    we
  • 23:15 - 23:16
    take one of these gifs and put them into
  • 23:16 - 23:19
    camp fire, which is why I own this hat.
  • 23:19 - 23:21
    I feel like I am screwing up all the
  • 23:21 - 23:25
    time, because it's probably my fault.
  • 23:25 - 23:26
    The next one we're gonna look at I like
  • 23:26 - 23:29
    to call wtf SQL. This one is courtesy of
  • 23:29 - 23:34
    @ilenecodes. She did not call it wtf SQL.
    That's
  • 23:34 - 23:36
    my name.
  • 23:36 - 23:38
    You can see her speak at Ruby Nation and
  • 23:38 - 23:40
    I highly encourage you to do so. Actually
    I
  • 23:40 - 23:43
    saw her present this, I saw her present this
  • 23:43 - 23:45
    bug at Mountain West Ruby Conference. She
    was giving
  • 23:45 - 23:48
    a talk on ActiveRecord stuff, like internals,
    and she's
  • 23:48 - 23:49
    going through all this stuff and she's like,
    if
  • 23:49 - 23:53
    you call it in this certain way, then it's
  • 23:53 - 23:57
    incredibly inefficient. Like, it does this
    weird stuff and
  • 23:57 - 24:00
    it's incredibly inefficient, and of course
    during Q&A I
  • 24:00 - 24:06
    was like, why don't they fix that?
  • 24:06 - 24:10
    And then I was like, oh, they is me.
  • 24:10 - 24:12
    OK. Anyway. So let's look at, let's look at
  • 24:12 - 24:14
    the bugs. So, we have a, we have a
  • 24:14 - 24:17
    object here. Like, this is just using pictures.
    We
  • 24:17 - 24:20
    have an author. The author is David. We create
  • 24:20 - 24:22
    a whole bunch of posts for it and then
  • 24:22 - 24:24
    call delete all. If we think about what the
  • 24:24 - 24:26
    SQL is for that, we would expect that it's,
  • 24:26 - 24:30
    like, OK, delete all from posts where the
    id
  • 24:30 - 24:32
    is whatever, and if you execute this, yes.
    That's
  • 24:32 - 24:33
    what happen.
  • 24:33 - 24:36
    Delete all from posts where author id equals
    one.
  • 24:36 - 24:39
    OK. Now, let's say you're messing around with
    this
  • 24:39 - 24:43
    thing in IRB. You say, OK, David dot posts,
  • 24:43 - 24:45
    and you inspect the return value of it. So
  • 24:45 - 24:50
    this, this test is simulating that. We're
    calling inspect
  • 24:50 - 24:52
    on that, because that's what IRB does to any
  • 24:52 - 24:54
    return value. It calls inspect and then shows
    you
  • 24:54 - 24:56
    the text below it.
  • 24:56 - 24:57
    So what do you think the SQL would be
  • 24:57 - 24:59
    for this?
  • 24:59 - 25:01
    If you thought it was the previous one, you
  • 25:01 - 25:03
    are wrong. Otherwise I wouldn't be showing
    this to
  • 25:03 - 25:06
    you. This, this is what the SQL looks like.
  • 25:06 - 25:13
    A giant IN statement. So yes. This is definitely
  • 25:13 - 25:16
    inefficient compared to the other one. Anyway,
    the cause
  • 25:16 - 25:18
    of this is exactly the same as the cause
  • 25:18 - 25:20
    of the previous one. We had state saved. We
  • 25:20 - 25:23
    said, OK, if this is loaded then we do
  • 25:23 - 25:26
    a different thing versus if it's not loaded.
    So
  • 25:26 - 25:27
    we're like, OK, if it's loaded then we're
    gonna
  • 25:27 - 25:29
    do a delete with an IN, otherwise we're just
  • 25:29 - 25:32
    gonna delete all the records, when actually
    we just
  • 25:32 - 25:34
    wanted to do a delete without the IN.
  • 25:34 - 25:37
    So, this is my, my next Bill Dance gif
  • 25:37 - 25:44
    that. Ah, I love this one. So the lesson
  • 25:50 - 25:52
    that I hope you all to take from this
  • 25:52 - 25:57
    is avoid subclassing built-in classes. They
    probably implement stuff
  • 25:57 - 26:00
    that you're not expecting. They're probably
    implementing an API
  • 26:00 - 26:03
    that you may not need or may not want.
  • 26:03 - 26:05
    You should be conservative about the API that
    you
  • 26:05 - 26:09
    implement. It's much easier to add a method
    than
  • 26:09 - 26:10
    it is to take one away.
  • 26:10 - 26:12
    If you take one away, you need to deprecate
  • 26:12 - 26:13
    it, and there's a lot more work. It's a
  • 26:13 - 26:17
    lot easier to introduce something new. The
    other thing
  • 26:17 - 26:20
    is that you should be extremely careful with
    mutations.
  • 26:20 - 26:22
    I'm not saying, like, don't mutate stuff,
    I'm just
  • 26:22 - 26:25
    saying be very careful about it. If you keep
  • 26:25 - 26:28
    a small API, then it's much easier to be
  • 26:28 - 26:30
    careful with your mutations.
  • 26:30 - 26:33
    So you might be asking yourself, Aaron. You
    find
  • 26:33 - 26:36
    all these bugs in the Rails and there's all
  • 26:36 - 26:37
    these bugs, why would you want to work on
  • 26:37 - 26:40
    this piece of code. And I'll tell you, the
  • 26:40 - 26:43
    reason I like working on Rails, the reason
    I
  • 26:43 - 26:45
    love being on the Rails core team is actually
  • 26:45 - 26:48
    because I love Ruby.
  • 26:48 - 26:53
    Is that weird? I just Googled for heart images.
  • 26:53 - 27:00
    I don't know if that's, like. Anyway. The
    reason
  • 27:00 - 27:03
    I love working on Rails is because Rails is
  • 27:03 - 27:06
    what gave me a job as a Ruby programmer.
  • 27:06 - 27:09
    So I want Rails to give everybody jobs. I
  • 27:09 - 27:10
    want to be able, I want everybody to be
  • 27:10 - 27:12
    able to work in Ruby on a day to
  • 27:12 - 27:14
    day basis. So it's really important to me
    to
  • 27:14 - 27:17
    make Rails a better place so that companies
    will
  • 27:17 - 27:18
    continue to adopt it and that people will
    be
  • 27:18 - 27:23
    able to have jobs and get paid using Ruby.
  • 27:23 - 27:25
    So the next portion of the presentation I
    want
  • 27:25 - 27:26
    to talk about is AdequateRecord.
  • 27:26 - 27:31
    This is a thing that I've been working on.
  • 27:31 - 27:36
    It's from Adequate Industries. So, what is,
    what is
  • 27:36 - 27:39
    AdequateRecord? AdequateRecord is a fork of
    ActiveRecord with some
  • 27:39 - 27:42
    performance improvements put on top of it,
    and I
  • 27:42 - 27:45
    want to talk about those performance improvements.
    But first
  • 27:45 - 27:47
    off, like, I gathered a whole bunch of quotes
  • 27:47 - 27:51
    about AdequateRecord. Like, what people are
    saying about it,
  • 27:51 - 27:54
    like, using it, using it on their applications
    and
  • 27:54 - 27:55
    how they find it.
  • 27:55 - 27:57
    So I want to share those quotes with you
  • 27:57 - 27:59
    just to, you know, so you know the quality
  • 27:59 - 28:06
    of the software. It's like ActiveRecord but
    more adequate.
  • 28:06 - 28:09
    I'm quoting myself.
  • 28:09 - 28:13
    That's how you know it's legit. It's all right,
  • 28:13 - 28:18
    but I've seen better. Thanks Jeremy. I appreciate
    that.
  • 28:18 - 28:21
    It was really good. Yehuda says, oh, it seems
  • 28:21 - 28:27
    to work. Josh Szmajda says, Sometimes good
    enough is
  • 28:27 - 28:30
    good enough.
  • 28:30 - 28:32
    I actually, I tried to get a quote from
  • 28:32 - 28:37
    Matz, and he just said, what? What is that?
  • 28:37 - 28:41
    So, why did I name it, like, why did
  • 28:41 - 28:44
    I actually name this library Adequate? I actually
    had
  • 28:44 - 28:46
    a motivation behind naming it AdequateRecord,
    and the reason
  • 28:46 - 28:51
    is humility. Like, I'm actually super tired
    of libraries
  • 28:51 - 28:55
    that are named, like, ActiveSomething and
    TerribleThis and all
  • 28:55 - 28:58
    that, like. Why? Why do we have to have
  • 28:58 - 29:01
    things that are named, like, super awesome
    whatever software?
  • 29:01 - 29:02
    Like I, I just want to know what your
  • 29:02 - 29:05
    software does. I don't care how awesome it
    is.
  • 29:05 - 29:08
    I just want something that works.
  • 29:08 - 29:12
    So, that's why I named it AdequateRecord.
    It's also,
  • 29:12 - 29:15
    it's another thing, like, I think it's an
    anti-marketing
  • 29:15 - 29:18
    term. I feel like a lot of software is
  • 29:18 - 29:19
    trying to be sold to me, and it really
  • 29:19 - 29:21
    bugs me. I don't like it when people try
  • 29:21 - 29:23
    to sell stuff to me. It's kind of like,
  • 29:23 - 29:27
    I don't know, the new version of people coming
  • 29:27 - 29:29
    to your door and trying to sell you stuff.
  • 29:29 - 29:31
    I want people to buy the software based on
  • 29:31 - 29:34
    its merits, not based on, like, how cool the
  • 29:34 - 29:36
    name is or whatever.
  • 29:36 - 29:39
    So, why did I fork?
  • 29:39 - 29:42
    The reason I forked is that I don't actually
  • 29:42 - 29:45
    want new features. SO this is a dirty little
  • 29:45 - 29:48
    secret of mine. I don't actually want new
    features
  • 29:48 - 29:52
    in Rails. Yet. I think that Rails accomplishes,
    like,
  • 29:52 - 29:55
    90% of the stuff that we need to have,
  • 29:55 - 29:58
    make great web apps. And I'm afraid that if
  • 29:58 - 30:00
    we try to keep going that extra ten percent,
  • 30:00 - 30:02
    we're just gonna be adding cruft that nobody
    wants
  • 30:02 - 30:05
    to use, or it's just, increasing the complexity
    of
  • 30:05 - 30:07
    the code that's there.
  • 30:07 - 30:09
    It actually makes me incredibly paranoid when
    we, when
  • 30:09 - 30:12
    we add new features to Rails, because, you
    know,
  • 30:12 - 30:13
    a lot of people think, like, hey, there's
    a
  • 30:13 - 30:16
    new feature there. This is really awesome.
    I can
  • 30:16 - 30:18
    do these super magical things, and I look
    at
  • 30:18 - 30:22
    it, and I'm like. Oh man. How many years
  • 30:22 - 30:26
    of refactoring is that gonna cost me?
  • 30:26 - 30:28
    So let's talk about, let's talk about Adequate's
    history,
  • 30:28 - 30:29
    so I can give you a little bit of
  • 30:29 - 30:32
    background about why I have opinions like
    that.
  • 30:32 - 30:34
    I've actually been working on this project
    for about
  • 30:34 - 30:38
    three years. So I've been refactoring the
    Rails code
  • 30:38 - 30:42
    base with this particular optimization in
    mind, and I,
  • 30:42 - 30:45
    it's taken me three years of refactoring this
    legacy
  • 30:45 - 30:46
    code just to get to the point where I
  • 30:46 - 30:49
    could actually add this stuff. If you look
    at
  • 30:49 - 30:51
    my talks for the past three years, I've been
  • 30:51 - 30:54
    talking about this stuff in theory, like talking
    about,
  • 30:54 - 30:57
    talking about doing prepared statement caching,
    talking about doing
  • 30:57 - 30:58
    yack shaving.
  • 30:58 - 31:00
    All these things are actually just leading
    up to
  • 31:00 - 31:03
    this. So, I, I'm actually very glad to have
  • 31:03 - 31:06
    all of you here today, because this is probably,
  • 31:06 - 31:08
    to me, the most important talk that I've given.
  • 31:08 - 31:11
    Because I've spent so much time on this. I've
  • 31:11 - 31:13
    had this idea in my head for three years
  • 31:13 - 31:15
    now and I really want to talk about it.
  • 31:15 - 31:17
    Adequate.
  • 31:17 - 31:20
    So, in order to talk about this, we need
  • 31:20 - 31:23
    to talk about how ActiveRecord works. So I'm
    gonna
  • 31:23 - 31:25
    just show like a brief overview of how ActiveRecord
  • 31:25 - 31:28
    works, and then we'll talk about the performance
    improvements
  • 31:28 - 31:29
    of AdequateRecord.
  • 31:29 - 31:30
    This is what it looks like when you say
  • 31:30 - 31:33
    post dot find ten, we go through a process
  • 31:33 - 31:35
    that looks similar to this. When you say post
  • 31:35 - 31:39
    dot find, we create new ActiveRecord relation
    object. Those
  • 31:39 - 31:43
    ActiveRecord relation objects eventually get
    translated into aRel SQL
  • 31:43 - 31:47
    nodes, into a SQL AST. That AST is then
  • 31:47 - 31:50
    transformed completely into a string. Literally
    a string. That
  • 31:50 - 31:53
    string is sent to the database. The database
    returns
  • 31:53 - 31:56
    a bunch of records. Those records are turned
    into
  • 31:56 - 31:58
    ActiveRecord base objects and then sent back
    to you
  • 31:58 - 32:00
    wherever you called that.
  • 32:00 - 32:02
    So this is basically the high-level overview
    of what
  • 32:02 - 32:05
    happens with ActiveRecord.
  • 32:05 - 32:07
    So the chance, the first change that we had
  • 32:07 - 32:10
    to go through was bind parameter introduction,
    and I'm
  • 32:10 - 32:13
    gonna show you why we need to do that.
  • 32:13 - 32:15
    If you looked at the, if you looked at
  • 32:15 - 32:17
    the logs in Rails many years ago, you'd see
  • 32:17 - 32:19
    something that looks like this. If you did
    post
  • 32:19 - 32:21
    dot find one or find three, you'd see these
  • 32:21 - 32:24
    SQL statements in your, in your logs.
  • 32:24 - 32:26
    And you may notice about them, the only thing
  • 32:26 - 32:30
    that changes is that number. The rest of the
  • 32:30 - 32:34
    string is constant. it does not change. So
    what
  • 32:34 - 32:35
    we did now, if you look in later versions
  • 32:35 - 32:37
    of Rails, you'll start to see something in
    your
  • 32:37 - 32:39
    logs that looks like this. Select star from
    post
  • 32:39 - 32:41
    where id equals question mark. And then some
    square
  • 32:41 - 32:44
    brackets there saying ID comma one.
  • 32:44 - 32:46
    And what the idea here is that we're trying
  • 32:46 - 32:49
    to separate static and dynamic content. Those
    are ids
  • 32:49 - 32:53
    are the only dynamic thing in that string,
    right.
  • 32:53 - 32:55
    We want to be able to generate something that's
  • 32:55 - 33:00
    always the same. The Adequate theory is that,
    in
  • 33:00 - 33:04
    this, in this diagram, if everything that
    generates that
  • 33:04 - 33:08
    string always generates the same thing, we
    should be
  • 33:08 - 33:10
    able to cache it. If you say post dot
  • 33:10 - 33:13
    find and it goes through all this stuff and
  • 33:13 - 33:16
    it generates a SQL statement that's always
    the same,
  • 33:16 - 33:18
    we should be able to cache that computation.
  • 33:18 - 33:20
    It means that we can say, OK, let's just
  • 33:20 - 33:22
    cache that. Then the next time you call post
  • 33:22 - 33:24
    dot find, we don't have to generate the SQL
  • 33:24 - 33:26
    statement. It's already there. Because we
    don't have any
  • 33:26 - 33:30
    dynamic values embedded in it. So this was
    done
  • 33:30 - 33:32
    quite awhile ago.
  • 33:32 - 33:34
    The next thing that we needed to do is
  • 33:34 - 33:39
    decouple our code. Now, separating the dynamic,
    the static
  • 33:39 - 33:42
    and dynamic content sounds, like, easy enough,
    but it
  • 33:42 - 33:46
    actually is not because it is embedded deep
    within
  • 33:46 - 33:47
    the Rails code. I am gonna show you where
  • 33:47 - 33:51
    it is. This is the worst part. Right here.
  • 33:51 - 33:55
    Yeah. You don't need to read that. Don't worry.
  • 33:55 - 33:58
    Those are, those three arrows are pointing
    at dynamic
  • 33:58 - 34:00
    values that are being inserted into your code.
    This
  • 34:00 - 34:03
    is deep within the call. Deep within the callstack.
  • 34:03 - 34:07
    This is actually inside the association's
    code. That's, and
  • 34:07 - 34:11
    that is one method. It is one method.
  • 34:11 - 34:13
    It is one method to rule them all and
  • 34:13 - 34:17
    in the legacy code bind them.
  • 34:17 - 34:19
    So this method defines how all the joins are
  • 34:19 - 34:23
    done inside of, inside of a relation. Like,
    basically
  • 34:23 - 34:25
    the problem with this method is if you have
  • 34:25 - 34:30
    specifically was, STI. So if you have single-table
    inheritance
  • 34:30 - 34:33
    and you need to insert that value for the,
  • 34:33 - 34:34
    the model name in there, that's what that
    was
  • 34:34 - 34:36
    handling.
  • 34:36 - 34:39
    So in order to simplify that, that, so that
  • 34:39 - 34:42
    code was, I think I said this was only
  • 34:42 - 34:45
    to do with associations. Like, has_many, has_many_through
    et cetera
  • 34:45 - 34:47
    et cetera. And I wanted to simplify that code,
  • 34:47 - 34:51
    so in Rails 4.1, I deleted has_and_belongs_to_many.
    It is
  • 34:51 - 34:53
    gone.
  • 34:53 - 34:59
    Thank you. I am extremely proud about this.
    And
  • 34:59 - 35:01
    don't, for those of you that haven't upgraded
    to
  • 35:01 - 35:05
    4 point 1 yet, it still works, OK? has_and_belongs_to_many,
  • 35:05 - 35:09
    the keyword is still there. You, you will
    be
  • 35:09 - 35:11
    able to upgrade your app and it will actually
  • 35:11 - 35:12
    work. And the way that I got it to
  • 35:12 - 35:16
    work is, has_and_belongs_to_many is actually
    a subset of has_many_through.
  • 35:16 - 35:17
    If you think about.
  • 35:17 - 35:20
    So, if you think about has_and_belongs_to_many,
    it's got three
  • 35:20 - 35:24
    tables. Has_many_through also has three tables.
    But has_many_through forces
  • 35:24 - 35:28
    you to define a middle model. So the, the
  • 35:28 - 35:32
    refactoring that I did is just on has, has_and_belongs_to_many,
  • 35:32 - 35:37
    it translates your, that call into a has_many_through
    with
  • 35:37 - 35:39
    an anonymous middle model.
  • 35:39 - 35:42
    So it should be completely transparent to
    you. And
  • 35:42 - 35:43
    because I was able to do that, I could
  • 35:43 - 35:46
    remove a bunch of code from that very complex
  • 35:46 - 35:47
    method, and I want to show you that I,
  • 35:47 - 35:50
    like, I don't expect you to read this diff.
  • 35:50 - 35:52
    I'm gonna show you a diff. I'm just showing
  • 35:52 - 35:54
    you a diff cause I'm very, very proud of
  • 35:54 - 35:55
    it. It, it's one of my favorite commits in
  • 35:55 - 35:57
    the Rails code base.
  • 35:57 - 35:59
    All you need to see that there are red
  • 35:59 - 36:02
    parts and no green parts. And there's a bunch
  • 36:02 - 36:04
    of commits that look like this. And the reason
  • 36:04 - 36:07
    I love these commits so much is because they're
  • 36:07 - 36:11
    removing stuff, not replacing it, and they're
    specifically removing
  • 36:11 - 36:15
    conditionals. There are if-statements in there
    that are just
  • 36:15 - 36:18
    getting pulled out and thrown away.
  • 36:18 - 36:20
    It makes me so happy, because when you look
  • 36:20 - 36:22
    at this code, you don't have to think about
  • 36:22 - 36:25
    those conditionals. Those conditionals are
    what tire you out.
  • 36:25 - 36:26
    You look at that and you're like, oh, if
  • 36:26 - 36:28
    it's this thing, then it does this, and you
  • 36:28 - 36:30
    think, well how did it get that way?
  • 36:30 - 36:33
    How, and you have to go figure out, how
  • 36:33 - 36:35
    did it get that way? So I felt very
  • 36:35 - 36:37
    happy about this. I was eating code out of
  • 36:37 - 36:40
    the Rails codebase. It made me super happy.
  • 36:40 - 36:43
    So, the next part. Wow, I'm actually making
    it
  • 36:43 - 36:46
    on time. I'm happy. OK. The next part, part
  • 36:46 - 36:48
    three, was to introduce a cache. This is finally
  • 36:48 - 36:50
    where we get to see our speed improvements.
    I'm
  • 36:50 - 36:53
    gonna show you the cache, what the caching
    API
  • 36:53 - 36:56
    looks like, but this is totally internals.
    Like, don't
  • 36:56 - 37:00
    use this. The API is unstable. But I'm just
  • 37:00 - 37:02
    gonna show you what it, what it looks like.
  • 37:02 - 37:04
    What, I'm gonna show you what it looks like
  • 37:04 - 37:06
    so that you know what the cache is or
  • 37:06 - 37:07
    what we're caching.
  • 37:07 - 37:08
    This is what the cache, this is a cache
  • 37:08 - 37:11
    code example. So, we can say, like, person
    dot
  • 37:11 - 37:15
    where, name, parameters dot bind, and then
    limit one.
  • 37:15 - 37:17
    And what that does is it caches the relation
  • 37:17 - 37:19
    that you created in there. And we can execute
  • 37:19 - 37:22
    that, we can execute that cached statement
    multiple times
  • 37:22 - 37:24
    with dynamic values.
  • 37:24 - 37:26
    So, wherever that params dot bind is, that's
    a
  • 37:26 - 37:32
    dynamic value. So, there's our normal, ActiveRecord
    relation object,
  • 37:32 - 37:34
    and that is where we execute it with different,
  • 37:34 - 37:37
    different values. Now, the thing about this
    is, the
  • 37:37 - 37:39
    reason I haven't exposed this to anybody,
    or one
  • 37:39 - 37:42
    reason I haven't exposed this to anybody is
    because,
  • 37:42 - 37:44
    the return value of that statement inside
    the block
  • 37:44 - 37:49
    must be an ActiveRecord relation object. And
    probably, I'm
  • 37:49 - 37:52
    figuring most people outside of the Rails
    core team
  • 37:52 - 37:57
    don't know which methods return ActiveRecord
    relation objects.
  • 37:57 - 37:59
    So, I know this, but probably not many other
  • 37:59 - 38:01
    people do. So I don't think it's a very
  • 38:01 - 38:05
    good interface for public consumption. So
    I want to
  • 38:05 - 38:07
    show the ob, cache object internals. This
    is what
  • 38:07 - 38:10
    the actual statement cache looks like. We
    have in,
  • 38:10 - 38:13
    from that previous example, we have the bind
    values.
  • 38:13 - 38:16
    These are the bind values. This keeps the
    offset.
  • 38:16 - 38:18
    It indicates the offset into the SQL statement
    where
  • 38:18 - 38:21
    that dynamic value is. And it also contains
    the
  • 38:21 - 38:23
    information for how to cast that dynamic value.
  • 38:23 - 38:26
    So, for example, when you get an id that
  • 38:26 - 38:28
    comes in from the request, that id is a
  • 38:28 - 38:30
    string, and we need to be able to cast
  • 38:30 - 38:32
    that to an integer. This contains that information.
    And
  • 38:32 - 38:35
    then down below is where the actual SQL statement
  • 38:35 - 38:38
    is cached and you can see it's just a
  • 38:38 - 38:39
    string.
  • 38:39 - 38:42
    So the next step after defining these cache,
    this
  • 38:42 - 38:44
    cache, was to update the internals and cache
    any
  • 38:44 - 38:48
    relation objects. And this is very interesting
    because, we
  • 38:48 - 38:49
    went through and looked through all the places
    in
  • 38:49 - 38:53
    ActiveRecord where relation objects are actually
    used. So, they're
  • 38:53 - 38:54
    used, these are the examples of things that
    are
  • 38:54 - 38:58
    used and I know it's a cardinal sin. Dots
  • 38:58 - 39:00
    with stuff to read. But I don't care. I've
  • 39:00 - 39:05
    been working on this forever so screw you
    guys.
  • 39:05 - 39:11
    So, all these things use ActiveRecord relations.
    Internally. Basically,
  • 39:11 - 39:13
    everything that you do with ActiveRecord uses
    relations and
  • 39:13 - 39:17
    relations internally. All of these are cacheable.
    So we
  • 39:17 - 39:19
    can add caches to all these things, and I'm
  • 39:19 - 39:21
    gonna show you an example of the cache that
  • 39:21 - 39:24
    we added internally. This is an example implementation.
  • 39:24 - 39:26
    So this is the implementation for find with
    an
  • 39:26 - 39:29
    id. You can see in there, we, we have
  • 39:29 - 39:33
    a key, and we say OK, create that relation.
  • 39:33 - 39:36
    So, in your Rails code, you may have typed
  • 39:36 - 39:38
    post dot where primary key arrow. That thing.
    We're
  • 39:38 - 39:41
    basically just doing that internally. So it's
    really not
  • 39:41 - 39:43
    much different than what you would do inside
    your
  • 39:43 - 39:44
    app code.
  • 39:44 - 39:46
    So that is our, that is our static values
  • 39:46 - 39:48
    for the SQL statement. And then here are our
  • 39:48 - 39:51
    dynamic values. That's the id that you actually
    passed
  • 39:51 - 39:53
    into find, so we just always call with that
  • 39:53 - 39:54
    id.
  • 39:54 - 39:56
    So I want to share a few, after looking
  • 39:56 - 39:57
    at that, it's really exciting. I want to share
  • 39:57 - 40:00
    a few fun facts. These are the different ways
  • 40:00 - 40:02
    that you can call post dot find.
  • 40:02 - 40:04
    I don't know if you knew this. You can
  • 40:04 - 40:05
    call with an array. You can call with an
  • 40:05 - 40:07
    array of arrays. You can call with a hash.
  • 40:07 - 40:09
    You can call with an ActiveRecord id. You
    can
  • 40:09 - 40:11
    call it with a block. You can call it
  • 40:11 - 40:12
    with scope. And you can call it with a
  • 40:12 - 40:15
    block and a scope with any of those combinations
  • 40:15 - 40:17
    above it.
  • 40:17 - 40:22
    So, only that one is cacheable. The rest of
  • 40:22 - 40:24
    these are, like, I have no idea why we
  • 40:24 - 40:27
    even support that. I don't even know what
    they
  • 40:27 - 40:30
    mean. So when I was trying to figure out
  • 40:30 - 40:31
    what we could cache and what we couldn't cache,
  • 40:31 - 40:34
    I felt like this. So if you go look
  • 40:34 - 40:36
    at the method, if you go look at the
  • 40:36 - 40:39
    method, I'm like, OK, this is all the stuff
  • 40:39 - 40:41
    that we can't cache. I don't know this, this,
  • 40:41 - 40:44
    any of these. So I'm gonna show you some
  • 40:44 - 40:47
    performance statistics for this. And if we
    could remove
  • 40:47 - 40:50
    all of that API, that would actually be super
  • 40:50 - 40:53
    nice. I would like that. Cause we could have
  • 40:53 - 40:54
    ActiveRecord even faster.
  • 40:54 - 40:56
    So let's talk about measuring performance,
    because we want
  • 40:56 - 41:00
    to see the performance of these things. I'm
    gonna
  • 41:00 - 41:03
    talk about some benchmarking tools. The way
    that I
  • 41:03 - 41:06
    benchmark this stuff and the way that you
    should
  • 41:06 - 41:07
    benchmarking things. The first tool I want
    to talk
  • 41:07 - 41:11
    about is benchmark/ips. This is a library
    that, actually,
  • 41:11 - 41:13
    Evan wrote. And I'm gonna compare this to
    the
  • 41:13 - 41:16
    normal benchmark library that's in, that comes
    shipped with
  • 41:16 - 41:17
    Ruby.
  • 41:17 - 41:19
    This is the normal benchmark library. So you
    say
  • 41:19 - 41:22
    like, OK, benchmark something, and then you
    need to
  • 41:22 - 41:23
    loop over something and see how long it takes.
  • 41:23 - 41:25
    That'll report to you how long it takes to
  • 41:25 - 41:28
    call that thing. The problem with this benchmark
    is,
  • 41:28 - 41:32
    like, we loop n-times, but how big should
    n
  • 41:32 - 41:34
    be? Have you ever written a benchmark and
    you
  • 41:34 - 41:38
    run it and it's like, oh, zero time?
  • 41:38 - 41:41
    Good job dude. So you have to sit there
  • 41:41 - 41:44
    and think, like, OK, I gotta increase the
    n.
  • 41:44 - 41:46
    Maybe decrease the n. And maybe you send the
  • 41:46 - 41:48
    benchmark off to somebody who has a faster
    machine
  • 41:48 - 41:50
    than you or a slower machine than you. Then
  • 41:50 - 41:51
    they have to, then they have to change the
  • 41:51 - 41:55
    n. What benchmark/ips does is it actually
    measures the
  • 41:55 - 41:58
    iterations per second. The number of times
    it can
  • 41:58 - 42:00
    call that method per second.
  • 42:00 - 42:02
    So you write a benchmark that looks like this.
  • 42:02 - 42:05
    And it will run that block as many times
  • 42:05 - 42:07
    as it can in five seconds. So it just
  • 42:07 - 42:10
    defaults to five seconds. And the output looks
    like
  • 42:10 - 42:11
    this. It says, OK, we can call it that
  • 42:11 - 42:15
    many times in five seconds. And the other
    thing
  • 42:15 - 42:16
    I really, really like about it, is it gives
  • 42:16 - 42:19
    you a standard deviation report. That plus
    or minus
  • 42:19 - 42:20
    three percent that's shown there.
  • 42:20 - 42:23
    The problem with the previous benchmarking
    tool is it
  • 42:23 - 42:26
    doesn't tell you standard deviation. So let's
    say you
  • 42:26 - 42:28
    write some code. Let's say you do some sort
  • 42:28 - 42:32
    of performance improvement. You think you've
    done a performance
  • 42:32 - 42:34
    improvement, and you compare your benchmark,
    you, you have
  • 42:34 - 42:36
    this benchmark. You compare your code to the
    old
  • 42:36 - 42:38
    code. And it looks like it's slightly faster.
    You're
  • 42:38 - 42:41
    like, great, it's slightly faster. But you
    didn't know
  • 42:41 - 42:43
    what the standard deviation was. If you don't
    know
  • 42:43 - 42:45
    what the standard deviation was, it could
    just be
  • 42:45 - 42:50
    noise. It could be other programs impacting
    your benchmark.
  • 42:50 - 42:52
    You don't really know that information. It's
    better if
  • 42:52 - 42:54
    you have the standard deviation, so you know,
    ah,
  • 42:54 - 42:57
    I'm one standard deviation outside, or I'm
    two standard
  • 42:57 - 43:00
    deviations outside. So, yes, this is definitely
    a performance
  • 43:00 - 43:03
    improvement. Getting standard deviation with
    your benchmarks is important.
  • 43:03 - 43:06
    The next tool that I use is GC dot
  • 43:06 - 43:08
    stat. I'm not sure what version of Ruby this
  • 43:08 - 43:11
    is in. I think 2 point 1. GC, this
  • 43:11 - 43:14
    is, in order to count object allocations when
    we're
  • 43:14 - 43:19
    doing queries. So this call will do a total
  • 43:19 - 43:22
    object allocation count. So this actually
    counts the number
  • 43:22 - 43:25
    of objects that have been allocated in your
    system
  • 43:25 - 43:29
    ever. Not, like, now, or not inside a loop,
  • 43:29 - 43:32
    but ever. Every time you allocate an object,
    this
  • 43:32 - 43:33
    value increases.
  • 43:33 - 43:36
    So, what we do, is I say, OK, I'm
  • 43:36 - 43:38
    gonna call, I'm gonna warm up this benchmark.
    I'm
  • 43:38 - 43:41
    gonna call person dot find. Then I'm gonna
    count
  • 43:41 - 43:43
    the total number of objects that were allocated
    in
  • 43:43 - 43:46
    the system. Then I'm gonna actually execute
    my benchmark
  • 43:46 - 43:48
    and say, OK, call, you know, find this person
  • 43:48 - 43:53
    so many times. Count the objects again. Subtract
    and
  • 43:53 - 43:56
    divide. And then we know the number of objects
  • 43:56 - 44:00
    that have been allocated per call. Science.
  • 44:00 - 44:06
    I should have put a slide of Jesse Pinkman
  • 44:06 - 44:07
    in here.
  • 44:07 - 44:10
    Anyway, so let's, let's actually look at some
    numbers.
  • 44:10 - 44:14
    Let's look at the performance of AdequateRecord.
    So let's,
  • 44:14 - 44:15
    we're gonna look at post dot find and post
  • 44:15 - 44:17
    dot find_by_name.
  • 44:17 - 44:20
    So, I wanted to benchmark these because they're,
    they're
  • 44:20 - 44:22
    essentially the same thing. One is just finding
    by
  • 44:22 - 44:24
    id the other one's finding by name. So they
  • 44:24 - 44:27
    should be approximately the same. And this
    is a
  • 44:27 - 44:31
    graph of their performance, essentially over
    time. The x-axis
  • 44:31 - 44:34
    along the bottom is the branch. So on the
  • 44:34 - 44:38
    left side is 2.3 stable to 3.0 stable, proceeding
  • 44:38 - 44:41
    to the right. The very right is AdequateRecord.
  • 44:41 - 44:44
    The bar along the y-axis is the calls per
  • 44:44 - 44:48
    second to the, to post dot find. So the
  • 44:48 - 44:51
    higher that is, the better. You can actually
    see
  • 44:51 - 44:54
    there around in 3.1 stable, it was tanking,
    like
  • 44:54 - 44:56
    super hard. I mean look at that.
  • 44:56 - 44:58
    What's also interesting here is that yellow
    line. That
  • 44:58 - 45:02
    yellow line represents mySQL, and I should
    say these,
  • 45:02 - 45:04
    along the bottom there, I say SQLite and mySQL
  • 45:04 - 45:07
    2 and mySQL and PostGres. That actually represents
    that
  • 45:07 - 45:11
    particular adapter that we were using. So,
    not exactly
  • 45:11 - 45:13
    mapping to the database. We were testing mySQL
    twice.
  • 45:13 - 45:15
    And I think this graph is interesting because
    you
  • 45:15 - 45:18
    can see, in 2.3 stable there was actually
    a
  • 45:18 - 45:24
    bias towards mySQL. MySQL was significantly
    faster in 2.3
  • 45:24 - 45:27
    stable than PostGres was, but you'll see that
    those
  • 45:27 - 45:29
    actually even out along here.
  • 45:29 - 45:32
    Now, this is the same, same benchmark put
    with
  • 45:32 - 45:36
    post dot find_by_name, and you can see, basically,
    the,
  • 45:36 - 45:37
    the look of the graph is about the same
  • 45:37 - 45:39
    as the previous one. We started out faster
    in
  • 45:39 - 45:43
    2.3, it slowed down, and then over on AdequateRecord
  • 45:43 - 45:45
    we're going much faster. And I just wanted
    to
  • 45:45 - 45:48
    call out this one here. This is mySQL. This
  • 45:48 - 45:51
    is that same graph, but I specifically pulled
    out
  • 45:51 - 45:56
    mySQL to show you, like, exactly the performance,
    the
  • 45:56 - 45:58
    performance changes of mySQL over time. So
    you can
  • 45:58 - 46:01
    see it just tanked super hard at 3.1 and
  • 46:01 - 46:04
    then slowly came back up.
  • 46:04 - 46:07
    This is the percent faster that AdequateRecord
    is than
  • 46:07 - 46:10
    4.1 stable. So, let's see, what is that? Some
  • 46:10 - 46:13
    of these are over a hundred percent faster,
    so
  • 46:13 - 46:16
    it's two times faster. This is the percent
    faster
  • 46:16 - 46:18
    it is than 3.2 st- or, 2.3 stable. We
  • 46:18 - 46:22
    can see mySQL, it is faster on AdequateRecord
    but
  • 46:22 - 46:24
    not by much. So we are faster.
  • 46:24 - 46:27
    This is a graph of the object allocations.
    So
  • 46:27 - 46:28
    this is the number of objects that are allocated
  • 46:28 - 46:31
    per call. And you can see there around 3.1
  • 46:31 - 46:33
    stable and 3.2, we're actually increasing
    the number of
  • 46:33 - 46:36
    objects that we allocate per call to this.
  • 46:36 - 46:40
    So it doesn't necessarily directly impact
    the calls per
  • 46:40 - 46:42
    second. It does have an impact on it, and
  • 46:42 - 46:47
    GC.pressure() does cause issues. But it's
    not, they're not
  • 46:47 - 46:51
    exactly aligned together.
  • 46:51 - 46:54
    Same issues with find_by_name. And you can
    see there,
  • 46:54 - 46:58
    again, on 2.3 stable a strong bias towards
    mySQL.
  • 46:58 - 47:05
    So AdequateRecord allocates 70% fewer objects
    than 4.1 stable
  • 47:05 - 47:09
    does per call. It allocates 55% fewer objects
    per
  • 47:09 - 47:11
    call than 2.3 stable.
  • 47:11 - 47:13
    Now I want to look at belongs_to. Like, I'm
  • 47:13 - 47:15
    gonna look at the, I'm gonna look at each
  • 47:15 - 47:18
    of the relations. So, belongs_to graph looks
    very similar
  • 47:18 - 47:22
    to those previous ones, except that SQLite3
    is insanely
  • 47:22 - 47:26
    faster. So, again, along the bottom is time.
    Along
  • 47:26 - 47:29
    the y-axis is calls per second, so higher
    is
  • 47:29 - 47:35
    better. Percent faster than 2.3 stable and
    4.1 stable.
  • 47:35 - 47:38
    The mySQL 2 bar doesn't have a 2.3 stable
  • 47:38 - 47:40
    one, because mySQL to that adapter didn't
    exist until
  • 47:40 - 47:44
    2.3 stable so I didn't test it. But we're
  • 47:44 - 47:46
    all, AdequateRecord is faster in all cases.
  • 47:46 - 47:50
    has_many :through. So I want to show has_many
    as
  • 47:50 - 47:53
    well as has_many :through. This is the performance
    graph
  • 47:53 - 47:55
    for that as well. You see exactly the same
  • 47:55 - 47:57
    thing. Started out fast. 2.3 stable, went
    down, and
  • 47:57 - 48:01
    now we're faster in AdequateRecord. Also,
    has_many :through call
  • 48:01 - 48:03
    speed over time.
  • 48:03 - 48:07
    So, again, we're also faster than 2.3 stable
    in
  • 48:07 - 48:10
    every case. Much faster than 4.1 stable in
    every
  • 48:10 - 48:12
    case. And the last thing I want to look
  • 48:12 - 48:18
    at is has_many :through growth. So caching
    these SQL
  • 48:18 - 48:21
    statements should give a, should give us constant
    time
  • 48:21 - 48:24
    performance with regard to generating the
    actual SQL statement
  • 48:24 - 48:26
    string. And that's what I want to demonstrate
    here
  • 48:26 - 48:30
    is show you that constant time performance
    compared to
  • 48:30 - 48:31
    actually any of the other branches.
  • 48:31 - 48:33
    So what I'm talking about with has_many :through
    growth
  • 48:33 - 48:35
    is, let's say we have a model that looks
  • 48:35 - 48:40
    like this. We say has_many :through one thing.
    What
  • 48:40 - 48:42
    I want to study here, in this case, is
  • 48:42 - 48:45
    what if we add another has_many :through.
    So what
  • 48:45 - 48:47
    if there's two of them? We go through two.
  • 48:47 - 48:49
    And then what happens if we go through three?
  • 48:49 - 48:52
    And what happens if we go through four? Et
  • 48:52 - 48:55
    cetera, et cetera, et cetera. So we keep increasing
  • 48:55 - 48:57
    the number of tables that we're joining against
    on
  • 48:57 - 48:58
    has_many :through, and this is what the graph
    looks
  • 48:58 - 48:59
    like.
  • 48:59 - 49:02
    So you can see, on master, well, actually,
    4.1
  • 49:02 - 49:05
    stable, actually, any of the, any of the branches
  • 49:05 - 49:07
    will look similar to this. Along the bottom
    is
  • 49:07 - 49:10
    the number of tables that we're actually joining
    against.
  • 49:10 - 49:12
    So that's the number of has_many :throughs
    that we're,
  • 49:12 - 49:14
    we're joining against. So at the very right
    hand
  • 49:14 - 49:17
    side, we're joining against sixteen tables.
  • 49:17 - 49:18
    And you can see on master we actually have
  • 49:18 - 49:22
    linear growth and on AdequateRecord we have
    constant time
  • 49:22 - 49:24
    growth. And it does grow just a little bit
  • 49:24 - 49:27
    there, and the reason, the reason it grow
    just
  • 49:27 - 49:30
    a little bit is because we're actually sending
    those
  • 49:30 - 49:32
    queries to the database, so database time
    is impacting
  • 49:32 - 49:35
    this. But the algorithm is constant time.
  • 49:35 - 49:38
    So, I am extremely, this is my favorite graph.
  • 49:38 - 49:43
    Aw yeah. Constant time!
  • 49:43 - 49:49
    So, this is, this is one of the things
  • 49:49 - 49:51
    that I'm talking about with why I think studying
  • 49:51 - 49:58
    computer science is important. OK? If you
    study this
  • 49:58 - 50:00
    stuff, you can say, you can look at these,
  • 50:00 - 50:02
    this performance, you can increase your code
    and you
  • 50:02 - 50:04
    can talk about it. You can quantify it. DHH
  • 50:04 - 50:07
    gave the example of, like, oh, I take a
  • 50:07 - 50:08
    lot of pictures, and now I've taken a lot
  • 50:08 - 50:11
    of pictures, so I'm just good at pictures.
    Which
  • 50:11 - 50:15
    is very nice. Except that, there is, I'm happy
  • 50:15 - 50:17
    that he takes pictures. That's cool. I like
    to
  • 50:17 - 50:21
    cure meats. I mean, we all have things.
  • 50:21 - 50:25
    But, even with, even with studying picture-taking,
    people are
  • 50:25 - 50:26
    like, OK, we have the rule of thirds. We
  • 50:26 - 50:28
    have the golden rules. There are these things
    that
  • 50:28 - 50:31
    we do that it, we can all talk about.
  • 50:31 - 50:32
    We have a common language and we also all
  • 50:32 - 50:35
    discovered that, hey, if we do these particular
    things,
  • 50:35 - 50:39
    our photographs turn out better. Generally
    speaking.
  • 50:39 - 50:41
    We have these things we can talk about, and
  • 50:41 - 50:44
    I think that's exactly what studying science
    brings to
  • 50:44 - 50:46
    the table. We can talk about this. I can
  • 50:46 - 50:48
    say to you, here is exactly why the performance
  • 50:48 - 50:52
    is much better. Generally constant time is
    better than
  • 50:52 - 50:58
    linear growth.
  • 50:58 - 51:05
    Anyway. TL;DR, 100% faster.
  • 51:09 - 51:14
    Thank you.
  • 51:14 - 51:21
    9001% better. It's over 9000.
  • 51:21 - 51:23
    So what I want to talk about now, is
  • 51:23 - 51:29
    I want to talk about the Adequate pricing
    model.
  • 51:29 - 51:32
    How much are you willing to pay for AdequateRecord?
  • 51:32 - 51:36
    $200? $300? Well, today I'm offering a very
    special
  • 51:36 - 51:40
    price. Today I'm offering it for $2.99 plus
    in-app
  • 51:40 - 51:41
    purchases.
  • 51:41 - 51:44
    I'm just kidding.
  • 51:44 - 51:46
    Let's talk about some the challenges, like
    some of
  • 51:46 - 51:49
    the issues with this thing, because we're
    not, like,
  • 51:49 - 51:52
    it's not all, you know, Unicorns and fairies
    and
  • 51:52 - 51:54
    all that stuff. Like, there are, there are
    definitely
  • 51:54 - 51:55
    trade-offs for this code, and I want to talk
  • 51:55 - 51:57
    about that.
  • 51:57 - 52:00
    We're trading memory for speed, obviously.
    Like, we can't
  • 52:00 - 52:03
    just get this speed from nowhere. We have
    to
  • 52:03 - 52:06
    cache this stuff. So we need to understand
    what
  • 52:06 - 52:08
    the cache size is, and I'm gonna give you
  • 52:08 - 52:10
    a little formula for the cache size. I'm sorry.
  • 52:10 - 52:12
    It's math.
  • 52:12 - 52:15
    So, we need to be, we need to count.
  • 52:15 - 52:17
    The cache size is equal to the number of
  • 52:17 - 52:20
    relations that you have, all those has_manys,
    and also
  • 52:20 - 52:22
    the number of find_bys that you have in your
  • 52:22 - 52:24
    system total. But it's bound by that, and
    it's
  • 52:24 - 52:26
    multiplied by the size of that cache object.
    So
  • 52:26 - 52:28
    I can't tell you exactly what the size of
  • 52:28 - 52:33
    the cache objects are, because they are variable
    depending
  • 52:33 - 52:34
    on the size of the SQL queries that you
  • 52:34 - 52:36
    have in there. But they're not very big.
  • 52:36 - 52:39
    So, we are definitely paying for memory. So
    these
  • 52:39 - 52:42
    will, this will actually increase the amount
    of memory
  • 52:42 - 52:44
    that your system is consuming. So we need
    to
  • 52:44 - 52:46
    study this. We need to study this because
    maybe
  • 52:46 - 52:49
    we should introduce an LRU cache to this and
  • 52:49 - 52:52
    expire, expire things as they go out. But
    since
  • 52:52 - 52:55
    the, since this particular cache is bound,
    I don't
  • 52:55 - 52:57
    think it's gonna be a problem.
  • 52:57 - 53:00
    The other issue is raw relations. So you're
    saying
  • 53:00 - 53:02
    to me, Aaron, you know, you might be saying
  • 53:02 - 53:03
    to me, Aaron, I'm really excited for you,
    you
  • 53:03 - 53:06
    increased the speed of all the stuff. But
    I
  • 53:06 - 53:10
    don't use find_by_name. I use this. Person
    dot where
  • 53:10 - 53:14
    and name. That thing. I use that. I don't
  • 53:14 - 53:17
    use find_by_name. Why don't you just make
    that faster?
  • 53:17 - 53:18
    And I say to you, why don't you make
  • 53:18 - 53:24
    it faster, jerk?
  • 53:24 - 53:26
    And the question is, so the question is, can
  • 53:26 - 53:28
    we, can we cache this? Like, can we cache
  • 53:28 - 53:30
    that thing? Can we make that thing faster?
    And
  • 53:30 - 53:33
    we can. It's true. We can do it. It's
  • 53:33 - 53:35
    possible. I have an experimental branch to
    do this.
  • 53:35 - 53:38
    This isn't in AdequateRecord right now. Where
    we take
  • 53:38 - 53:41
    those values and then generate a key from
    the
  • 53:41 - 53:44
    values that you passed to each of those relation
  • 53:44 - 53:47
    objects, and then cache the SQL query that's
    generated
  • 53:47 - 53:49
    from that. And we actually see a 30% speed
  • 53:49 - 53:50
    improvement.
  • 53:50 - 53:54
    This is person dot where, you know, name,
    to_a.
  • 53:54 - 53:57
    So blue is master and green is the experimental
  • 53:57 - 54:01
    branch with the caching built-in. So it's
    about 30%
  • 54:01 - 54:03
    faster. So that's good. The problem, though,
    is if
  • 54:03 - 54:05
    you take a look at the implementation, like,
    this
  • 54:05 - 54:08
    is, this is approximately the implementation.
    That blue part
  • 54:08 - 54:11
    is calculating the key for the cache, and
    then
  • 54:11 - 54:13
    the red part is actually executing the query.
  • 54:13 - 54:16
    Now, the problem with this code is that over
  • 54:16 - 54:20
    eleven different variables impact the cache
    key. So I
  • 54:20 - 54:22
    have to actually inspect eleven different
    variables and say,
  • 54:22 - 54:24
    like, is this, are we sure that we've seen
  • 54:24 - 54:26
    this query before? Are we sure we've seen
    this
  • 54:26 - 54:28
    query before? On eleven different variables.
    And in fact
  • 54:28 - 54:32
    that implementation that I showed you only
    handles two
  • 54:32 - 54:36
    forms of person dot where. I only cached like,
  • 54:36 - 54:38
    person dot where and person dot limit. Those
    two.
  • 54:38 - 54:40
    Cause I wanted to show some, I wanted to
  • 54:40 - 54:43
    show you one more experiment.
  • 54:43 - 54:45
    One more experiment is doing a finder comparison.
    So
  • 54:45 - 54:48
    let's say we have person dot where name Aaron,
  • 54:48 - 54:50
    like, what you might write in your controller
    and
  • 54:50 - 54:52
    then person dot find_by_name Aaron. These
    are both on
  • 54:52 - 54:56
    the experimental branch of AdequateRecord.
    So the person dot
  • 54:56 - 54:58
    where does have the speed improvements that
    I just
  • 54:58 - 55:01
    showed you. And if we benchmark these two,
    this
  • 55:01 - 55:03
    is what, this is what the results look like.
  • 55:03 - 55:07
    Where, compared to find_by_name. It's not
    even a contest.
  • 55:07 - 55:10
    Find_by_name is three times faster in this
    case, and
  • 55:10 - 55:14
    that's even with performance improvements
    to the where case.
  • 55:14 - 55:16
    And the reason is because every time we call
  • 55:16 - 55:18
    that person dot where, we're actually allocating
    a new
  • 55:18 - 55:22
    ActiveRecord relation object, and we can't
    get around that.
  • 55:22 - 55:25
    We're always gonna be allocating those objects.
    So, my
  • 55:25 - 55:27
    actual question is, like, should we, should
    we cache
  • 55:27 - 55:32
    these relations? Should we do this? I'm not
    sure.
  • 55:32 - 55:34
    I'm really not sure if we should do this.
  • 55:34 - 55:38
    It introduces some very complex code, and
    if you're
  • 55:38 - 55:40
    doing a bunch of, like, dot wheres and all
  • 55:40 - 55:43
    those things, I'm not sure exactly what you'll
    be
  • 55:43 - 55:47
    caching. In AdequateRecord today, the cache
    is bound. But
  • 55:47 - 55:49
    if you're doing a bunch of crazy stuff, like
  • 55:49 - 55:51
    all that wheres and stuff, maybe it will be
  • 55:51 - 55:53
    unbound, and you'll see unbounded memory growth
    and I
  • 55:53 - 55:55
    would not like that.
  • 55:55 - 56:00
    B-T-W, unmounted memory growth is bad. Science.
  • 56:00 - 56:03
    So, I want a new API. I want something
  • 56:03 - 56:06
    that looks like this. So, like, cached query,
    find
  • 56:06 - 56:08
    all by name, do name, and you pass in
  • 56:08 - 56:10
    a name. So you could define a method that
  • 56:10 - 56:12
    does this and we pass in the dynamic values
  • 56:12 - 56:15
    to that. So we build up a cached relation
  • 56:15 - 56:17
    in here, and then we can execute that cache
  • 56:17 - 56:19
    relation multiple times.
  • 56:19 - 56:21
    The reason I want that is because the cache
  • 56:21 - 56:22
    key is easy. The cache key is just that
  • 56:22 - 56:25
    thing you pass to me. And we're bound in
  • 56:25 - 56:27
    size.
  • 56:27 - 56:30
    The relation API is maintained as well. That's
    another
  • 56:30 - 56:32
    advantage of this thing. And you, I know you
  • 56:32 - 56:35
    might be thinking, Aaron, this looks like
    scope. We
  • 56:35 - 56:39
    can't use scope because people, in their applications
    today,
  • 56:39 - 56:41
    expect that the scope block will be executed
    multiple
  • 56:41 - 56:43
    times. I expect that there are many of you
  • 56:43 - 56:45
    in the audience who have a scope that are
  • 56:45 - 56:50
    like, today's posts, right. Where it generates
    a date.
  • 56:50 - 56:51
    It says, like, give me all the posts that
  • 56:51 - 56:55
    are after your, that happen today. And you
    expect
  • 56:55 - 56:57
    that that date is calculated every time that
    block
  • 56:57 - 56:59
    is executed. So we can't just go off of
  • 56:59 - 57:00
    the scope block.
  • 57:00 - 57:04
    All right. So I've got one more, one other
  • 57:04 - 57:08
    more thing.
  • 57:08 - 57:12
    I think, I think Steve Jobs said that, right?
  • 57:12 - 57:17
    So let's, let's merge AdequateRecord. Should
    we do that?
  • 57:17 - 57:21
    Yes? OK.
  • 57:21 - 57:22
    So I know this is, like, this is a
  • 57:22 - 57:27
    totally cardinal sin of presentations, but
    I'm gonna do,
  • 57:27 - 57:30
    do it live. Is that OK? Would you forgive
  • 57:30 - 57:33
    me? All right.
  • 57:33 - 57:40
    All right. So let's do this. All right.
  • 57:43 - 57:50
    Hold up. I'm not very good at typing. Sorry.
  • 57:50 - 57:52
    OK. OK.
  • 57:52 - 58:00
    OK. This'll work. This'll work. OK. So we're
    Git
  • 58:00 - 58:03
    pulling now. It's downloading from the internet.
    The internet
  • 58:03 - 58:09
    might be a little bit slow. Hopefully it'll
    work.
  • 58:09 - 58:18
    Please work. Ah. Ee. Maybe we won't be able
  • 58:18 - 58:25
    to do this live. Oh. Oh. OK. I think
  • 58:25 - 58:30
    it's there. Ah! Oh!
  • 58:30 - 58:34
    How do you merge? I don't know what I.
  • 58:34 - 58:37
    I don't know what I'm doing here. I mean,
  • 58:37 - 58:39
    don't you think that Git has really good documentation?
  • 58:39 - 58:42
    Isn't that, isn't that true? Like, we can
    read
  • 58:42 - 58:45
    through all the help pages there. That looks.
    Ah!
  • 58:45 - 58:48
    Oh! I didn't know about that one. OK. Ah.
  • 58:48 - 58:51
    Oh. Back to the merge. Back to the merge.
  • 58:51 - 58:54
    OK. We're merging it in. We merged it in.
  • 58:54 - 58:58
    Ah. All right. Let's commit the merge. Commit.
    OK.
  • 58:58 - 59:01
    Doing good. Good job Aaron. Oh. That was,
    that
  • 59:01 - 59:06
    was a wrong way. OK. Now let's merge it
  • 59:06 - 59:09
    in. Now let's merge it in. OK. Merged. Ah,
  • 59:09 - 59:10
    nice.
  • 59:10 - 59:17
    OK, that's master, right? Are we doing it
    right?
  • 59:23 - 59:30
    In the terminal? And. And. And. Ah.
  • 59:36 - 59:38
    Pushed.
  • 59:38 - 59:40
    OK.
  • 59:40 - 59:47
    AdequateRecord has been merged.
  • 59:48 - 59:52
    Three years of horrible stuff done. OK. So
    one,
  • 59:52 - 59:56
    this is my last, very, very strong opinion.
    My
  • 59:56 - 59:58
    last strong opinion of the evening. I think
    that
  • 59:58 - 60:01
    Rails 4.2 will be the fastest Rails ever.
    This
  • 60:01 - 60:04
    is what I am working for. I also think
  • 60:04 - 60:06
    that this is just the beginning. This is just
  • 60:06 - 60:08
    the beginning of the performance improvements
    that we can
  • 60:08 - 60:09
    do to Rails.
  • 60:09 - 60:11
    So thank you.
Title:
RailsConf 2014 - Closing Keynote by Aaron Patterson
Description:

more » « less
Video Language:
English
Duration:
01:00:59

English subtitles

Revisions