< Return to Video

RailsConf 2014 - Curmudgeon: An Opinionated Framework by Ernie Miller

  • 0:17 - 0:18
    ERNIE MILLER: Good afternoon everybody.
  • 0:18 - 0:19
    AUDIENCE: Good afternoon.
  • 0:19 - 0:20
    E.M.: How's it going?
  • 0:20 - 0:21
    AUDIENCE: It's going good! Hi Ernie!
  • 0:21 - 0:23
    E.M.: Hi. My name's Ernie Miller. I work for
  • 0:23 - 0:26
    a company called Appriss in Louisville, Kentucky.
    Please ask
  • 0:26 - 0:29
    me about them later so that I can justify
  • 0:29 - 0:30
    expensing the trip.
  • 0:30 - 0:32
    AUDIENCE: Whoo!
  • 0:32 - 0:32
    [applause]
  • 0:32 - 0:35
    E.M.: If I could ask you all to do
  • 0:35 - 0:38
    me a favor, as it turns out, most of
  • 0:38 - 0:41
    my fellow co-workers that had come out to
    RailsConf
  • 0:41 - 0:44
    have had to catch a flight to go back
  • 0:44 - 0:46
    home, and so they're missing my talk. And
    so
  • 0:46 - 0:48
    what I'd like you to do is to Tweet
  • 0:48 - 0:51
    very enthusiastically about the talk, regardless
    of if it's
  • 0:51 - 0:52
    very good, so that, you know, for at least
  • 0:52 - 0:54
    until it goes on video, they're gonna think
    they
  • 0:54 - 0:56
    missed the talk of a lifetime.
  • 0:56 - 1:00
    So, RailsConf, huh? Have you guys had a good
  • 1:00 - 1:00
    times?
  • 1:00 - 1:01
    AUDIENCE: Whoo!
  • 1:01 - 1:02
    [applause]
  • 1:02 - 1:03
    E.M.: Yeah? Yeah.
  • 1:03 - 1:08
    I've had a ball, too. I've had a ball,
  • 1:08 - 1:08
    too.
  • 1:08 - 1:09
    So.
  • 1:09 - 1:10
    AUDIENCE: Ah, yeah!
  • 1:10 - 1:11
    E.M.: I am not.
  • 1:11 - 1:13
    AUDIENCE: [indecipherable - 00:01:10]
  • 1:13 - 1:15
    E.M.: Yes. Yes it was.
  • 1:15 - 1:20
    So, I am not a member of Ruby core.
  • 1:20 - 1:25
    I am not a member of Rails core. However,
  • 1:25 - 1:28
    last month, this game came out, and I'm an
  • 1:28 - 1:32
    avid gamer, and I'd like to happily report
    that
  • 1:32 - 1:35
    I am very frequently a member of Damage core,
  • 1:35 - 1:37
    at this point.
  • 1:37 - 1:41
    Unfortunately, membership only lasts for about
    fifteen seconds at
  • 1:41 - 1:43
    a time. Then I get booted again. So, so
  • 1:43 - 1:46
    there is that. But, you know, I'm thinking,
    you
  • 1:46 - 1:48
    know, it's, it's moving up in the world. I'm
  • 1:48 - 1:50
    a member of something core.
  • 1:50 - 1:55
    So, so, it's come to my attention recently
    that
  • 1:55 - 1:57
    I have been giving a fair number of talks
  • 1:57 - 2:00
    that usually involve me ranting about something,
    and I
  • 2:00 - 2:02
    think I'm becoming a bit of a curmudgeon.
  • 2:02 - 2:02
    [applause]
  • 2:02 - 2:07
    So, you're not supposed to clap for that.
  • 2:07 - 2:08
    [laughter]
  • 2:08 - 2:10
    OK. So, one of the things that I want
  • 2:10 - 2:12
    to start off by doing is saying that I
  • 2:12 - 2:14
    recognize that most of us would not be in
  • 2:14 - 2:17
    this room if it weren't for Rails, and that
  • 2:17 - 2:20
    we really owe a lot of our opportunity to
  • 2:20 - 2:22
    get paid for doing Ruby, I know I do
  • 2:22 - 2:27
    anyway, to Rails's existence. So, first off,
    I'd like
  • 2:27 - 2:29
    to get a hand for Rails and how awesome
  • 2:29 - 2:30
    it is and how it enables us to do
  • 2:30 - 2:31
    everything.
  • 2:31 - 2:32
    [applause]
  • 2:32 - 2:36
    OK. OK. Nope. Nope. That's enough. Nope. No
    more.
  • 2:36 - 2:37
    We're done celebrating.
  • 2:37 - 2:37
    [laughter]
  • 2:37 - 2:40
    Just that much celebration. Nothing more.
  • 2:40 - 2:40
    [laughter]
  • 2:40 - 2:43
    OK. All right. Stop the part.
  • 2:43 - 2:48
    So. That. That gets me every time.
  • 2:48 - 2:50
    So, that being the case, I, I have to
  • 2:50 - 2:54
    say, a lot of us have been hitting brick
  • 2:54 - 2:57
    walls. How many of you have been building
    something
  • 2:57 - 3:00
    relatively complex with Rails, and you sort
    of feel
  • 3:00 - 3:02
    like you've, you've gone up against a brick
    wall.
  • 3:02 - 3:05
    You can't make anymore forward progress and
    you feel
  • 3:05 - 3:07
    like you've been kind of, you know, so- yeah,
  • 3:07 - 3:09
    OK. So some hands are going up right.
  • 3:09 - 3:12
    And, and, and so it seems to me, like,
  • 3:12 - 3:15
    if there is that much talk about it, you
  • 3:15 - 3:17
    know, it seems like we often get the response
  • 3:17 - 3:19
    that, you know, we just need to run with
  • 3:19 - 3:23
    more passion at the wall. Run faster. And,
    and
  • 3:23 - 3:27
    if we just fully commit that we'll burst through
  • 3:27 - 3:28
    and we'll be in this sort of magical land
  • 3:28 - 3:32
    where everything works the way that it's supposed
    to,
  • 3:32 - 3:34
    and just don't fight so much, right?
  • 3:34 - 3:38
    I have to think that if so many of
  • 3:38 - 3:40
    us have kind of run into these sort of
  • 3:40 - 3:44
    problems, that maybe there's something there.
    Maybe there's, there's
  • 3:44 - 3:45
    some kind of an issue there, and I wanted
  • 3:45 - 3:48
    to give a few opinions about, you know, why
  • 3:48 - 3:49
    that might be.
  • 3:49 - 3:55
    So, Rails is a convention over configuration
    advocate, right.
  • 3:55 - 3:57
    That's, that's the big thing that we always
    talk
  • 3:57 - 3:59
    about, that we would prefer to have convention
    over
  • 3:59 - 4:04
    configuration. Now, conventions are really
    what, what opinions want
  • 4:04 - 4:07
    to be when they grow up, right. So, most
  • 4:07 - 4:10
    conventions have stemmed from an opinion.
    We hopefully share
  • 4:10 - 4:14
    the opinion, but I want to be clear that,
  • 4:14 - 4:16
    when I talk about the opinions that Rails
    has
  • 4:16 - 4:19
    today, I am not talking specifically about
    any members
  • 4:19 - 4:21
    of the core team. I'm not talking about the
  • 4:21 - 4:25
    people, though the software may in fact reflect
    opinions
  • 4:25 - 4:27
    of people, what I want to talk about is
  • 4:27 - 4:29
    what does the software tell us, right?
  • 4:29 - 4:33
    Because we know that Rails is opinionated
    software. So,
  • 4:33 - 4:35
    with that out of the way, let's go with
  • 4:35 - 4:38
    the first opinion that Rails, Rails has, that
    I
  • 4:38 - 4:41
    believe Rails has anyway, which is that code
    should
  • 4:41 - 4:45
    read like English. And we see this pretty
    frequently
  • 4:45 - 4:50
    in comparisons between straight-up Ruby versus
    Rails kind of
  • 4:50 - 4:51
    code, right, so.
  • 4:51 - 4:53
    Here's something that a lot of us actually
    like.
  • 4:53 - 4:54
    Like, I know this is one of the things
  • 4:54 - 4:56
    that hooked me on Rails right off the bat,
  • 4:56 - 4:57
    was like, oh, I can say, like, five dot
  • 4:57 - 5:01
    days ago, or, you know, because I'm writing
    something
  • 5:01 - 5:03
    in old English, I can say one dot fortnight.from_now.
  • 5:03 - 5:09
    That's very useful. Right.
  • 5:09 - 5:12
    So there's nothing particular, when we say
    like, one
  • 5:12 - 5:14
    dot megabyte, right, there's, there's nothing
    megabyte-y about the
  • 5:14 - 5:18
    number, right. It just does some multiplication.
  • 5:18 - 5:23
    Similarly, we have some, oh yeah. Fortnight.
    Yeah. Similarly,
  • 5:23 - 5:27
    we have some differences where we have something
    that
  • 5:27 - 5:30
    array already has, for instance, on it, like
    the
  • 5:30 - 5:31
    sh- I just found out it's called the shovel
  • 5:31 - 5:33
    operator. I always just said less than less
    than,
  • 5:33 - 5:35
    but whatever it is, right. So we have, like,
  • 5:35 - 5:38
    array less than less than object, right, and
    we've,
  • 5:38 - 5:40
    we've got that alias to append, so that we
  • 5:40 - 5:42
    can say append.
  • 5:42 - 5:44
    We have object dot in, so we can ask
  • 5:44 - 5:46
    whether an object is in an array include of
  • 5:46 - 5:48
    ask an array whether it has an object. Things
  • 5:48 - 5:50
    like that.
  • 5:50 - 5:54
    We have string methods that have been, you
    know,
  • 5:54 - 5:57
    kind of patched in for, for instance, the
    string
  • 5:57 - 5:58
    inquirer. That's one of my, one of my favorite
  • 5:58 - 6:01
    ones. Right in the middle there, we have a
  • 6:01 - 6:02
    check on the left. In Ruby, you simply ask
  • 6:02 - 6:06
    if the environment string equals production.
    But in Rails,
  • 6:06 - 6:09
    there's a thing called a string inquirer,
    which simply
  • 6:09 - 6:13
    patches method_missing so that you can actually
    say, OK.
  • 6:13 - 6:16
    Is the string actually containing the method
    that you
  • 6:16 - 6:19
    just sent minus the question mark? And so,
    that's
  • 6:19 - 6:21
    really all its doing - the thing on the
  • 6:21 - 6:23
    left.
  • 6:23 - 6:27
    Here's another one. So, in time, we can say
  • 6:27 - 6:30
    beginning_of_day, we can say midnight, we
    can sat at_midnight,
  • 6:30 - 6:34
    we can say at_beginning_of_day. We can say
    midday, noon,
  • 6:34 - 6:37
    at_midday, at_noon, at_middle_of_day, right.
    They're all the same thing,
  • 6:37 - 6:42
    and yet there's this really clean API that's
    exposed
  • 6:42 - 6:45
    this whole change thing, right. It's fairly
    discoverable. Like,
  • 6:45 - 6:47
    I could make a reasonable guess that if I
  • 6:47 - 6:50
    said change_minute to something, or if I said
    change
  • 6:50 - 6:52
    any piece of the time to something, it would
  • 6:52 - 6:55
    be able to do exactly what I ask it
  • 6:55 - 6:57
    to do just then. But instead we have these,
  • 6:57 - 7:00
    these aliases that allow us to write code
    that's
  • 7:00 - 7:01
    like English.
  • 7:01 - 7:04
    Now, when I go into a coffee shop and
  • 7:04 - 7:05
    I want something that's got a high caffeine
    content,
  • 7:05 - 7:07
    I may order one of these. You all know
  • 7:07 - 7:10
    what this is, right. This is coffee brewed
    by
  • 7:10 - 7:12
    forcing a small amount of nearly boiling water
    under
  • 7:12 - 7:15
    pressure through finely ground coffee beans.
    And that's what
  • 7:15 - 7:16
    I go up to the counter and ask for,
  • 7:16 - 7:16
    right.
  • 7:16 - 7:19
    Nope. You know. They'd probably go, you mean
    an
  • 7:19 - 7:24
    espresso, right? Because espresso is what
    we call a
  • 7:24 - 7:29
    loan word. We borrowed that word from Italian
    because
  • 7:29 - 7:31
    it was concise, it was a good way to
  • 7:31 - 7:34
    say what it was that, that we wanted to
  • 7:34 - 7:36
    say without all of those words, right.
  • 7:36 - 7:40
    Ruby is a language in-and-of-itself. It borrows
    from English
  • 7:40 - 7:43
    where it makes sense. But it is my opinion,
  • 7:43 - 7:45
    anyway, that if there is a concise way to
  • 7:45 - 7:47
    say something in Ruby, we don't necessarily
    need to
  • 7:47 - 7:50
    borrow a loan word in English. You know how
  • 7:50 - 7:51
    you sit across the table from that guy who
  • 7:51 - 7:53
    always like to use a foreign word for something
  • 7:53 - 7:57
    just to sound clever, right? Right. That's
    what we're
  • 7:57 - 8:00
    doing, right. Like, it doesn't make a lot
    of
  • 8:00 - 8:01
    sense.
  • 8:01 - 8:04
    Now, here's one you may initially disagree
    with. I
  • 8:04 - 8:06
    believe that Rails believes that models descend
    from ActiveRecord,
  • 8:06 - 8:10
    or at the very least an ORM. Now, if
  • 8:10 - 8:12
    you disagree with me, I have three words for
  • 8:12 - 8:17
    you. Rails generate model.
  • 8:17 - 8:20
    What do you get? You get an ActiveRecord subclass,
  • 8:20 - 8:23
    right. Now, you might say, well that's silly,
    right.
  • 8:23 - 8:26
    But this is the first exposure that Rails
    developers
  • 8:26 - 8:29
    are likely to have to what goes in a
  • 8:29 - 8:31
    model's directory, and I have talked to extremely
    smart
  • 8:31 - 8:34
    developers who have told me that they went
    a
  • 8:34 - 8:37
    number of years before they realized they
    could stick
  • 8:37 - 8:40
    plain-old Ruby classes in app models, because
    they just
  • 8:40 - 8:43
    thought that, that's not what models are.
    Right?
  • 8:43 - 8:45
    And so, rightfully so then, Rails believes
    that the
  • 8:45 - 8:48
    data is the domain, right. That's the ActiveRecord
    pattern.
  • 8:48 - 8:50
    That's the whole point of it. And if you
  • 8:50 - 8:52
    don't believe me, I'll show you some README
    information,
  • 8:52 - 8:53
    right.
  • 8:53 - 8:56
    The prime directive is that we're minimizing
    the code
  • 8:56 - 9:00
    needed to build a real-world domain model.
    Lots of
  • 9:00 - 9:03
    reflection and runtime extension is the understatement
    of the
  • 9:03 - 9:10
    year. And magic is not inherently a bad word.
  • 9:10 - 9:14
    Now, what this really comes down to is, is
  • 9:14 - 9:18
    Rails was very much a reaction to very configuration-heavy
  • 9:18 - 9:24
    frameworks in Java, XML files and the like.
    Big
  • 9:24 - 9:27
    reaction to that, right. So what we had determined
  • 9:27 - 9:30
    at that point was that configuration is the
    devil,
  • 9:30 - 9:34
    right. And once you have, once you have determined
  • 9:34 - 9:36
    that there is a greater evil out there, then
  • 9:36 - 9:38
    a lot of lesser evils start to seem pretty
  • 9:38 - 9:41
    great by comparison, right. So you can rationalize
    yourself
  • 9:41 - 9:44
    into a really tricky spot.
  • 9:44 - 9:47
    And so, our goal is to be able to
  • 9:47 - 9:51
    write class Post inherits from ActiveRecord::Base
    end and have
  • 9:51 - 9:55
    magic happen, right. Like, for instance, we
    infer, and
  • 9:55 - 9:56
    I want to talk a little about, about one
  • 9:56 - 9:59
    thing that we do in that case, right. We
  • 9:59 - 10:03
    infer what the attributes should be on that,
    on
  • 10:03 - 10:05
    that model without writing a single line of
    code.
  • 10:05 - 10:08
    Now, there's a problem with that. Namely,
    that in
  • 10:08 - 10:10
    order to infer the attribute names, you must
    first
  • 10:10 - 10:13
    invent the universe. So I want to walk us
  • 10:13 - 10:17
    through what that looks like. We're gonna
    do one
  • 10:17 - 10:19
    deep dive into some Rails internals, and then
    I
  • 10:19 - 10:21
    promise we'll come back up for air and we'll,
  • 10:21 - 10:25
    we'll talk about happy things.
  • 10:25 - 10:29
    So, so you might imagine pretty, pretty early
    on,
  • 10:29 - 10:33
    that we're gonna go ahead and initialize a
    module,
  • 10:33 - 10:35
    and we're gonna actually have a module to
    store
  • 10:35 - 10:37
    our attribute methods in. That's actually
    something I kind
  • 10:37 - 10:40
    of like, right, because as a Rubyist, I expect
  • 10:40 - 10:41
    to be able to call super if I define
  • 10:41 - 10:42
    my own method on the class, so that makes
  • 10:42 - 10:44
    a lot of sense, right.
  • 10:44 - 10:45
    So if we look at what happens when we
  • 10:45 - 10:48
    generate the module, we have a new anonymous
    module
  • 10:48 - 10:50
    that extends Mutex, cause we don't want to
    be
  • 10:50 - 10:53
    modifying the module from two different threads.
  • 10:53 - 10:56
    And, then in method_missing, we have this
    handy little
  • 10:56 - 11:02
    hook that defines the attribute methods, right.
    And so,
  • 11:02 - 11:06
    in method_missing, we call this every single
    time, right.
  • 11:06 - 11:09
    And the idea being that once we've defined
    the
  • 11:09 - 11:11
    methods, they're, we're not gonna hit method_missing,
    at least
  • 11:11 - 11:14
    for those methods anymore.
  • 11:14 - 11:15
    And so we bail out, if, in fact, we've
  • 11:15 - 11:21
    already generated them. And we call super
    with column
  • 11:21 - 11:24
    names, right. Now, where do we get column
    names
  • 11:24 - 11:27
    from? Well, it's not there. In fact, method_missing
    was
  • 11:27 - 11:30
    the only thing that actually sits on, on the
  • 11:30 - 11:32
    instance level. The rest of the stuff that
    we're
  • 11:32 - 11:33
    gonna be looking at sits on the singleton.
    It
  • 11:33 - 11:36
    sits on the subclass of ActiveRecord itself
    as a
  • 11:36 - 11:37
    class method.
  • 11:37 - 11:41
    So, when we call super, we're actually calling
    super
  • 11:41 - 11:45
    into ActiveModels. Definition of defining
    attributes, right. So we're
  • 11:45 - 11:48
    saying, define attributes methods from ActiveModel.
    We're passing it
  • 11:48 - 11:51
    the column names. So here's column names.
    Well, column
  • 11:51 - 11:55
    names is, again, a singleton method. It knows
    that
  • 11:55 - 11:58
    it needs columns, right. And below here, we
    have
  • 11:58 - 11:58
    columns.
  • 11:58 - 12:02
    Well, columns needs the connections, for starters,
    to the
  • 12:02 - 12:04
    database to talk, to figure out, you know,
    what
  • 12:04 - 12:05
    table it's gonna read from. And it also needs
  • 12:05 - 12:08
    to determine table name, right. So now we
    need
  • 12:08 - 12:11
    to know the table name. So we don't have
  • 12:11 - 12:14
    the table name yet, so we call a reset
  • 12:14 - 12:18
    table name, and most of the time I'm gonna
  • 12:18 - 12:21
    skip past some of the, some of the more
  • 12:21 - 12:23
    convoluted things and just talk about the
    compute table
  • 12:23 - 12:24
    name, right. So we have to compute the table
  • 12:24 - 12:27
    name. It makes sense, right?
  • 12:27 - 12:29
    So, this is kind of a big method. Hopefully
  • 12:29 - 12:31
    you all can see the, the part that matters,
  • 12:31 - 12:36
    which is we call undecorated table name with
    the,
  • 12:36 - 12:38
    again, we're sitting on the class. So name
    refers
  • 12:38 - 12:40
    to class dot name, right. The string name
    of
  • 12:40 - 12:43
    the class. The full module name.
  • 12:43 - 12:47
    And, undecorated table name basically does
    exactly what you
  • 12:47 - 12:50
    see here. Let's say we have a namespace model,
  • 12:50 - 12:55
    Conferences::RailsConf becomes RailsConf becomes
    rails underscore conf becomes rails_confs,
  • 12:55 - 12:59
    OK. Which is great. And then, of course, if
  • 12:59 - 13:01
    we have Animals::Moose it becomes Moose it
    becomes moose
  • 13:01 - 13:05
    it becomes mooses. Which makes lots of sense,
    right?
  • 13:05 - 13:12
    Well, that means we need to handle irregular
    pluralization.
  • 13:12 - 13:14
    So we check and we see whether or not
  • 13:14 - 13:19
    there's a default pluralization to find for
    moose. There
  • 13:19 - 13:21
    is not. There, there, there are some interesting
    ones,
  • 13:21 - 13:24
    I think. We've got, like, sheep. We do have
  • 13:24 - 13:28
    sheep, so we're at least in the ball park.
  • 13:28 - 13:31
    We have jeans. We have fish. But we don't
  • 13:31 - 13:32
    have moose.
  • 13:32 - 13:36
    So, we go into an initializer and we set
  • 13:36 - 13:43
    inflect.uncountable "moose" and then it works,
    right. But. Configuration.
  • 13:44 - 13:46
    Or we can say self dot table_name equal 'moose'
  • 13:46 - 13:50
    and then bypass all of that altogether, right.
    But,
  • 13:50 - 13:52
    again, configuration.
  • 13:52 - 13:55
    Now, if configuration is the devil and magic
    is
  • 13:55 - 13:59
    the goal, then we have to think to ourselves,
  • 13:59 - 14:01
    what is, what is magic, really? And, and an
  • 14:01 - 14:06
    enjoyable magic trick is basically willful
    suspension of disbelief,
  • 14:06 - 14:09
    right. So, that is, if this magician came
    up
  • 14:09 - 14:12
    and said, I'm going to saw my assistant in
  • 14:12 - 14:15
    half, and you didn't think, there's a trick
    here,
  • 14:15 - 14:17
    like, it's based in the rules of reality,
    like,
  • 14:17 - 14:19
    there's something going on. It would be pretty
    horrified,
  • 14:19 - 14:22
    right. We'd be like, I don't be- where have
  • 14:22 - 14:24
    I gone? Like, what is going on here, right?
  • 14:24 - 14:27
    And so there is this level where we would
  • 14:27 - 14:30
    do better to consider, how can we root this
  • 14:30 - 14:33
    kind of magic in some reality that the average
  • 14:33 - 14:35
    person is going to be able to understand?
    And
  • 14:35 - 14:38
    then kind of build on that knowledge, sort
    of
  • 14:38 - 14:40
    scaffold, if you will. And, otherwise, you
    end up
  • 14:40 - 14:42
    with what I, what I referred to as douche
  • 14:42 - 14:44
    bag magic, which magic that bites you, magic
    that
  • 14:44 - 14:47
    screws you over in all sorts of wonderful
    ways.
  • 14:47 - 14:52
    So, let's imagine, for a moment, a world,
    a
  • 14:52 - 14:55
    world where we do have magic that we can
  • 14:55 - 15:01
    understand. And, so let's just say we have
    ImaginaryRecord::Record
  • 15:01 - 15:05
    that always asks us to configure a table name.
  • 15:05 - 15:07
    That always asks us to define the attributes
    in
  • 15:07 - 15:11
    a very mapper style, data mapper style. Right?
  • 15:11 - 15:13
    Given an attribute name, tell it's how its
    to
  • 15:13 - 15:14
    load the attributes. Tell it how to load the
  • 15:14 - 15:15
    attributes. Maybe some other stuff. We don't,
    we're just,
  • 15:15 - 15:19
    we're imagining here, right. We're, we're
    just in your
  • 15:19 - 15:20
    imagination.
  • 15:20 - 15:23
    And then let's say that we have a MagicRecord
  • 15:23 - 15:26
    that inherits from the ImaginaryRecord::Record,
    and does all the
  • 15:26 - 15:31
    same stuff that we did before, except it calls
  • 15:31 - 15:34
    these methods on the class in order to set
  • 15:34 - 15:36
    the table name programmatically, in order
    to set the
  • 15:36 - 15:37
    attributes programmatically, right.
  • 15:37 - 15:41
    Well, that would be pretty cool. We would
    have
  • 15:41 - 15:43
    to make some trade offs, but we'd basically
    get
  • 15:43 - 15:46
    to the point where we could do something like
  • 15:46 - 15:48
    inherit from MagicRecord and get the exact
    same behavior
  • 15:48 - 15:52
    as we wanted. But as a freebie, now we
  • 15:52 - 15:54
    have the ability to drop down another layer,
    if
  • 15:54 - 15:57
    we want. And to actually define this stuff
    with
  • 15:57 - 15:58
    less magic.
  • 15:58 - 16:02
    And you say, well that's great. So that's
    attributes.
  • 16:02 - 16:05
    We kind of understand that. That's pretty
    simple, right.
  • 16:05 - 16:08
    Big whoop. ActiveRecord also does all these
    other things,
  • 16:08 - 16:11
    I mean, you know, it's got like attribute
    typecasting
  • 16:11 - 16:14
    and associations and serializations and secure
    passwords and transactions
  • 16:14 - 16:17
    and macro reflection and nested attributes,
    time stamps, lifecycle
  • 16:17 - 16:21
    callbacks, validations, dirty tracking, mass
    assignment, sanitation, to name
  • 16:21 - 16:24
    some, and oh, by the way, we have querying
  • 16:24 - 16:27
    and persisting, right. That's kind of a important
    thing
  • 16:27 - 16:30
    in a persistence library.
  • 16:30 - 16:34
    And so, I say yeah. Yeah, exactly. That's.
    That's
  • 16:34 - 16:36
    an interesting problem that we have, right.
    Because they're
  • 16:36 - 16:38
    all kind of living in one place, and how
  • 16:38 - 16:43
    do you expose this kind of interface, this
    kind
  • 16:43 - 16:47
    of way of interacting with, with your library,
    to
  • 16:47 - 16:49
    cover all of these things. And my answer would
  • 16:49 - 16:51
    be basically that you, you don't. You, you
    allow
  • 16:51 - 16:53
    this to tell you maybe I've got a crazy
  • 16:53 - 16:54
    idea.
  • 16:54 - 16:59
    So, this is the ancestry chain of, of an
  • 16:59 - 17:02
    ActiveRecord::Base subclass. I just wanted
    to show it to
  • 17:02 - 17:08
    you real quickly. Now, yeah. Yeah. Three cheers
    for
  • 17:08 - 17:12
    the, for the ancestry chain of ActieRecord::Base.
    So, somebody's
  • 17:12 - 17:15
    clapping. Oh no. Right.
  • 17:15 - 17:18
    SO, in Rails we call this clarity. You may
  • 17:18 - 17:25
    have heard that earlier. Because API surface
    area is
  • 17:26 - 17:29
    irrelevant. We don't care about that. In other
    words,
  • 17:29 - 17:33
    the Single Responsibility Principle is super
    simple for sufficiently
  • 17:33 - 17:38
    large values of responsibility. Like, if you're
    responsibility is
  • 17:38 - 17:41
    to do everything, then you just say, OK, gotta
  • 17:41 - 17:44
    do everything. It's gotta work, right. That's
    my responsibility.
  • 17:44 - 17:47
    Well, it works. All right. Done.
  • 17:47 - 17:50
    And so awhile back, actually last weekend,
    I Tweeted
  • 17:50 - 17:55
    some of these statistics about an observation
    on an,
  • 17:55 - 17:59
    a brand new Rails 4.1 app, what a subclass
  • 17:59 - 18:02
    of ActiveRecord has, what the view has, and
    what
  • 18:02 - 18:06
    the controller has in terms of ancestors,
    public protected
  • 18:06 - 18:09
    class methods, public protected instance methods,
    and same for
  • 18:09 - 18:11
    private methods, right.
  • 18:11 - 18:14
    Now, look. It may very well be that this
  • 18:14 - 18:16
    is exactly the API size that we need. I'm
  • 18:16 - 18:18
    not gonna argue that one way or the other
  • 18:18 - 18:21
    right now. But what I will say is that
  • 18:21 - 18:24
    there are other ways to get there. Just because
  • 18:24 - 18:25
    we want these methods does not mean they all
  • 18:25 - 18:28
    actually have to be implemented in modules
    that are
  • 18:28 - 18:32
    included onto the class.
  • 18:32 - 18:34
    And so what I'm getting at is that, it's
  • 18:34 - 18:37
    very, very hard to keep track of just what
  • 18:37 - 18:40
    you're doing. I've been writing Rails for
    over seven
  • 18:40 - 18:42
    years. I'm not exactly sure how long at this
  • 18:42 - 18:46
    point. But, I know that, since I've been doing
  • 18:46 - 18:49
    it, I still have to have documentation open
    most
  • 18:49 - 18:51
    of the time when I'm doing anything serious.
    Like,
  • 18:51 - 18:54
    maybe I'm just dumb. Possible. I don't know.
    But
  • 18:54 - 18:57
    I need documentation. It's a really big namespace
    to
  • 18:57 - 18:59
    try to keep in your head all at one
  • 18:59 - 19:00
    point.
  • 19:00 - 19:05
    So, this is on, online at GitHub, and you
  • 19:05 - 19:07
    are free to do science to verify my empirical
  • 19:07 - 19:11
    observations and see whether or not they are
    accurate,
  • 19:11 - 19:13
    and I would love to see PRs to this
  • 19:13 - 19:17
    repo, actually, with, you know, different
    versions of Rails
  • 19:17 - 19:19
    to see how things have changed, complexity-wise.
  • 19:19 - 19:22
    Now, it's not enough really for ActiveRecord
    to just
  • 19:22 - 19:26
    do this on its own. It actually encourages
    us
  • 19:26 - 19:31
    to do this, right. Rails has this whole helper
  • 19:31 - 19:34
    thing, right. And, let me give you an example
  • 19:34 - 19:36
    of something I actually encountered and, I'm
    embarrassed to
  • 19:36 - 19:38
    say, spent like half a day trouble shooting
    with
  • 19:38 - 19:40
    the, with helpers.
  • 19:40 - 19:44
    So, I decided I had a really great idea,
  • 19:44 - 19:46
    and I was gonna use something that I heard
  • 19:46 - 19:49
    that OO developers like to do, which is polymorphism,
  • 19:49 - 19:50
    and use it at the view layer, right. And
  • 19:50 - 19:54
    I'm like, I can have something that is summarizable,
  • 19:54 - 19:56
    and so I might have a helper for posts
  • 19:56 - 19:58
    that's summary, and I might have a helper
    for
  • 19:58 - 20:00
    reviews that's summary.
  • 20:00 - 20:03
    And I can share a partial that prints that
  • 20:03 - 20:06
    summary in an appropriate way for that particular
    thing,
  • 20:06 - 20:08
    right. That seemed pretty cool. So this is
    how
  • 20:08 - 20:12
    it would look in a partial. And in development
  • 20:12 - 20:16
    it worked wonderfully. It worked exactly the
    way I
  • 20:16 - 20:18
    expected. And then I deployed to production.
  • 20:18 - 20:24
    Now, how many of you think it worked? Right.
  • 20:24 - 20:26
    How many of you think it didn't work. Well,
  • 20:26 - 20:29
    it's kind of a trick question, because honestly
    you
  • 20:29 - 20:31
    can't really tell me, because you don't have
    enough
  • 20:31 - 20:35
    information right now. Because there's this
    thing, right.
  • 20:35 - 20:39
    OK, so, seven years ago, there was a commit
  • 20:39 - 20:41
    to Rails that said, we are going to make
  • 20:41 - 20:43
    it default assumption you want all helpers
    all the
  • 20:43 - 20:49
    time. No comment.
  • 20:49 - 20:52
    And, for a long period of time, I'd like
  • 20:52 - 20:53
    to imagine it was some kind of a dark
  • 20:53 - 20:56
    age in Rails. There was really no way to
  • 20:56 - 20:58
    opt out of this, per se, until a patch
  • 20:58 - 21:00
    came in that added include all helpers as
    a
  • 21:00 - 21:04
    configuration option. So I thought, this is
    great. I
  • 21:04 - 21:07
    found this, now I found this after hours of
  • 21:07 - 21:10
    searching, like, because I just somehow missed
    the memo
  • 21:10 - 21:12
    that we had done that. It was way back
  • 21:12 - 21:13
    in 2.3, like, this has been the way for
  • 21:13 - 21:14
    awhile, right.
  • 21:14 - 21:17
    But, like I just kind of assume, like, it's
  • 21:17 - 21:22
    named post_helper, it should help posts. Not,
    like, other
  • 21:22 - 21:24
    things. But that's not how it works. So there's
  • 21:24 - 21:28
    this kind of big namespace, right. And so,
    I
  • 21:28 - 21:31
    would recommend that nearly all of you consider
    adding
  • 21:31 - 21:35
    this to to your application dot rb. You will
  • 21:35 - 21:38
    be much more sane for it. If you're going
  • 21:38 - 21:40
    to use helpers, at the very least, having
    a
  • 21:40 - 21:42
    namespace that you can kind of control. If
    you
  • 21:42 - 21:44
    want to be available to all controllers, then
    throw
  • 21:44 - 21:47
    it in application_helper or have a module.
    You can
  • 21:47 - 21:49
    still use modules, I hear. It works.
  • 21:49 - 21:51
    Now, we did all this in the name of
  • 21:51 - 21:55
    convenience, right. Convenience is, is going
    to trump everything
  • 21:55 - 21:58
    else. We want convenient usage at expense
    of anything
  • 21:58 - 22:03
    else. And, you know, so I own a house.
  • 22:03 - 22:06
    And I think to myself often that, you know,
  • 22:06 - 22:10
    when nature calls, I have, like, to get up
  • 22:10 - 22:12
    and like, go to a special room to go
  • 22:12 - 22:15
    do my business, right.
  • 22:15 - 22:16
    [laughter]
  • 22:16 - 22:20
    And I mean that's really inconvenient. So
    like, why
  • 22:20 - 22:23
    don't I just install a toilet, like, in every
  • 22:23 - 22:26
    room in the house, right? Because then, like,
    if
  • 22:26 - 22:29
    I'm watching the tube, it doesn't matter you
    know.
  • 22:29 - 22:31
    Do my thing. It's all good. but the problem
  • 22:31 - 22:34
    with that is, right, that first off, you've
    got,
  • 22:34 - 22:37
    like, plumbing now to help support this, this
    aspiration
  • 22:37 - 22:41
    of having a toilet in every room. And plumbers
  • 22:41 - 22:43
    are expensive and, like, stuff breaks and
    then it's
  • 22:43 - 22:45
    like, I've got a leak and I've got damage
  • 22:45 - 22:48
    and stuff, and then the other problem is,
    like,
  • 22:48 - 22:51
    every room is a toilet, right.
  • 22:51 - 22:56
    So, I would encourage you to consider that
    if
  • 22:56 - 22:59
    this is kind of what you're looking for, if
  • 22:59 - 23:03
    a giant namespace of, of, of methods and functions
  • 23:03 - 23:05
    is what you would really like to have, then
  • 23:05 - 23:10
    have I got the language for you.
  • 23:10 - 23:16
    It is super convenient, like, everything is
    at arm's
  • 23:16 - 23:18
    length. What's that? You want to do something
    with
  • 23:18 - 23:21
    a string and an array, yeah, doesn't matter.
    MySQL,
  • 23:21 - 23:25
    sure. Absolutely. I mean, just a thought.
  • 23:25 - 23:30
    So now another, another Rails opinion is,
    who needs
  • 23:30 - 23:36
    classes when we've got modules? And I say
    this
  • 23:36 - 23:40
    primarily because of one interesting piece
    of code, which
  • 23:40 - 23:47
    is ActiveSupport::Concern. So, ActiveSupport::Concern
    you may think is mainly
  • 23:48 - 23:50
    for having a convention around having a class
    methods
  • 23:50 - 23:54
    module inside your module. And instance methods
    and so
  • 23:54 - 23:57
    forth. But it's not.
  • 23:57 - 24:00
    The problem the it's designed to solve is
    that,
  • 24:00 - 24:03
    in this world, the Ruby world, the one that
  • 24:03 - 24:07
    we live in lots of times, we, we actually
  • 24:07 - 24:09
    would have to include. There's a lot of extension
  • 24:09 - 24:11
    onto a class, right, when you include a module
  • 24:11 - 24:13
    in the Rails world. Like, a lot of the
  • 24:13 - 24:15
    modules that Rails is built on go and do
  • 24:15 - 24:18
    metaprogramming and add methods to the singleton
    or whatever
  • 24:18 - 24:20
    onto the class itself, right.
  • 24:20 - 24:22
    And if you're adding stuff to the singleton,
    then
  • 24:22 - 24:25
    it's not sufficient for you to go ahead and,
  • 24:25 - 24:28
    and do that in a module that is itself
  • 24:28 - 24:30
    included, right. Because when it gets included
    in the
  • 24:30 - 24:32
    module, it modifies the module singleton,
    not the class
  • 24:32 - 24:34
    singleton. With me so far?
  • 24:34 - 24:37
    Right. This is a huge problem. So. So let's
  • 24:37 - 24:40
    solve it. Now, we have this ability to have
  • 24:40 - 24:45
    dependencies that get trapped by ActiveSupport::Concern,
    so that each
  • 24:45 - 24:48
    singleton knows what, what its dependencies
    are, and then
  • 24:48 - 24:52
    at the time that you include the, the dependency
  • 24:52 - 24:54
    that you're really looking for, it can also
    go
  • 24:54 - 24:56
    back and include into your module all the
    other
  • 24:56 - 24:57
    ones that it needed, and so then that way
  • 24:57 - 25:00
    they can do their metaprogramming magic on
    your singleton
  • 25:00 - 25:02
    instead of their singleton.
  • 25:02 - 25:05
    It's great. And it's, you know, so what it
  • 25:05 - 25:07
    is is that there was this, this, this problem.
  • 25:07 - 25:12
    There was this problem that we had. And, you
  • 25:12 - 25:15
    know, we decided to bundle a, a, a free
  • 25:15 - 25:19
    razor with every yak. And, I mean, I guess
  • 25:19 - 25:23
    that's one solution, sure. And so, so I've
    been
  • 25:23 - 25:25
    thinking a lot about this lately.
  • 25:25 - 25:27
    And one of the things that sort of bothers
  • 25:27 - 25:30
    me is that, you know, we're regularly told
    not
  • 25:30 - 25:34
    to, not to fight the framework, right. But
    our
  • 25:34 - 25:39
    framework pretty actively fights the language.
    There are things
  • 25:39 - 25:42
    that the language is saying, hey, this might
    be
  • 25:42 - 25:43
    crazy. Maybe you don't want to do this. And
  • 25:43 - 25:47
    we're like, I won't do what you tell me.
  • 25:47 - 25:51
    I will do exactly what I want to do.
  • 25:51 - 25:55
    And it encourages this, this kind of module-centric
    design.
  • 25:55 - 25:57
    Limits the entry points that we can have.
    So,
  • 25:57 - 25:59
    you know, Yehuda made a really great point,
    actually,
  • 25:59 - 26:01
    when he talked about that we're kind of on
  • 26:01 - 26:04
    the 400th story, right. And, and I agree.
    We
  • 26:04 - 26:07
    are, we are like way up here in terms
  • 26:07 - 26:08
    of abstraction.
  • 26:08 - 26:12
    But, like, I've heard rumors that, like, maybe,
    on
  • 26:12 - 26:15
    most buildings, like, those other floors like
    have people
  • 26:15 - 26:18
    in them, and like, they do things. And like
  • 26:18 - 26:21
    maybe you can not just be trapped on the
  • 26:21 - 26:23
    400th floor forever, but maybe you want to
    like
  • 26:23 - 26:26
    go down, cause like, I heard, like, on floor
  • 26:26 - 26:29
    350 there's like an ice cream store, and like,
  • 26:29 - 26:32
    I like ice cream. Right. So maybe I want
  • 26:32 - 26:33
    to go down and have some ice cream.
  • 26:33 - 26:37
    But, like, I can't. Because I could only do
  • 26:37 - 26:40
    things with things that are instantiatable,
    right. And if
  • 26:40 - 26:42
    everything is a module, I'm not instantiating
    that. I
  • 26:42 - 26:45
    guess I could write my own class and include
  • 26:45 - 26:47
    half of what's going on, but that seems like
  • 26:47 - 26:49
    I'm just perpetuating the problem.
  • 26:49 - 26:54
    So, here's another, here's another Rails opinion.
    Rails believes
  • 26:54 - 26:59
    that your conventions suck. First example
    is, now, I
  • 26:59 - 27:01
    know it's gonna be hard for you to believe,
  • 27:01 - 27:06
    but there were conventions for building applications
    before Rails
  • 27:06 - 27:09
    came out. Like, people were actually building
    - I
  • 27:09 - 27:13
    know, it's a little weird. They were building
    web
  • 27:13 - 27:14
    applications, and, and one of the things that
    they
  • 27:14 - 27:16
    used was JavaScript, right.
  • 27:16 - 27:20
    Now, love or hate JavaScript, it, it, it's
    here
  • 27:20 - 27:22
    to stay at this point. We, we, we're gonna
  • 27:22 - 27:25
    be writing it. And so, Rails, once upon a
  • 27:25 - 27:28
    time - you guys remember this? You remember
    this?
  • 27:28 - 27:32
    Like, let's, so. If this was before your time
  • 27:32 - 27:35
    with Rails, we had, we had this great idea,
  • 27:35 - 27:40
    right, which is, JavaScript's a pain to write.
    And
  • 27:40 - 27:44
    let's write Ruby that writes JavaScript instead.
    And so
  • 27:44 - 27:47
    we called that RJS, and you could write these,
  • 27:47 - 27:48
    there were these methods that if you said
    page
  • 27:48 - 27:51
    dot whatever, it would generate some JavaScript.
    And you
  • 27:51 - 27:53
    could go look at the JavaScript and it was,
  • 27:53 - 27:55
    you know, about what you would expect generated
    JavaScript
  • 27:55 - 27:57
    to be.
  • 27:57 - 28:00
    And then we decided, you know, OK, maybe that
  • 28:00 - 28:02
    was crazy. But we're still not happy with
    the
  • 28:02 - 28:07
    whole state that we have to write JavaScript.
    So
  • 28:07 - 28:10
    we decided to use JavaScript that looks like
    Ruby,
  • 28:10 - 28:15
    right. OK. Great. All right. Fine. I can see
  • 28:15 - 28:17
    that.
  • 28:17 - 28:21
    And then, at that point, now, we were at
  • 28:21 - 28:24
    a point where there's this other convention,
    where like,
  • 28:24 - 28:27
    if you're using jQuery, and many of us are,
  • 28:27 - 28:31
    like, let's say, let's say that I want to
  • 28:31 - 28:34
    render, I have decided I'm gonna be on the
  • 28:34 - 28:36
    straight and narrow, I am going to render
    my,
  • 28:36 - 28:40
    my, my views in Ruby. I want to render
  • 28:40 - 28:42
    static html that I spit out. But I need
  • 28:42 - 28:46
    some dynamic parts, and so I'm gonna render
    some,
  • 28:46 - 28:49
    some JavaScript as well that's gonna do some
    things,
  • 28:49 - 28:50
    right. Use jQuery.
  • 28:50 - 28:52
    This is a pretty standard convention, right.
    I mean,
  • 28:52 - 28:53
    how many of you have this exact code in
  • 28:53 - 28:56
    your code base somewhere, right. If you're
    not raising
  • 28:56 - 29:01
    your hand, I'm very shocked. So, we thought,
    you
  • 29:01 - 29:02
    know, that's, that's great. It's really cool
    to be
  • 29:02 - 29:05
    able to hook into $(document).ready and do
    some stuff.
  • 29:05 - 29:09
    And so, so Rails said, that's a horrible idea.
  • 29:09 - 29:13
    You should use Turbolinks. And so now, look,
    you
  • 29:13 - 29:16
    can yank Turbolinks out of your gemfile and
    that's
  • 29:16 - 29:19
    true. You can do that, right. But it's my
  • 29:19 - 29:23
    opinion that convention should probably not
    completely break someone's
  • 29:23 - 29:25
    expectations if they're doing server-side
    rendering, and this is
  • 29:25 - 29:27
    something that you, you are going to run into
  • 29:27 - 29:29
    if you're just starting out with Rails. You'll
    be
  • 29:29 - 29:30
    like, well, why isn't this doing? Well, we
    don't
  • 29:30 - 29:32
    fire. We don't fire the doc.
  • 29:32 - 29:35
    No, there are, there are other gems that will
  • 29:35 - 29:37
    make this seem like that is not the case.
  • 29:37 - 29:39
    But the fact of the matter is, it's gonna
  • 29:39 - 29:42
    bite you. So, so Rails said, you know, we
  • 29:42 - 29:46
    have opinions about how you should write JavaScript.
  • 29:46 - 29:48
    Rails has opinions about how you should maintain
    data
  • 29:48 - 29:55
    integrity as well. And so in the Rails world,
  • 29:55 - 29:57
    this is a typical, typical way to handle some,
  • 29:57 - 30:00
    some validation of data integrity, right.
    Maybe you make
  • 30:00 - 30:03
    sure that you have a customer, and you need
  • 30:03 - 30:07
    a unique reference number, and you have a
    typo
  • 30:07 - 30:08
    there.
  • 30:08 - 30:11
    validates_associates. Validates :associates
    and :line_items, right. And you won't
  • 30:11 - 30:16
    save an order unless its :line_items are valid.
    And
  • 30:16 - 30:20
    that's really interesting to me, because objects,
    unfortunately, you
  • 30:20 - 30:23
    know, they don't really understand their relations
    to other
  • 30:23 - 30:26
    things very well, because those live somewhere
    else. They're
  • 30:26 - 30:29
    in the data store separate, right. And, you
    know,
  • 30:29 - 30:31
    I, I really think that it would be great,
  • 30:31 - 30:34
    like, if there was some sort of a system
  • 30:34 - 30:36
    that we could use. So, like, I don't know,
  • 30:36 - 30:41
    it would be like a system for managing, I
  • 30:41 - 30:48
    don't know, relational data, maybe? I don't
    know.
  • 30:48 - 30:51
    It would be great if we had one of
  • 30:51 - 30:55
    those. And it turns out that, like, we do.
  • 30:55 - 30:59
    And they are, like, super good at understanding
    relationships
  • 30:59 - 31:03
    between data. And they are super good at,
    at
  • 31:03 - 31:05
    validating the data that goes in and out and
  • 31:05 - 31:10
    ensuring that things are atomic, right, and
    that, that
  • 31:10 - 31:12
    our updates are not gonna run into race conditions
  • 31:12 - 31:14
    and the like, right?
  • 31:14 - 31:16
    I mean, and I'm talking about, even the, let's
  • 31:16 - 31:22
    say, less than civilized versions of databases,
    those are,
  • 31:22 - 31:24
    those are also able, able to do pretty well
  • 31:24 - 31:28
    at this. Because, Ruby, the Ruby land has
    to
  • 31:28 - 31:30
    cross a process boundary to know any of this
  • 31:30 - 31:33
    stuff, and that's pretty lossy, really.
  • 31:33 - 31:35
    So, I don't think it would be fair, you
  • 31:35 - 31:37
    know, I've griped a lot at this point about
  • 31:37 - 31:38
    a few of the opinions that I think Rails
  • 31:38 - 31:41
    has, and I feel like you came here hoping
  • 31:41 - 31:43
    that I would offer you some solutions, right.
    I
  • 31:43 - 31:48
    want to show you some solutions that I've
    found.
  • 31:48 - 31:54
    These are my solutions. They look pretty nice,
    I
  • 31:54 - 31:54
    think.
  • 31:54 - 31:55
    Science.
  • 31:55 - 32:00
    No. So, I've been doing this thing lately,
    and
  • 32:00 - 32:05
    I'm calling it IDD. And that stands for Ignorance-Driven
  • 32:05 - 32:11
    Development. It's really blissful. And it's
    this, this crazy
  • 32:11 - 32:16
    idea that, like, maybe starting with Rails
    g model,
  • 32:16 - 32:19
    like starting out thinking about your persistence,
    is maybe
  • 32:19 - 32:21
    not the way to go.
  • 32:21 - 32:23
    If you're thinking about your persistence
    for - I
  • 32:23 - 32:26
    mean, I can tell you, all right. Raise your
  • 32:26 - 32:30
    hand if you have stopped to consider what
    your
  • 32:30 - 32:32
    database scheme, schema is gonna look like
    after you've
  • 32:32 - 32:34
    typed Rails g model, and you're just kind
    of
  • 32:34 - 32:37
    frozen there, like, crap. Analysis paralysis
    sets in, right.
  • 32:37 - 32:41
    Because, like, migrations are a pain and databases
    are,
  • 32:41 - 32:43
    ew, yuck. We want to do everything in Ruby,
  • 32:43 - 32:44
    right?
  • 32:44 - 32:46
    And, and so that's a problem, right, because
    I
  • 32:46 - 32:48
    don't necessarily know what the best way to
    store
  • 32:48 - 32:50
    my data is off the top of my head,
  • 32:50 - 32:53
    right? I may find that out as I go.
  • 32:53 - 32:55
    So here's a crazy idea.
  • 32:55 - 32:58
    Start with Ruby and ignore persistence, off
    the bat.
  • 32:58 - 33:01
    Like, probably that is not your domain. Your
    domain
  • 33:01 - 33:03
    is not to be a CRUD app. Most of
  • 33:03 - 33:05
    us here, anyway, our domain is not to just
  • 33:05 - 33:07
    be a CRUD app, right. We have some business
  • 33:07 - 33:08
    logic.
  • 33:08 - 33:11
    And after you start with Ruby, then you start
  • 33:11 - 33:14
    to identify the scary things, right. And this
    is
  • 33:14 - 33:16
    like the part of our domain that we're really
  • 33:16 - 33:19
    scared we're not gonna be able to implement.
    Like,
  • 33:19 - 33:21
    what is the thing that's gonna be super hairy,
  • 33:21 - 33:23
    that we're just kind of like, afraid to tackle,
  • 33:23 - 33:26
    right. And removing the, like, the analysis
    paralysis that
  • 33:26 - 33:28
    can set in when you're trying to figure out
  • 33:28 - 33:30
    where your, what your data's gonna look like,
    while
  • 33:30 - 33:32
    you're just kind of playing around with, with
    an
  • 33:32 - 33:34
    algorithm, is great, because it gives you
    this sort
  • 33:34 - 33:36
    of power to attack the scary things. You can
  • 33:36 - 33:40
    do, I know it's crazy to say, some TDD
  • 33:40 - 33:42
    and attack these scary things.
  • 33:42 - 33:44
    And it's, the cost of experimentation is a
    lot
  • 33:44 - 33:46
    lower when you're not messing around running
    migrations. You're
  • 33:46 - 33:50
    just running super fast tests. Everything
    is really nice.
  • 33:50 - 33:51
    And you validate that the business logic that
    you're
  • 33:51 - 33:54
    trying to write is going to be sane before
  • 33:54 - 33:56
    you go any further.
  • 33:56 - 33:59
    And so, so what that might look like, for
  • 33:59 - 34:01
    instance, is let's say I have a monster class,
  • 34:01 - 34:04
    right. I simply give it some teeth and some
  • 34:04 - 34:06
    claws, right, and it can bite and it can
  • 34:06 - 34:08
    scratch, and I write my test. And let's just
  • 34:08 - 34:10
    assume that biting and scratching is a very,
    very
  • 34:10 - 34:13
    difficult thing for a monster to do, right.
  • 34:13 - 34:15
    And, and so it starts out that way. And
  • 34:15 - 34:18
    you gradually iterate on the things that you
    want
  • 34:18 - 34:21
    your monster to do, right. And then what you
  • 34:21 - 34:25
    find out is that, eventually, after having
    iterated through
  • 34:25 - 34:28
    maybe, maybe many, many iterations on what
    this class
  • 34:28 - 34:31
    looks like, what its collaborators might look
    like, you
  • 34:31 - 34:33
    get to a point where you're like, OK. I
  • 34:33 - 34:35
    know how to make this monster now. I know
  • 34:35 - 34:37
    how to, how to tackle it, right.
  • 34:37 - 34:39
    And now is a time for you to admit
  • 34:39 - 34:43
    persistence. Right, now you start to think,
    OK, well,
  • 34:43 - 34:45
    I've gotta persist this stuff somewhere. I
    have some,
  • 34:45 - 34:47
    some things about this business logic that
    are gonna
  • 34:47 - 34:50
    require me to save some data to the database.
  • 34:50 - 34:52
    And so you decide, well, what database am
    I
  • 34:52 - 34:54
    gonna use? Or is it gonna be NoSQL or
  • 34:54 - 34:55
    is it gonna be SQL or is it gonna
  • 34:55 - 34:59
    be, I don't know, something in memory? Right.
  • 34:59 - 35:03
    And then from that point, let's just say you
  • 35:03 - 35:07
    decide, well, now I'm gonna do some ActiveRecord.
    And
  • 35:07 - 35:09
    so you say, all I do is now inherit
  • 35:09 - 35:11
    from ActiveRecord::Base. The teeth and claws
    are no longer
  • 35:11 - 35:16
    supplied via injection. But instead they come
    from relationships
  • 35:16 - 35:19
    in some way, and we maybe have determined
    that
  • 35:19 - 35:24
    we require that we have teeth and claws.
  • 35:24 - 35:25
    And then, you guys are gonna think. You notice
  • 35:25 - 35:29
    there's no methods here, right. Right. No
    methods. It's
  • 35:29 - 35:32
    not doing anything yet, except the ActiveRecord
    stuff. You're
  • 35:32 - 35:34
    gonna think I'm trolling you. But here's what
    I've
  • 35:34 - 35:36
    started to do.
  • 35:36 - 35:41
    I use modules. Now, the way I see it,
  • 35:41 - 35:43
    you know, in firefighting there's this thing
    called a
  • 35:43 - 35:47
    back fire, where it's like, OK, so, when they
  • 35:47 - 35:49
    say, like, fight fire with fire, that's actually
    a
  • 35:49 - 35:51
    thing. And like, I'm like, you know what,
    Rails,
  • 35:51 - 35:53
    if you really wanna burn the whole place down,
  • 35:53 - 35:54
    that's OK. I got my own little fire going
  • 35:54 - 35:57
    over here. And it's gonna, it's gonna allow
    me
  • 35:57 - 35:59
    to have some semblance of order. And let me
  • 35:59 - 36:02
    show you what that looks like. And before
    you
  • 36:02 - 36:03
    think that it won't work, I can only just
  • 36:03 - 36:06
    say that it has worked for me. Give it
  • 36:06 - 36:09
    a try. Strangely, I'm not going to prescribe
    that
  • 36:09 - 36:10
    it's gonna be the solution for everyone. I
    know
  • 36:10 - 36:11
    that's kind of the hip thing to do is
  • 36:11 - 36:15
    to say, like, my solution will work for you.
  • 36:15 - 36:17
    But it worked for me.
  • 36:17 - 36:20
    And what it would look like is this. So
  • 36:20 - 36:24
    I now have behaviors that I expose in modules,
  • 36:24 - 36:30
    right. These behaviors are specifically intended
    to provide one
  • 36:30 - 36:35
    isolated thing, one isolated capability to
    the persisted record,
  • 36:35 - 36:37
    right. And so in this case, like, here is
  • 36:37 - 36:42
    the biting module, for instance, right. And
    it knows
  • 36:42 - 36:43
    how to bite. And let's say this is after
  • 36:43 - 36:45
    we have developed all of our, all of our
  • 36:45 - 36:47
    stuff in plain Ruby, right, this is what we
  • 36:47 - 36:50
    landed on for what bite need to, need to
  • 36:50 - 36:52
    perform, right.
  • 36:52 - 36:58
    And so once we've done that, we can write
  • 36:58 - 37:01
    a class, you know, we can actually just test
  • 37:01 - 37:03
    against the class that limits the API service
    that
  • 37:03 - 37:06
    our behavior interacts with. This was the
    goal. Like,
  • 37:06 - 37:10
    this is why I do this at all, is
  • 37:10 - 37:13
    because thinking about how I'm gonna interact
    with this,
  • 37:13 - 37:16
    like, essentially infinite API that, that
    a lot of,
  • 37:16 - 37:19
    a lot of Rails provides, particularly ActiveRecord
    provides in
  • 37:19 - 37:22
    this case, is, is too hard for me. Cause
  • 37:22 - 37:25
    I'm dumb, OK. So, what I need is some
  • 37:25 - 37:26
    help to help me just be able to see
  • 37:26 - 37:28
    into the test. This is the part of the
  • 37:28 - 37:30
    API I care about.
  • 37:30 - 37:32
    And you may be concerned about this. You may
  • 37:32 - 37:35
    say, this looks a lot like ActiveSupport::Concern.
    I can
  • 37:35 - 37:37
    understand why you would say that. Let me
    show
  • 37:37 - 37:39
    you why that's not the case. So, earlier we
  • 37:39 - 37:45
    talked about how ActiveSupport::Concern's
    primary goal is to solve
  • 37:45 - 37:48
    the problem of modules that depend on other
    modules
  • 37:48 - 37:51
    that modify their base class, right.
  • 37:51 - 37:54
    The intention in this, and that might look
    like
  • 37:54 - 37:55
    this. Like, let's say now there's like a whole
  • 37:55 - 37:58
    fighting behavior that might bite and might
    scratch, we
  • 37:58 - 38:00
    don't know yet. There may be some probability
    associated
  • 38:00 - 38:03
    with it, that against a particular target
    or maybe
  • 38:03 - 38:05
    more than one target or whatever, and so it
  • 38:05 - 38:09
    sort of has this dependency, not just on the
  • 38:09 - 38:11
    API that the class that it's being included
    into
  • 38:11 - 38:14
    has, but also the stuff that's getting included
    into
  • 38:14 - 38:17
    that class already. So it expects bite and
    scratch,
  • 38:17 - 38:20
    which are provided by other two behaviors.
    So, that
  • 38:20 - 38:24
    kind of thing becomes actually painful. That
    actually becomes
  • 38:24 - 38:27
    painful when you're not using ActiveSupport::Concern.
  • 38:27 - 38:30
    And so, what you actually have here is a
  • 38:30 - 38:32
    canary in the coal mine, a sentinel animal,
    right.
  • 38:32 - 38:35
    It's, it's something that's telling you, there's
    this thing
  • 38:35 - 38:38
    that's doing more than one kind of thing that's
  • 38:38 - 38:43
    more complex, right. And it really isn't fully
    encapsulated
  • 38:43 - 38:46
    in the stuff that I've got so far. And
  • 38:46 - 38:49
    it leads you to understand that maybe there's
    another
  • 38:49 - 38:51
    thing. Like maybe there's an encounter, right,
    and it
  • 38:51 - 38:54
    might include one or more combatants that
    select targets
  • 38:54 - 38:56
    and do one of their actions, right. Either
    bite
  • 38:56 - 38:59
    or scratch. All right.
  • 38:59 - 39:02
    So, to kind of start to sum things up,
  • 39:02 - 39:04
    it, we, we, a lot of us work in
  • 39:04 - 39:08
    the startup world, right. And it's really
    frustrating and
  • 39:08 - 39:10
    surprising to me that we embrace this idea
    of
  • 39:10 - 39:13
    a minimal, minimum viable product in the startup
    world,
  • 39:13 - 39:16
    right. Build the smallest thing that could
    possibly work
  • 39:16 - 39:17
    and then go from there.
  • 39:17 - 39:22
    I, I kind of feel like in software, the
  • 39:22 - 39:26
    whole goal, really, is to make as few decisions
  • 39:26 - 39:29
    as you possibly can in order to make, get
  • 39:29 - 39:31
    the desired result, right. Every decision
    you defer till
  • 39:31 - 39:34
    later is going to give you some capability
    to
  • 39:34 - 39:38
    be able to react to change, right. So I
  • 39:38 - 39:40
    would like to see us, both in Rails and
  • 39:40 - 39:41
    in the software that we write, start off with
  • 39:41 - 39:46
    fewer opinions. Start off with fewer assumptions.
    Make sure
  • 39:46 - 39:48
    that the floors that we build have a purpose.
  • 39:48 - 39:50
    One great way to do that is to make
  • 39:50 - 39:51
    sure that you can instantiate a lot of the
  • 39:51 - 39:52
    things, right.
  • 39:52 - 39:54
    If you can instantiate a lot of the things
  • 39:54 - 39:56
    then they must have a purpose that we can
  • 39:56 - 39:58
    reason about. We can think about. As opposed
    to,
  • 39:58 - 40:02
    well, they might modify five hundred methods
    on another
  • 40:02 - 40:07
    class. And in general, just be a considerate
    software
  • 40:07 - 40:07
    writer.
  • 40:07 - 40:09
    Thanks for your time.
Title:
RailsConf 2014 - Curmudgeon: An Opinionated Framework by Ernie Miller
Description:

more » « less
Duration:
40:36

English subtitles

Revisions