< Return to Video

Ruby Conf 2013 - Eliminating branching, nil and attributes - let's get weird

  • 0:17 - 0:20
    DAVID COPELAND: All right. Has everyone enjoyed
    their lunch?
  • 0:20 - 0:25
    Ready to talk about some really strange and
    weird code?
  • 0:25 - 0:27
    So thanks a lot for coming. My talk is
  • 0:27 - 0:30
    called eliminating branching, nil, and attributes
    - let's get
  • 0:30 - 0:34
    weird. So we're gonna see some really strange
    code.
  • 0:34 - 0:36
    Briefly, about me, I work at a company called
  • 0:36 - 0:40
    Stitch Fix. We're a personal styling service
    for women's
  • 0:40 - 0:42
    clothes. I'd love to talk about all the cool
  • 0:42 - 0:44
    things that we're doing, but that's not what
    this
  • 0:44 - 0:45
    talk is about.
  • 0:45 - 0:48
    I wrote this book about writing command-line
    apps in
  • 0:48 - 0:50
    Ruby, which you should buy and read and do.
  • 0:50 - 0:52
    Also, not really what the talk is about. I
  • 0:52 - 0:55
    also wrote another book about how to do everything
  • 0:55 - 0:57
    to be a great programmer except for the actual
  • 0:57 - 1:00
    programming part. Again, it's not really what
    I'd like
  • 1:00 - 1:01
    to talk about.
  • 1:01 - 1:03
    I'd like to talk about Top Chef. Anybody watch
  • 1:03 - 1:06
    Top Chef? All right. My wife and I have
  • 1:06 - 1:08
    watched it for years. It's one of my favorite
  • 1:08 - 1:10
    shows. I'm very excited when it shows up.
    I
  • 1:10 - 1:12
    haven't been home for about a month, so no
  • 1:12 - 1:15
    spoilers about the current season.
  • 1:15 - 1:16
    What I love, and if you're not familiar with
  • 1:16 - 1:18
    it, it's a reality show about cooking, so
    these
  • 1:18 - 1:22
    chef's will compete each week and, at the
    end
  • 1:22 - 1:24
    of each episode, a chef will be eliminated,
    and
  • 1:24 - 1:26
    at the end of the season, one chef wins
  • 1:26 - 1:29
    a bunch of money and some kudos and other
  • 1:29 - 1:30
    things like that.
  • 1:30 - 1:31
    What I like about it is that, unlike a
  • 1:31 - 1:34
    lot of reality shows that are about dramatic
    personalities
  • 1:34 - 1:37
    arguing in some house that they live together,
    on
  • 1:37 - 1:41
    Top Chef, you're watching experts execute
    things that they're
  • 1:41 - 1:44
    good at. You're watching these people cook
    this amazing
  • 1:44 - 1:47
    food under intense pressure and just watching
    experts work,
  • 1:47 - 1:48
    I always find fascinating.
  • 1:48 - 1:51
    So what's also fascinating is that the show's
    format
  • 1:51 - 1:55
    hasn't really changed over the years. And
    so when
  • 1:55 - 1:57
    you see experts doing things in a very similar
  • 1:57 - 2:00
    format over many years, patterns start to
    emerge that
  • 2:00 - 2:02
    I find interesting.
  • 2:02 - 2:04
    So the beginning of each show, there's what
    they
  • 2:04 - 2:06
    call the Quick Fire challenge. So the chefs
    are
  • 2:06 - 2:10
    given a short amount of time to make a
  • 2:10 - 2:12
    dish. So, for example, they may have to make
  • 2:12 - 2:17
    an Asian inspired dish that features the dycon
    radish,
  • 2:17 - 2:20
    and they might have thirty minutes to do it.
  • 2:20 - 2:22
    And so it's very intense watching them try
    to
  • 2:22 - 2:25
    do this. Now, what always happens in the show,
  • 2:25 - 2:26
    and if you watch Top Chef, you watch it
  • 2:26 - 2:29
    for years, you'll know exactly where I'm going,
    they're
  • 2:29 - 2:31
    will always be one chef who works in an
  • 2:31 - 2:33
    Asian restaurant, who makes Asian food. This
    chef grew
  • 2:33 - 2:37
    up on a dycon radish farm, knows everything
    about
  • 2:37 - 2:40
    everything in this particular challenge. So
    he is very
  • 2:40 - 2:42
    confident. He is, like, I got this. I know
  • 2:42 - 2:44
    how to do all these things. No one's gonna,
  • 2:44 - 2:46
    no one's gonna beat me. I'm gonna get the
  • 2:46 - 2:48
    advantage later in the show by winning the
    Quick
  • 2:48 - 2:49
    Fire challenge.
  • 2:49 - 2:51
    And, of course, there's always another chef,
    and she
  • 2:51 - 2:53
    is a French pastry chef. She doesn't know
    what
  • 2:53 - 2:56
    a dycon radish is. She doesn't like Asian
    food.
  • 2:56 - 2:58
    She's never cooked Asian food. And she's very
    worried
  • 2:58 - 3:00
    that not only is she not going to win,
  • 3:00 - 3:03
    but she's going to lose the Quick Fire challenge,
  • 3:03 - 3:05
    which comes with a disadvantage later, which
    means that
  • 3:05 - 3:08
    her chance of getting eliminated is very high.
    So
  • 3:08 - 3:12
    she's very upset about this particular challenge.
  • 3:12 - 3:16
    Now what happens is our chef who works in
  • 3:16 - 3:18
    the Asian restaurant will do what he always
    does.
  • 3:18 - 3:20
    Produce what he always produces. And he will
    produce
  • 3:20 - 3:23
    a mediocre dish, because the level of competition
    is
  • 3:23 - 3:25
    so high, when he just executes these things
    that
  • 3:25 - 3:27
    he knows how to do, he's not really rising
  • 3:27 - 3:30
    to the level of his competition. Which is
    kind
  • 3:30 - 3:31
    of unsurprising.
  • 3:31 - 3:33
    But what's more surprising is that our French
    pastry
  • 3:33 - 3:36
    chef will, invariable - oh, I forgot to hit
  • 3:36 - 3:41
    start on this thing. Will invariably win the
    competition,
  • 3:41 - 3:42
    even though she technically has no idea what
    she's
  • 3:42 - 3:45
    doing, right. Because she has the abilities
    of a
  • 3:45 - 3:49
    chef, she understands the basic tools of cooking,
    and
  • 3:49 - 3:50
    even though she doesn't know how Asian food
    is
  • 3:50 - 3:53
    supposed to be made, or what you're supposed
    to
  • 3:53 - 3:56
    do with the dycon radish, she's forced to
    get
  • 3:56 - 3:57
    creative.
  • 3:57 - 3:59
    This happens all the time on the show, and
  • 3:59 - 4:04
    I think it's interesting to note the, being,
    being
  • 4:04 - 4:08
    constrained and being forced to work without
    the things
  • 4:08 - 4:11
    that are comfortable to you can force people
    to
  • 4:11 - 4:14
    become creative and can force people to do
    something
  • 4:14 - 4:16
    that they wouldn't have thought of because
    they're outside
  • 4:16 - 4:17
    of their comfort zone.
  • 4:17 - 4:19
    So that's what this talk is about. We're going
  • 4:19 - 4:23
    to talk about some things, like nil, like
    branching,
  • 4:23 - 4:25
    like attributes, that we use all the time
    and
  • 4:25 - 4:28
    are very useful, and are comfortable to us,
    and
  • 4:28 - 4:30
    we're gonna take those away and see what the
  • 4:30 - 4:33
    code looks like without those and see if that
  • 4:33 - 4:36
    kind of makes us get a little more creative
  • 4:36 - 4:37
    or think of things that we wouldn't normally
    have
  • 4:37 - 4:40
    thought of.
  • 4:40 - 4:42
    So I want to first talk about the billion
  • 4:42 - 4:46
    dollar mistake. Anybody familiar with this
    term? So it
  • 4:46 - 4:50
    was coined by Tony Harr, who is a luminary
  • 4:50 - 4:53
    in the world of database research. If you've
    ever
  • 4:53 - 4:56
    used a relational database, you have him to
    thank
  • 4:56 - 4:58
    for how it works.
  • 4:58 - 5:01
    And in 1965, before most of us were probably
  • 5:01 - 5:04
    born, before most of us were probably programming,
    he
  • 5:04 - 5:08
    was working on an object-oriented programming
    language. He has
  • 5:08 - 5:09
    this to say.
  • 5:09 - 5:12
    "I was designing the first comprehensive type
    system for
  • 5:12 - 5:16
    references in an object oriented language-"
    Remember, 1965. "I
  • 5:16 - 5:18
    couldn't resist the temptation to put in a
    nul
  • 5:18 - 5:21
    reference, simply because it was so easy to
    implement.
  • 5:21 - 5:24
    This has lead to innumerable errors, vulnerabilities,
    and system
  • 5:24 - 5:26
    crashes, which have probably caused a billion
    dollars of
  • 5:26 - 5:30
    pain and damage in the last forty years."
  • 5:30 - 5:33
    I think it's probably been fifty years since,
    since
  • 5:33 - 5:36
    that happened, and it's interesting to think
    about. The
  • 5:36 - 5:38
    whole time I've been programming, there's
    been nul. There's
  • 5:38 - 5:40
    nul everywhere. Nul's in SQL, it's in C, it's
  • 5:40 - 5:43
    in C++, it's in Java, it's in JavaScript,
    it's
  • 5:43 - 5:45
    in Ruby, it's in Python. It's just everywhere.
    Like,
  • 5:45 - 5:47
    and you always use it for, I don't know
  • 5:47 - 5:50
    or unassigned or nothing.
  • 5:50 - 5:52
    So what if he hadn't done that? What if
  • 5:52 - 5:55
    he had resisted that temptation? So what if
    Ruby
  • 5:55 - 5:58
    didn't have nil at all, right?
  • 5:58 - 6:00
    Specifically, that would mean that every single
    variable would
  • 6:00 - 6:02
    have to have a value, cause there is no
  • 6:02 - 6:07
    default stand-in value. And it would also
    mean that
  • 6:07 - 6:09
    there's no handy global system you can reach
    for
  • 6:09 - 6:11
    everywhere that means nothing.
  • 6:11 - 6:15
    So let's say Ruby didn't have this at all.
  • 6:15 - 6:18
    Would we be able to get our work done?
  • 6:18 - 6:20
    So here's some code. It is a person. A
  • 6:20 - 6:22
    person has a name and a birth date, and
  • 6:22 - 6:24
    as you can see in the little highlighted line
  • 6:24 - 6:26
    here, it's title, person may or may not have
  • 6:26 - 6:28
    a title. So typically we'll, we'll default
    that to
  • 6:28 - 6:31
    nil so that you can create people without
    specifying
  • 6:31 - 6:33
    explicitly nil or anything like that.
  • 6:33 - 6:36
    So you can see how this optional title affects
  • 6:36 - 6:39
    our code. Title is nil. We say, "Hello, Bob."
  • 6:39 - 6:41
    But if Bob has a title, we say, "Hello,
  • 6:41 - 6:42
    Mr. Bob."
  • 6:42 - 6:44
    This is, you know, it's very simplistic, but
    it's
  • 6:44 - 6:47
    pretty typical of code that we write around
    nil.
  • 6:47 - 6:49
    So if we don't have nil, we can't do
  • 6:49 - 6:51
    this. So how would we solve the problem of
  • 6:51 - 6:53
    having people, some of whom have titles and
    some
  • 6:53 - 6:55
    of whom don't have titles?
  • 6:55 - 6:58
    Well, why don't we use the type system, right?
  • 6:58 - 7:00
    So we can make a person that just has
  • 7:00 - 7:02
    the attributes that all people have. A name
    and
  • 7:02 - 7:04
    a birth date. So we can see the greeting
  • 7:04 - 7:07
    method is very simple: "Hello, Bob." And then
    we'll
  • 7:07 - 7:11
    make a subclass called TitledPerson, and that
    will have
  • 7:11 - 7:13
    a title, and then the, it will override greeting,
  • 7:13 - 7:15
    to say, "Hello, Mr. Bob."
  • 7:15 - 7:18
    So now we know, everywhere we have a titled
  • 7:18 - 7:20
    person, we know there's a title. If we don't
  • 7:20 - 7:22
    have a titled person, we don't have a title.
  • 7:22 - 7:25
    So we didn't need to check for nil. Unfortunately,
  • 7:25 - 7:29
    this technique is - it's great for giant slides
  • 7:29 - 7:32
    with giant fonts on them. But, in reality,
    right,
  • 7:32 - 7:33
    think of an object in your system that has
  • 7:33 - 7:35
    a lot of optional values.
  • 7:35 - 7:38
    It would be super complex to do this with
  • 7:38 - 7:40
    lots and lots of optional values. You could
    use
  • 7:40 - 7:43
    modules. It gets kind of weird, but it also
  • 7:43 - 7:46
    kind of shows, like, a, this is not really
  • 7:46 - 7:48
    the most Ruby way to solve this problem, right.
  • 7:48 - 7:51
    Ruby, yes, you make classes and they create
    objects,
  • 7:51 - 7:53
    but having lots of finegrained types like
    this is
  • 7:53 - 7:55
    not as helpful as it might be in, like,
  • 7:55 - 7:56
    a statically typed language.
  • 7:56 - 7:58
    So if we were doing Scala we might want
  • 7:58 - 8:00
    to write a routine that says, I need a
  • 8:00 - 8:02
    person that has a title, so I'm gonna require
  • 8:02 - 8:04
    you to pass in a titled person and the
  • 8:04 - 8:06
    compiler will refuse to compile your code
    if you
  • 8:06 - 8:09
    don't do that. Ruby doesn't work that way,
    and
  • 8:09 - 8:11
    it's, no offense, I'm glad it doesn't work
    that
  • 8:11 - 8:15
    way. The point is, if we're using types like
  • 8:15 - 8:16
    this, we end up having to check the types
  • 8:16 - 8:18
    of things, or have our tests check the types
  • 8:18 - 8:20
    of things, and that's just kind of strange
    to
  • 8:20 - 8:23
    be adding these degenerate type systems to
    our tests
  • 8:23 - 8:24
    and code.
  • 8:24 - 8:27
    So we really do need some concept of nul
  • 8:27 - 8:28
    or some concept of, like, there is no value
  • 8:28 - 8:30
    here or I don't know. Like, we do need
  • 8:30 - 8:33
    that concept. We can't skirt it just by using
  • 8:33 - 8:36
    types and modules.
  • 8:36 - 8:37
    So we could do this, right. But let's think
  • 8:37 - 8:39
    harder than this. Let's try a little harder
    than
  • 8:39 - 8:43
    just recreating nil. Let's think about what
    nil means.
  • 8:43 - 8:47
    So nil means a variable hasn't been set. It
  • 8:47 - 8:49
    could mean that we don't know the value of
  • 8:49 - 8:51
    a variable yet, but we might later. It could
  • 8:51 - 8:53
    mean that there is no value. We know that
  • 8:53 - 8:55
    there is no value. We know someone doesn't
    have
  • 8:55 - 8:59
    a title. It could mean some vague concept
    of
  • 8:59 - 9:01
    So if we want to model these four things,
  • 9:01 - 9:03
    I don't think nil would be the way we'd
  • 9:03 - 9:04
    go about it. I don't think we'd want to
  • 9:04 - 9:07
    have a single symbol represent all of these
    four
  • 9:07 - 9:09
    concepts, because they're different, and there's
    no way to
  • 9:09 - 9:12
    tell the difference between a unset variable
    and a
  • 9:12 - 9:15
    variable whose value we don't know, if they're
    both
  • 9:15 - 9:16
    nil.
  • 9:16 - 9:21
    So let's, let's create four symbols - sorry
    about
  • 9:21 - 9:23
    the zoom here. So four symbols, each one represents
  • 9:23 - 9:25
    one of those concepts. So now we can tell
  • 9:25 - 9:28
    the difference. And so if we look back at
  • 9:28 - 9:31
    our person code, again, we're going back to
    the
  • 9:31 - 9:34
    kind of the original version, but here, you'll
    notice
  • 9:34 - 9:38
    we're giving title the default value of unknown.
    So
  • 9:38 - 9:42
    because now there are four different things
    we've created,
  • 9:42 - 9:44
    we can make a design decision about what title
  • 9:44 - 9:45
    should default to.
  • 9:45 - 9:47
    We could decide that a title has no value
  • 9:47 - 9:49
    by default. We could decide that it's unknown
    by
  • 9:49 - 9:50
    default. So that's a design decision that
    we get
  • 9:50 - 9:54
    to make that expresses something about our
    person that
  • 9:54 - 9:56
    we couldn't do before. So we're gonna call,
    we're
  • 9:56 - 9:59
    gonna just say a person is unknown. A person's
  • 9:59 - 10:02
    title is unknown by default.
  • 10:02 - 10:04
    So our greet method, you know, we could do
  • 10:04 - 10:08
    it like this, and, you know, this is not
  • 10:08 - 10:10
    gonna work. Obviously this is buggy, right,
    because if
  • 10:10 - 10:12
    we give no value, then, "Hello, No Value Bob."
  • 10:12 - 10:14
    Like that's not right.
  • 10:14 - 10:18
    But more, moreso, since there's so many different
    symbols
  • 10:18 - 10:22
    that represent some type of no value, we can't
  • 10:22 - 10:24
    just get away with comparing it. Like, with
    nil,
  • 10:24 - 10:26
    it's handy. We know there's only one nil.
    And
  • 10:26 - 10:27
    even though we know we should be calling the
  • 10:27 - 10:30
    dot nil method, we tend to compare it to
  • 10:30 - 10:32
    nil a lot. But that's OK because there's only
  • 10:32 - 10:32
    one of them.
  • 10:32 - 10:34
    Well, in this world of no nil, there isn't
  • 10:34 - 10:36
    one of them, there's four, and it would be
  • 10:36 - 10:39
    pretty darn ugly to be checking title against
    all
  • 10:39 - 10:43
    four values. What we really need is some sort
  • 10:43 - 10:45
    of API around this, some messages that we
    can
  • 10:45 - 10:48
    send to make this a little simpler.
  • 10:49 - 10:51
    So what if we had something like this? We
  • 10:51 - 10:54
    had a message called when_value that everybody
    responds to,
  • 10:54 - 10:56
    and if the person we're sending that message
    to
  • 10:56 - 10:59
    happens to be a value, it will execute this
  • 10:59 - 11:03
    code, "Hello, Mr. Bob." And if title isn't
    a
  • 11:03 - 11:07
    value, is some sort of nil-like thing, it
    will
  • 11:07 - 11:08
    execute this: "Hello, Bob."
  • 11:08 - 11:11
    So this is pretty easy to implement. BasicObject,
    right,
  • 11:11 - 11:14
    is the root of all objects in Ruby. And
  • 11:14 - 11:16
    all objects are values, by default, so when_value
    will
  • 11:16 - 11:19
    just call the block given to it, and, or_else
  • 11:19 - 11:21
    is a nil-op? cause since our basic objects
    are
  • 11:21 - 11:24
    values, we don't want to do this or_else thing.
  • 11:24 - 11:27
    Now for these four special nil-like things,
    we'll make
  • 11:27 - 11:30
    the superclass called NilLikeSentinal, which
    is the best name
  • 11:30 - 11:32
    I could come up with without using one of
  • 11:32 - 11:34
    the names of these objects, and it does the
  • 11:34 - 11:37
    opposite, right. So when value is nothing,
    it's a
  • 11:37 - 11:38
    no op, but or_else, because these are not
    actual
  • 11:38 - 11:41
    real values, will execute. And then we give
    all
  • 11:41 - 11:44
    these guys a new superclass.
  • 11:44 - 11:47
    So that makes that work, which is kind of
  • 11:47 - 11:51
    interesting. It's a little bit strange-looking,
    right, because we've
  • 11:51 - 11:53
    got this method called or_else, but Ruby also
    has
  • 11:53 - 11:56
    this else thing, it's kind of like we're branching,
  • 11:56 - 11:58
    but we're not. It's, it's a little bit weird,
  • 11:58 - 12:00
    and it's kind of the same lines of code
  • 12:00 - 12:02
    as our nil-checking thing.
  • 12:02 - 12:04
    So, you know, I would probably want to know,
  • 12:04 - 12:07
    is there any advantage to doing it this way?
  • 12:07 - 12:11
    Well, let's consider if our greeting method
    gets a
  • 12:11 - 12:14
    little more complex, and now what we want
    to
  • 12:14 - 12:16
    do is, if we have a title, we want
  • 12:16 - 12:19
    to say, "Hello Mr. Bob." But if we don't
  • 12:19 - 12:21
    have a title but we know that a person
  • 12:21 - 12:23
    has no title, right, we know you have no
  • 12:23 - 12:25
    title, we'll say, "Hello Bob," but if we're
    not
  • 12:25 - 12:27
    sure, if the title is unknown or we haven't
  • 12:27 - 12:30
    been told what the title is, we want to
  • 12:30 - 12:32
    say, "I'm not sure how to greet you Bob."
  • 12:32 - 12:33
    So these are, these are different things,
    right. We
  • 12:33 - 12:35
    know a person doesn't have a title is different
  • 12:35 - 12:39
    from not knowing what a person's title is.
  • 12:39 - 12:43
    So with Nil, this would be very hard, but
  • 12:43 - 12:47
    now it's kind of, let's expand our little
    Nil-like
  • 12:47 - 12:51
    API to have this concept of when_known. So
    does
  • 12:51 - 12:53
    this value, this thing we have is a value
  • 12:53 - 12:56
    or not, is it something known? Do we have
  • 12:56 - 12:59
    knowledge about something? So, of course,
    BasicObjects, since they
  • 12:59 - 13:02
    are values, we know they are that value.
  • 13:02 - 13:07
    Nil-like objects, again, are not known by
    default, and
  • 13:07 - 13:10
    then we'll have our known Nil-like sentinel,
    which will
  • 13:10 - 13:14
    represent things that are not values but represent
    knowledge
  • 13:14 - 13:17
    that we have. So no value at empty, represent
  • 13:17 - 13:20
    that, and now, our code looks like this.
  • 13:20 - 13:23
    And this is what I love about Ruby. title.when_value,
  • 13:23 - 13:27
    "Hello Mr. Bob." when_known, "Hello Bob" or_else,
    "Not sure
  • 13:27 - 13:28
    how to greet you Bob."
  • 13:28 - 13:30
    I can just read you the code and it
  • 13:30 - 13:33
    sounds like a sentence. It sounds like what
    it
  • 13:33 - 13:34
    does.
  • 13:34 - 13:35
    So this is actually a little bit more interesting.
  • 13:35 - 13:39
    It's definitely strange-looking, but you'll
    notice that we've lost
  • 13:39 - 13:41
    all of that deep nesting that we might have
  • 13:41 - 13:43
    had. Everything's kind of typographically
    the same, which it
  • 13:43 - 13:45
    should be because these are all equally likely
    to
  • 13:45 - 13:50
    happen in our world. And it's just, you know,
  • 13:50 - 13:52
    it kind of reads nice.
  • 13:52 - 13:54
    And it's important to point out, if we were
  • 13:54 - 13:56
    using Nil, we probably would never have come
    up
  • 13:56 - 13:57
    with any of this, and to be able to
  • 13:57 - 14:00
    tell a Nil title, does that mean unknown or
  • 14:00 - 14:03
    does that mean I know that there is no
  • 14:03 - 14:05
    title? Like, you'd have to have some boolean
    flag
  • 14:05 - 14:07
    to keep track of that or some magical symbol.
  • 14:07 - 14:09
    So, instead what we've done is we've just
    created
  • 14:09 - 14:12
    objects and messages to model the actual thing
    we
  • 14:12 - 14:14
    want to do.
  • 14:14 - 14:15
    So that's kind of cool.
  • 14:15 - 14:19
    Now, you'll notice that I didn't make methods
    called
  • 14:19 - 14:23
    is_value or is_known or anything like that.
    And that
  • 14:23 - 14:26
    leads to the next -oh, also, this is the
  • 14:26 - 14:28
    best part of this so I can't believe I
  • 14:28 - 14:29
    forgot.
  • 14:29 - 14:30
    Wouldn't it be nice to get that in your
  • 14:30 - 14:33
    stackTrace, or that, instead of no such value
    for
  • 14:33 - 14:35
    nilClass? Like, who knows what that means?
    But this,
  • 14:35 - 14:37
    right, this means I didn't handle some logic,
    and
  • 14:37 - 14:40
    this means that I screwed up. So that's another
  • 14:40 - 14:43
    kind of side-benefit of, of doing this.
  • 14:43 - 14:44
    So, to get back to the Nil method or
  • 14:44 - 14:47
    the value method or is_known method like,
    you, you
  • 14:47 - 14:49
    might think that I should have added those,
    and
  • 14:49 - 14:51
    based my logic on that. So I want to
  • 14:51 - 14:54
    talk about attributes.
  • 14:54 - 14:56
    Those are kind of a form of attributes. And
  • 14:56 - 15:01
    so, what I mean is attr_accessor, attr_reader,
    attr_writer. These
  • 15:01 - 15:03
    give the appearance of being able to access
    the
  • 15:03 - 15:06
    internal state of our objects and the ability
    to
  • 15:06 - 15:10
    change, directly, the internal state of our
    objects.
  • 15:10 - 15:12
    Ruby helps by allowing this method named foo
    equals
  • 15:12 - 15:16
    to be cooled with foo space equals, so it
  • 15:16 - 15:18
    really does give the appearance that our objects
    are
  • 15:18 - 15:20
    these dumb structs that we can just kind of
  • 15:20 - 15:21
    change willy-nilly.
  • 15:21 - 15:24
    Because it's so darn handy and so easy, and
  • 15:24 - 15:26
    especially when we're manipulating things
    in a database, we
  • 15:26 - 15:29
    tend to write code like this a lot. But
  • 15:29 - 15:32
    I think that is potentially bad. So let me
  • 15:32 - 15:35
    try to make that point by describing how you
  • 15:35 - 15:37
    might buy something by using attributes.
  • 15:37 - 15:41
    So you take out your wallet. Hand your entire
  • 15:41 - 15:44
    wallet over to the clerk. The clerk will then
  • 15:44 - 15:46
    rifle through your wallet to find whatever
    combination of
  • 15:46 - 15:50
    cash, credit cards, gift cards he decides
    that you
  • 15:50 - 15:54
    should use to pay to oversee the transaction,
    and
  • 15:54 - 15:55
    hands you back your wallet in whatever state
    he
  • 15:55 - 15:57
    felt like leaving it in.
  • 15:57 - 16:00
    So, right? Some countries don't even take
    your credit
  • 16:00 - 16:01
    card. They give you a machine to run your
  • 16:01 - 16:03
    credit card through, right. No one buys things
    like
  • 16:03 - 16:05
    this. This is crazy.
  • 16:05 - 16:07
    But when you write code that makes heavy use
  • 16:07 - 16:10
    of attributes, it's kind of like how you're
    coding,
  • 16:10 - 16:14
    right? So let's say that Ruby doesn't allow
    this
  • 16:14 - 16:15
    sort of thing. Let's say that Ruby doesn't
    have
  • 16:15 - 16:19
    this little nice equals method deal and that
    the
  • 16:19 - 16:21
    standard library doesn't provide attr_accessor
    or attr_reader or attr_writer.
  • 16:21 - 16:24
    It doesn't provide any of that stuff.
  • 16:24 - 16:26
    So if you've ever coded in JavaScript or Java,
  • 16:26 - 16:28
    you know what that's like, cause they, those
    languages
  • 16:28 - 16:29
    don't provide that.
  • 16:29 - 16:33
    Ooh boy, that got really zoomed.
  • 16:33 - 16:36
    OK, that's not too bad. So here's some code
  • 16:36 - 16:38
    that, that, that we, that we will not be
  • 16:38 - 16:40
    allowed to write. So we have a very sophisticated
  • 16:40 - 16:42
    greeting method now that is going to give
    you
  • 16:42 - 16:44
    a casual greeting: "Hi Bob" if we know your
  • 16:44 - 16:47
    first name. If we don't, but you have a
  • 16:47 - 16:49
    last name, then we're gonna see if you have
  • 16:49 - 16:52
    a gender, and if your gender also has a
  • 16:52 - 16:55
    gender-specific salutation, and if all that
    is true, we
  • 16:55 - 16:58
    will say, "Hello Mr. Jones" and if not, we'll
  • 16:58 - 17:00
    say "Hello Jones," and if all else false,
    we'll
  • 17:00 - 17:00
    say, "Hello."
  • 17:00 - 17:03
    So this is convoluted, but I'm sure we've
    all
  • 17:03 - 17:05
    written code that looks more or less like
    this.
  • 17:05 - 17:07
    Asking things for their things and checking
    their things
  • 17:07 - 17:09
    against other things.
  • 17:09 - 17:10
    So if we can't do any of this, if
  • 17:10 - 17:13
    we can't create easily an API like this, right,
  • 17:13 - 17:16
    what would we do? So, getting back to the
  • 17:16 - 17:18
    Java and JavaScript part, we all know what
    those
  • 17:18 - 17:21
    languages do. They make methods called getters
    and setters
  • 17:21 - 17:26
    that look like crappy versions of attributes.
  • 17:26 - 17:27
    And the, that makes sense for those languages
    cause
  • 17:27 - 17:30
    those languages aren't terribly powerful compared
    to Ruby. But
  • 17:30 - 17:34
    Ruby has more features available to us that
    might
  • 17:34 - 17:37
    not lead us down that path.
  • 17:37 - 17:41
    So what if we did something like this? We
  • 17:41 - 17:43
    have a method called with_attributes - hang
    on, I'm
  • 17:43 - 17:46
    sorry these are so small. There we go.
  • 17:46 - 17:48
    And so if the first name is there, then
  • 17:48 - 17:50
    we'll run this bucket code. If we didn't,
    but
  • 17:50 - 17:52
    we have a gendered salutation and a last name,
  • 17:52 - 17:57
    run this block of code, et cetera. So I
  • 17:57 - 17:59
    should point out, this absolutely works. A
    lambda has
  • 17:59 - 18:02
    access to not only the number of parameters,
    but
  • 18:02 - 18:04
    the names of those parameters. So you could
    just
  • 18:04 - 18:08
    look at the parameter list to figure out what
  • 18:08 - 18:12
    attributes are being asked for.
  • 18:12 - 18:15
    So this is kind of strange, right. But you
  • 18:15 - 18:17
    could imagine, if the standard library provided
    something like
  • 18:17 - 18:20
    this, this would start to look kind of normal,
  • 18:20 - 18:23
    and again, right, we've lost, we've lost that
    big
  • 18:23 - 18:26
    huge cone of nesting, and now we have a
  • 18:26 - 18:29
    nice, nice little typographically organized
    thing for each thing
  • 18:29 - 18:33
    that could possibly happen. It's nice.
  • 18:33 - 18:35
    But there's another couple things that are
    nice about
  • 18:35 - 18:40
    this that we wouldn't have gotten with this
    craziness.
  • 18:40 - 18:44
    One is that we have an API that differentiates
  • 18:44 - 18:47
    a request for information and actually being
    given that
  • 18:47 - 18:51
    information. So that allows us some more flexibility.
    So
  • 18:51 - 18:54
    if we wanted to have logic that says, you
  • 18:54 - 18:56
    know, maybe someone has a gender salutation
    and they
  • 18:56 - 18:58
    have a last name, but if someone asked for
  • 18:58 - 18:59
    them both at the same time we want to
  • 18:59 - 19:00
    do something else.
  • 19:00 - 19:02
    Like, we could do that with a structure like
  • 19:02 - 19:04
    this. We couldn't do that by just allowing
    people
  • 19:04 - 19:07
    to have access to whatever they wanted. So
    that's
  • 19:07 - 19:09
    kind of interesting. But what's more interesting
    is, when
  • 19:09 - 19:10
    you think about the scope of some of these
  • 19:10 - 19:11
    variables.
  • 19:11 - 19:17
    So here, the, the, the scope over which first
  • 19:17 - 19:19
    name, last name, gender, all this stuff, it's
    all
  • 19:19 - 19:21
    global to this method, right. All those values
    could
  • 19:21 - 19:23
    be accessed anywhere, and although this is
    a very
  • 19:23 - 19:25
    short method, I think we all know that the
  • 19:25 - 19:28
    larger the scope of a variable is, the harder
  • 19:28 - 19:30
    a routine is to understand, because you have
    to
  • 19:30 - 19:32
    keep a lot of things in your head to
  • 19:32 - 19:34
    understand what is going on and what might
    happen.
  • 19:34 - 19:38
    Here, the scope of first name is just here.
  • 19:38 - 19:40
    The scope of gender_salutation and last_name
    is just here.
  • 19:40 - 19:43
    Now, even though these are one-liners, each
    of these
  • 19:43 - 19:45
    blocks, each of these alternatives, is still
    going to
  • 19:45 - 19:47
    be smaller than the entire routine.
  • 19:47 - 19:49
    So we've actually made the code a little simpler
  • 19:49 - 19:53
    to understand by reducing the scope of the
    variables
  • 19:53 - 19:55
    that we need to do our job. But we
  • 19:55 - 19:57
    haven't taken away any power. You still have
    access
  • 19:57 - 19:59
    to these things. And it's kind of the same
  • 19:59 - 20:02
    lines of code. So that's kind of interesting
    I
  • 20:02 - 20:03
    think.
  • 20:03 - 20:05
    Where it gets really interesting is when we
    want
  • 20:05 - 20:09
    to change the internal state of an object.
    So
  • 20:09 - 20:13
    again, we might want to change a person's
    city
  • 20:13 - 20:16
    to normalize it or something like that. And
    you
  • 20:16 - 20:18
    know whatever your feelings are on mutable
    state and
  • 20:18 - 20:21
    changing things like, our programs do need
    to make
  • 20:21 - 20:24
    changes to something somewhere sometimes,
    so we have to
  • 20:24 - 20:27
    have an ability to change something about
    something.
  • 20:27 - 20:30
    So if we can't do something like this little
  • 20:30 - 20:34
    magic, magicness here, and we're not doing
    setters cause
  • 20:34 - 20:37
    setters are weak, what are we gonna do? Well
  • 20:37 - 20:40
    what if we made, we'll follow along our with_attributes
  • 20:40 - 20:44
    concept and we'll make a method that records
    all
  • 20:44 - 20:46
    of the changes a caller might want to make
  • 20:46 - 20:48
    to us and then we can decide what to
  • 20:48 - 20:49
    do with that.
  • 20:49 - 20:52
    So maybe that looks like this. Person has
    this
  • 20:52 - 20:55
    update method, takes a block, and inside that
    block
  • 20:55 - 20:59
    we will use the update object to record, let's
  • 20:59 - 21:01
    say a bunch of requests of changes and, you
  • 21:01 - 21:02
    know, I'd like to update the city to this
  • 21:02 - 21:05
    and blah, blah, blah.
  • 21:05 - 21:07
    So again it's the same lines of code but
  • 21:07 - 21:11
    now we have a level of indirection between
    what
  • 21:11 - 21:13
    we would like to do and having those changes
  • 21:13 - 21:15
    actually made, which is kind of interesting,
    right. Because
  • 21:15 - 21:17
    it gives us some, a little bit more power
  • 21:17 - 21:20
    that we wouldn't get with these, these equals
    methods
  • 21:20 - 21:22
    that we use so often.
  • 21:22 - 21:25
    So, you know, a naive implementation might
    just be
  • 21:25 - 21:27
    to just do what equals methods do, right,
    so
  • 21:27 - 21:29
    we could kind of default to that if we
  • 21:29 - 21:31
    wanted to. So we're getting the exact same
    thing
  • 21:31 - 21:35
    with about the same lines of code. And, but
  • 21:35 - 21:37
    we could do more interesting things. What
    if we
  • 21:37 - 21:39
    wanted to run this in a database transaction?
  • 21:39 - 21:41
    Well, if you've done Rails programming, then
    the way
  • 21:41 - 21:43
    to do this is either you, the caller, must
  • 21:43 - 21:46
    put everything in a transaction, or you have
    to
  • 21:46 - 21:48
    use a Rails-specific magic method that only
    some objects
  • 21:48 - 21:51
    have that is known and documented to put things
  • 21:51 - 21:52
    in a transaction.
  • 21:52 - 21:55
    So me, being the object who's being changed,
    I
  • 21:55 - 21:56
    don't really have a lot of control over that.
  • 21:56 - 21:57
    So this would allow me to do that if
  • 21:57 - 22:01
    I wanted. What's more interesting is that
    since we
  • 22:01 - 22:02
    have all of the changes that we want to
  • 22:02 - 22:04
    make to an object in one place without them
  • 22:04 - 22:07
    haven't actually being made, we can examine
    them before
  • 22:07 - 22:08
    doing anything.
  • 22:08 - 22:11
    So we could decide that if you're changing
    the
  • 22:11 - 22:14
    zip code and city together at the same time,
  • 22:14 - 22:16
    then we want to make sure that those are
  • 22:16 - 22:18
    consistent with each other, and we want to
    blow
  • 22:18 - 22:21
    up if not. So doing this with equals methods
  • 22:21 - 22:23
    would be tricky. It would be really hard to
  • 22:23 - 22:27
    get it exactly right in every case.
  • 22:27 - 22:29
    But it's, you know, it is kind of, it's
  • 22:29 - 22:30
    kind of strange looking, but I, you know,
    I
  • 22:30 - 22:32
    think, like, I would be used to this if
  • 22:32 - 22:34
    this was just kind of how you did things.
  • 22:34 - 22:36
    And it's kind of interesting that by not using
  • 22:36 - 22:39
    these handy things that we think are easy,
    we
  • 22:39 - 22:44
    get a lot more power available to us.
  • 22:44 - 22:51
    So, you may have noticed that the before and
  • 22:51 - 22:53
    after, the after didn't have any if statements
    in
  • 22:53 - 22:56
    it. And that was sort of intentional but sort
  • 22:56 - 22:58
    of a kind of side-effect of just the way
  • 22:58 - 23:00
    we went about solving those problems. But
    that makes
  • 23:00 - 23:03
    me wonder, right. What if we don't have if
  • 23:03 - 23:06
    statements? Which is a crazy notions, right.
    I kind
  • 23:06 - 23:08
    of feel like programmers jobs are to write
    if
  • 23:08 - 23:09
    statements, right.
  • 23:09 - 23:11
    If I didn't need to write an if statement,
  • 23:11 - 23:13
    programming would be easy. And if you think
    about,
  • 23:13 - 23:16
    like, what are the features of assembly language,
    that
  • 23:16 - 23:19
    are also in Ruby. If statements is one of
  • 23:19 - 23:20
    them, right. You can't write an assembly language
    without
  • 23:20 - 23:23
    some method of branching the code. You have
    to
  • 23:23 - 23:25
    direct the code to go one place in a
  • 23:25 - 23:28
    certain case and another place in another
    case.
  • 23:28 - 23:30
    So what if Ruby didn't have if statements?
    There's
  • 23:30 - 23:32
    no if. There's no unless. No else. No switch.
  • 23:32 - 23:35
    None of that stuff. How in the heck would
  • 23:35 - 23:38
    we get anything done without if statements?
    Let's find
  • 23:38 - 23:39
    out.
  • 23:39 - 23:41
    So here, so we're gonna get away from the
  • 23:41 - 23:44
    exciting world of greeting people to a little
    bit
  • 23:44 - 23:46
    more of the real world of getting their money
  • 23:46 - 23:49
    from them. So here is an imaginary routine,
    so
  • 23:49 - 23:51
    let's so we've been given this credit card
    service
  • 23:51 - 23:54
    and the idea here is we want to charge
  • 23:54 - 23:55
    somebody some money, and then if anything
    goes wrong
  • 23:55 - 23:58
    we're gonna give them a reasonable explanation.
  • 23:58 - 24:01
    And so this is a pretty typical pattern, right.
  • 24:01 - 24:03
    We get back some blob of data. We ask
  • 24:03 - 24:06
    the blob of data some stuff and do things
  • 24:06 - 24:08
    based on that stuff. Right, that's pretty
    reasonable. Like,
  • 24:08 - 24:10
    if it's a success, fine. If it's not we
  • 24:10 - 24:13
    compare the error code to some magic value
    and
  • 24:13 - 24:16
    that means expired and, and I, and else must
  • 24:16 - 24:19
    mean declined, and because we're doing network
    programming we
  • 24:19 - 24:22
    gotta, you know, we gotta rescue everything.
    Cause, you
  • 24:22 - 24:25
    know, that might, something might go wrong
    there.
  • 24:25 - 24:28
    So without if statements, how might we implement
    something
  • 24:28 - 24:30
    like this?
  • 24:30 - 24:33
    Well, if there were no if statements, I would
  • 24:33 - 24:35
    bet that the creator and designer of the credit
  • 24:35 - 24:39
    card service might design an API a little
    differently,
  • 24:39 - 24:41
    right. This design of passing back a blob
    of
  • 24:41 - 24:43
    data and hoping you know what to do with
  • 24:43 - 24:45
    it is a lot more difficult if you don't
  • 24:45 - 24:47
    have these branching structures.
  • 24:47 - 24:49
    So the credit card service might be designed
    in
  • 24:49 - 24:51
    a way that doesn't require having if statements.
    So
  • 24:51 - 24:54
    let's see what that might look like, right.
  • 24:54 - 24:57
    What it might do instead is map every possible
  • 24:57 - 25:00
    thing that could happen to some code. SO I'm
  • 25:00 - 25:04
    the caller. I'm gonna say, for every possible
    outcome,
  • 25:04 - 25:05
    here's the code I'd like you to run if
  • 25:05 - 25:07
    that happens, and then the credit card service
    will
  • 25:07 - 25:11
    sort out what outcome actually did happen
    and call
  • 25:11 - 25:12
    the right code.
  • 25:12 - 25:16
    So that might look something like this. Right,
    on
  • 25:16 - 25:20
    success do nothing, on decline, on expiration,
    on exception.
  • 25:20 - 25:23
    So this is kind of interesting, right. What,
    for,
  • 25:23 - 25:27
    for one thing, again, typographically, everything's
    together. It's kind
  • 25:27 - 25:29
    of nice. We, we've brought this exception
    up to
  • 25:29 - 25:32
    where it belongs, because exceptions are just
    as likely
  • 25:32 - 25:34
    to happen, so it should, it doesn't deserve
    its
  • 25:34 - 25:37
    special place down at the end.
  • 25:37 - 25:39
    And this also reads a lot clearer, right.
    I
  • 25:39 - 25:41
    don't have to make that mental shift of like,
  • 25:41 - 25:44
    if some field equals some magic value then
    that
  • 25:44 - 25:46
    means the concept of expiration. I can just
    call
  • 25:46 - 25:50
    a method that says what it is.
  • 25:50 - 25:52
    So that's kind of cool, right. We skirted
    the
  • 25:52 - 25:54
    issue by redesigning the API to not need if
  • 25:54 - 25:59
    statements. And, but this, there's some negatives,
    right. Like
  • 25:59 - 26:03
    this is totally custom, totally proprietary
    to this service.
  • 26:03 - 26:05
    So this isn't like a generalized language
    construct that
  • 26:05 - 26:07
    we might be able to use. It's, it's very
  • 26:07 - 26:09
    one-off.
  • 26:09 - 26:11
    If statements are, are handy, because when
    we talk
  • 26:11 - 26:12
    about what code is supposed to do we use
  • 26:12 - 26:15
    the word if. That's why it's in the language.
  • 26:15 - 26:16
    SO this gets rid of that. So you could
  • 26:16 - 26:18
    say that, that if you have a large code
  • 26:18 - 26:21
    base, had lots of things that worked like
    this,
  • 26:21 - 26:23
    it could be kind of strange.
  • 26:23 - 26:25
    So I'm gonna ask again, what does this let
  • 26:25 - 26:28
    us do that this if statement approach didn't
    let
  • 26:28 - 26:32
    us do? So let's say I screw up when
  • 26:32 - 26:34
    I'm implementing my credit charge handler,
    and I forget
  • 26:34 - 26:37
    to handle the case where someone's card is
    expired.
  • 26:37 - 26:38
    SO I just have this code. And again, it
  • 26:38 - 26:41
    looks nice. It reads nice. Everything is good.
    My
  • 26:41 - 26:42
    tests all pass.
  • 26:42 - 26:46
    The failure was that I didn't understand every
    possible
  • 26:46 - 26:48
    outcome that could happen when I'm using the
    credit
  • 26:48 - 26:50
    card service, right. So I am living in the
  • 26:50 - 26:53
    fantasy world where I can charge credit cards,
    and
  • 26:53 - 26:55
    the garbage collector who has made the credit
    card
  • 26:55 - 26:58
    service for me has, has to explain to me
  • 26:58 - 27:00
    at some level what I need to do.
  • 27:00 - 27:02
    And I haven't, I haven't understood that.
    Now, if
  • 27:02 - 27:05
    I did make this mistake, it's really hard
    to
  • 27:05 - 27:07
    find out that this happened, right. You might
    have
  • 27:07 - 27:11
    people buying things and being told that they
    successfully
  • 27:11 - 27:13
    purchased, but then they never get their item,
    which
  • 27:13 - 27:16
    is bad. Or worse, they could be told that
  • 27:16 - 27:17
    they successfully purchased and then they
    did get their
  • 27:17 - 27:19
    item. So we're giving away things for free.
  • 27:19 - 27:22
    This is a very hard mistake to find. And
  • 27:22 - 27:26
    it has disastrous consequences. And so the
    hope, right,
  • 27:26 - 27:27
    the way that we prevent ourselves from making
    a
  • 27:27 - 27:30
    mistake like this is we hope that our garbage
  • 27:30 - 27:32
    collector, who created our credit card service
    wrote enough
  • 27:32 - 27:36
    documentation and explained things well enough
    that we understand.
  • 27:36 - 27:38
    And that we read that documentation and totally
    understood
  • 27:38 - 27:42
    how to use this API.
  • 27:42 - 27:44
    So with the way that we normally do thing,
  • 27:44 - 27:47
    that's what we have. We have hope. Here we
  • 27:47 - 27:50
    could actually check, right. Because what
    we're doing, this
  • 27:50 - 27:53
    code isn't actually running. This code is
    mapping outcomes
  • 27:53 - 27:56
    to code. But it's not actually running the
    code.
  • 27:56 - 27:58
    This guy, the credit card service is actually
    running
  • 27:58 - 27:59
    the code.
  • 27:59 - 28:02
    So before the credit card service runs the
    code,
  • 28:02 - 28:04
    it could check to see if I handled everything.
  • 28:04 - 28:06
    It could check and it could notice, I didn't
  • 28:06 - 28:10
    provide any code for the on expiration case.
    And
  • 28:10 - 28:12
    it could decide, dude, you did not understand
    how
  • 28:12 - 28:15
    to use me. I'm not gonna go forward because
  • 28:15 - 28:18
    you, something is broken. You have failed.
    If you
  • 28:18 - 28:20
    want to give away products, that is cool with
  • 28:20 - 28:22
    me, the credit card service, but you need
    to
  • 28:22 - 28:24
    tell me explicitly that you knew that there
    was
  • 28:24 - 28:26
    this case to handle and that you handled it
  • 28:26 - 28:28
    in some way.
  • 28:28 - 28:30
    That's kind of cool, right. You can't do that
  • 28:30 - 28:33
    with if statements. It's impossible to do
    with if
  • 28:33 - 28:34
    statements, unless you remember to call some
    magic method
  • 28:34 - 28:38
    or something. And here, instead of relying
    on documentation
  • 28:38 - 28:40
    and my ability to read and understand how
    to
  • 28:40 - 28:43
    use this credit card service, the API itself
    can
  • 28:43 - 28:46
    bake in all of this safety. It can, it
  • 28:46 - 28:49
    can encapsulate the knowledge that our garbage
    collector has
  • 28:49 - 28:52
    so that we can live in fantasy land.
  • 28:52 - 28:55
    Which is kind of cool. So it's something,
    and
  • 28:55 - 28:57
    I should point out, I didn't come up with
  • 28:57 - 28:59
    this, this little pattern and then write a
    talk
  • 28:59 - 29:00
    around it. I just came up with the talk
  • 29:00 - 29:03
    and I just tried to, tried to write this
  • 29:03 - 29:06
    code without if statements, and that's kind
    of what
  • 29:06 - 29:07
    I came up with. So it's kind of interesting
  • 29:07 - 29:09
    that that is something that fell out, that
    I
  • 29:09 - 29:13
    can do more things.
  • 29:13 - 29:15
    But I've skated the issue of the if statement,
  • 29:15 - 29:17
    right. I've, I've changed the rules so I didn't
  • 29:17 - 29:20
    need an if statement to implement this. But
    somebody,
  • 29:20 - 29:23
    somewhere, is gonna have to figure out, did
    the
  • 29:23 - 29:26
    credit card succeed or not, and do something
    or
  • 29:26 - 29:27
    do something else. So somebody has to do that
  • 29:27 - 29:28
    somewhere.
  • 29:28 - 29:31
    So let's delve more into our imagined credit
    card
  • 29:31 - 29:34
    service. And, and see where that, see where
    that
  • 29:34 - 29:36
    leads us. SO we can imagine that the way
  • 29:36 - 29:39
    this works is it'll sort out some URL. It'll
  • 29:39 - 29:41
    call the URL over the internet, get some status
  • 29:41 - 29:46
    back, and then we'll have the outcome class
    kind
  • 29:46 - 29:48
    of handle figuring out what that result means.
  • 29:48 - 29:50
    So the outcome class, since it has all these
  • 29:50 - 29:52
    blocks of code that we gave it, it's going
  • 29:52 - 29:54
    to look at the results of our restful API
  • 29:54 - 29:56
    call, figure out what it means and figure
    out
  • 29:56 - 29:58
    what block of code to call.
  • 29:58 - 30:01
    That sounds like a job for if statements.
    So
  • 30:01 - 30:04
    taking a step deeper, right, our, our method
    has
  • 30:04 - 30:08
    kind of three parts. It gets status from result,
  • 30:08 - 30:10
    it'll call on the private method that, that
    sorts
  • 30:10 - 30:13
    out what that status means. It returns the
    name
  • 30:13 - 30:14
    of a method and then we will call that
  • 30:14 - 30:16
    method on ourselves.
  • 30:16 - 30:19
    So the what to call method is where we
  • 30:19 - 30:20
    have these if statements. So this might be
    how
  • 30:20 - 30:23
    we would do it if we, we had if
  • 30:23 - 30:27
    statements. But we don't. So we could do this
  • 30:27 - 30:29
    outcome type thing again, we could just keep
    doing
  • 30:29 - 30:32
    outcomes within outcomes and all that, but
    somebody somewhere's
  • 30:32 - 30:34
    gonna have to compare two values and decide
    to
  • 30:34 - 30:35
    do one thing or the other.
  • 30:35 - 30:37
    So let's not do the outcome thing here. Let's
  • 30:37 - 30:40
    try to do this a different way.
  • 30:40 - 30:43
    The result is gonna be super strange.
  • 30:43 - 30:45
    So we made a little pseudo code here. So
  • 30:45 - 30:48
    we, what we have is we have some expressions
  • 30:48 - 30:50
    and if this expression is true we want to
  • 30:50 - 30:52
    do this, and if this is true we want
  • 30:52 - 30:53
    to do this, and all else we could do
  • 30:53 - 30:56
    that. Right, that's the basic logic that we
    want.
  • 30:56 - 30:58
    So since we don't have these if statements,
    how
  • 30:58 - 31:01
    can we capture these expressions in some way
    that
  • 31:01 - 31:04
    we can evaluate them. Well, we could wrap
    them
  • 31:04 - 31:06
    in a lambda. So now we have a mapping
  • 31:06 - 31:10
    of a lambda representing our expression to
    some symbol.
  • 31:10 - 31:11
    So what we want to do is we want
  • 31:11 - 31:13
    to go through all of these lambdas that we
  • 31:13 - 31:16
    have and find the first one that's true.
  • 31:16 - 31:18
    So if we had them in a list, say,
  • 31:18 - 31:20
    right, so now we have a list of pairs.
  • 31:20 - 31:22
    Each pair is a lambda representing our expression
    and
  • 31:22 - 31:25
    the method to call. So we want the first
  • 31:25 - 31:27
    one in this list, so that's detect. And so
  • 31:27 - 31:29
    detect, if you don't know, it, it finds the
  • 31:29 - 31:32
    first element in a list for which a particular
  • 31:32 - 31:33
    condition holds.
  • 31:33 - 31:36
    So in that case, that condition is to call
  • 31:36 - 31:38
    our lambdas and see if they return true with
  • 31:38 - 31:41
    our input. So that is going to return one
  • 31:41 - 31:44
    of our pairs. Our pair being the, the lambda
  • 31:44 - 31:45
    and the method. Of course, we don't care about
  • 31:45 - 31:48
    the lambda. So we destructure it and we get
  • 31:48 - 31:49
    the method.
  • 31:49 - 31:51
    And if detect didn't find anything, it's going
    to
  • 31:51 - 31:53
    return nil, which means we will return call
    on
  • 31:54 - 31:55
    exception. So that is how you do that without
  • 31:55 - 31:57
    any if statements.
  • 31:57 - 31:59
    That is weird, right. I mean, does this look
  • 31:59 - 32:04
    normal to anyone? If I came across this, it
  • 32:04 - 32:06
    would take me a long time to learn that
  • 32:06 - 32:09
    this was an if statement and I would venture
  • 32:09 - 32:12
    to say a language for which this was the
  • 32:12 - 32:14
    primary way to direct logic would probably
    not be
  • 32:14 - 32:16
    a successful language.
  • 32:16 - 32:20
    Cause this is very strange.
  • 32:20 - 32:22
    So I must ask myself, is there something I
  • 32:22 - 32:23
    can do with this, is there some advantage
    to
  • 32:23 - 32:27
    this that I didn't get with these if statements?
  • 32:27 - 32:31
    So let's suppose I made, I made an error.
  • 32:31 - 32:33
    Now, this is very simplified, right. You can
    see
  • 32:33 - 32:35
    here that two hundred is less than five hundred.
  • 32:35 - 32:38
    So this code is never gonna be called. Now
  • 32:38 - 32:40
    this is super simple. You can kind of see
  • 32:40 - 32:42
    by inspection that there's a problem, and
    it would
  • 32:42 - 32:44
    be very simple to write a test that reveals
  • 32:44 - 32:46
    this and you would probably have those tests.
  • 32:46 - 32:49
    So I'm asking you to remember that code that
  • 32:49 - 32:51
    you have fully tested but yet was buggy, because
  • 32:51 - 32:54
    there is something you forgot, or a bunch
    of
  • 32:54 - 32:56
    if statements that were very hard to understand
    all
  • 32:56 - 33:00
    at once, right. And that you have totally
    tested,
  • 33:00 - 33:02
    and it went to production and then it didn't
  • 33:02 - 33:05
    work because of something like this.
  • 33:05 - 33:08
    So the only way, right, the only way to
  • 33:08 - 33:10
    solve this is to have a lot of tests
  • 33:10 - 33:14
    and just be diligent, right. Just try harder.
    But
  • 33:14 - 33:16
    is there a way with this other crazy structure
  • 33:16 - 33:19
    that we could do that? And so you might
  • 33:19 - 33:21
    be wondering why, you might have noticed that
    I
  • 33:21 - 33:24
    used a list, right, instead of a map between
  • 33:24 - 33:25
    the map and all that stuff. That's because
    the
  • 33:25 - 33:27
    list retains the order. And so the order in
  • 33:27 - 33:32
    which we evaluate these things is very important.
  • 33:32 - 33:35
    So how could we, how could we detect this
  • 33:35 - 33:39
    error? So, since our logic is not encoded
    in
  • 33:39 - 33:41
    the programming language, but is actually
    encoded in a
  • 33:41 - 33:44
    data structure, we could examine this data
    structure and,
  • 33:44 - 33:46
    and find out things about it. So if we
  • 33:46 - 33:48
    assumed that our crazy version of Ruby that
    has
  • 33:48 - 33:51
    no if statements and requires us to do this
  • 33:51 - 33:55
    exists, it seems logical that it might have
    a
  • 33:55 - 33:59
    class that helps us write this weird if statement.
  • 33:59 - 34:01
    So, and, again, all of this code works. There's
  • 34:01 - 34:03
    a link at the end. This all absolutely works.
  • 34:03 - 34:06
    So let's say this logic class here handles
    all
  • 34:06 - 34:08
    that mumbo jumbo with going through the list
    and
  • 34:08 - 34:10
    detect and all that crap. So all we have
  • 34:10 - 34:12
    to do is this. Now, I'm not saying this
  • 34:12 - 34:15
    is not weird - this is still strange. But
  • 34:15 - 34:18
    it kind of creates a class concept here.
  • 34:18 - 34:22
    So when we evaluate the logic, given an input,
  • 34:22 - 34:25
    the logic could say, hey, that input is true
  • 34:25 - 34:28
    for more than one expression. So I don't know
  • 34:28 - 34:30
    which one you meant. I don't know what to
  • 34:30 - 34:32
    do. I'm just gonna assume that you haven't
    thought
  • 34:32 - 34:34
    this through, you've screwed something up,
    and I'm just
  • 34:34 - 34:36
    gonna, I'm just gonna blow up.
  • 34:36 - 34:39
    With a nonexclusive disjunction error. That's
    the best name
  • 34:39 - 34:41
    I could come up with for that, for that
  • 34:41 - 34:44
    concept. It took a lot of Wikipedia sleuthing
    to
  • 34:44 - 34:47
    figure that out.
  • 34:47 - 34:50
    So that's kind of handy, right. So if every
  • 34:50 - 34:52
    crazy set of conditionals I ever wrote could
    be
  • 34:52 - 34:54
    evaluated by someone smarter than me and tell
    me
  • 34:54 - 34:56
    that I didn't think it through and things
    aren't
  • 34:56 - 35:00
    mutually exclusive, that would be useful to
    me.
  • 35:00 - 35:02
    So to fix it, we have to do this,
  • 35:02 - 35:05
    right. Now these two things are mutually exclusive.
    They
  • 35:05 - 35:08
    will never be true for the same input. But,
  • 35:08 - 35:12
    but, right, everybody's bothered by this repetition
    I hope.
  • 35:12 - 35:15
    Cause this bothers me. Like, I don't like
    having
  • 35:15 - 35:16
    to say the same thing twice. That's what the
  • 35:16 - 35:19
    if statement gave us - the else concept.
  • 35:19 - 35:21
    But this is just blocks and, and lambdas,
    so
  • 35:21 - 35:24
    we could extract them and reuse them. And
    now
  • 35:24 - 35:26
    look at our code, right. Logic on success,
    then
  • 35:26 - 35:29
    return call and success. Logic on decline,
    then return
  • 35:29 - 35:32
    call and decline. Logic evaluate status or
    else call
  • 35:32 - 35:33
    on exception.
  • 35:33 - 35:35
    It has that awesome Ruby-like quality where
    you can
  • 35:35 - 35:38
    just read the code out and it's like, executable
  • 35:38 - 35:40
    pseudo code. Like that's kind of cool. Even
    though,
  • 35:40 - 35:42
    like, it's kind of weird what we're doing,
    it's
  • 35:42 - 35:44
    pretty easy to understand. And this is a lot
  • 35:44 - 35:47
    easier to understand than that crazy list
    of, and
  • 35:47 - 35:48
    detect and all that.
  • 35:48 - 35:51
    So I could see a language that had this
  • 35:51 - 35:53
    as the way of branching. That might be a
  • 35:53 - 35:55
    little more successful than, than our other
    one.
  • 35:55 - 36:01
    So, yeah, that's, that's, that's, that's kind
    of crazy.
  • 36:01 - 36:04
    So that was a lot of weird stuff, and,
  • 36:04 - 36:06
    like I said, it all works, and, and I
  • 36:06 - 36:07
    can, I'll show you the link at the end.
  • 36:07 - 36:09
    I'm not telling you you should do that ever.
  • 36:09 - 36:11
    I'm not saying you should put that in your
  • 36:11 - 36:13
    production code base. I certainly haven't.
  • 36:13 - 36:18
    But what you should take away is that sometimes
  • 36:18 - 36:22
    more interesting things can come if you remove
    tools,
  • 36:22 - 36:24
    if you remove techniques. If those things
    that you
  • 36:24 - 36:28
    are really hold dear or think that there's
    no
  • 36:28 - 36:30
    way I could ever do without X - well,
  • 36:30 - 36:32
    try solving the problem without X and see
    what
  • 36:32 - 36:34
    happens. You might be surprised. You might
    come up
  • 36:34 - 36:38
    with something that is actually really useful,
    and maybe
  • 36:38 - 36:38
    gives you more power.
  • 36:38 - 36:41
    I mean this, this business with the credit
    card
  • 36:41 - 36:44
    service where you map the outcome to the code
  • 36:44 - 36:46
    and it blows up if you haven't thought of
  • 36:46 - 36:48
    everything, like, that seems actually kind
    of useful, like,
  • 36:48 - 36:51
    especially for something as critical as like
    taking money
  • 36:51 - 36:52
    from people. Like I kind of want to get
  • 36:52 - 36:54
    that really right.
  • 36:54 - 36:56
    So it's kind of interesting. So I'd encourage
    you
  • 36:56 - 36:58
    to do the same things.
  • 36:58 - 37:00
    That's all I've got. I do want to pitch
  • 37:00 - 37:02
    from my company, we are small. We have a
  • 37:02 - 37:05
    business model that works and is easy to understand,
  • 37:05 - 37:08
    which I hope you find interesting. If you're
    interested
  • 37:08 - 37:11
    at all, come talk to me. Here's the links
  • 37:11 - 37:14
    for everything. The book, Senior Software
    Engineer, that I
  • 37:14 - 37:16
    told you I wouldn't talk about cause it's
    not
  • 37:16 - 37:18
    relevant, well, you can buy it today for $10
  • 37:18 - 37:20
    if you'd like. That's all I got.
  • 37:20 - 37:22
    I think we have a few time for questions
  • 37:22 - 37:25
    if anyone, if anyone has them.
  • 37:27 - 37:29
    Cool. Well, if you got any other questions,
    come
  • 37:29 - 37:31
    up and talk to me and I really appreciate
  • 37:31 - 37:34
    you guys coming. Thanks.
Title:
Ruby Conf 2013 - Eliminating branching, nil and attributes - let's get weird
Description:

more » « less
Duration:
37:57

English subtitles

Revisions