< Return to Video

RailsConf 2014 - Refactoring Towards Component-based Rails Architectures

  • 0:17 - 0:19
    STEPHAN HAGEMANN: Thanks for coming.
  • 0:19 - 0:21
    You came to Big Rails.
  • 0:21 - 0:23
    If you did not intend to go to Big Rails.
  • 0:23 - 0:25
    My wife's actually currently in a plane,
  • 0:25 - 0:28
    and so for some reason I had to think of a
    plane metaphor.
  • 0:28 - 0:29
    And her flight just got canceled.
  • 0:29 - 0:30
    If you did not intend to go to Big
  • 0:30 - 0:33
    Rails, which I can understand. It can be messy.
  • 0:33 - 0:38
    Better get out now, the flight might be bumpy.
  • 0:38 - 0:40
    So I want to talk about really large Rails
  • 0:40 - 0:42
    apps, and my buddy Austin suggested, a couple
    days
  • 0:42 - 0:46
    ago, let's use GitHub. Search for Rails. Sort
    by
  • 0:46 - 0:49
    size. This is officially the biggest Rails
    app you've
  • 0:49 - 0:52
    never heard of on GitHub. It's open source.
    It
  • 0:52 - 0:55
    also only has eight models. Which is because
    they
  • 0:55 - 0:56
    upload all their assets.
  • 0:56 - 0:58
    It's a hundred and fifty megabytes big, and
    that's
  • 0:58 - 1:01
    not the kind of big I'm talking about. I
  • 1:01 - 1:05
    want to talk about component-based Rails architectures
    and why
  • 1:05 - 1:09
    you should refactor towards them. And how
    to do
  • 1:09 - 1:12
    that.
  • 1:12 - 1:15
    Component-based Rails architectures is a term
    I use. I
  • 1:15 - 1:19
    tag my Tweets about it as #cbra, and I'm
  • 1:19 - 1:20
    the only person in the world doing it. But
  • 1:20 - 1:25
    if you use that too, I'm certainly replying.
    And,
  • 1:25 - 1:28
    here's a memo for that.
  • 1:28 - 1:32
    If I can get one idea in straight off
  • 1:32 - 1:36
    the bat, then it is that this is, this
  • 1:36 - 1:39
    stuff is easy. If you can think about your
  • 1:39 - 1:42
    application by writing, by painting boxes
    and drawing arrows
  • 1:42 - 1:44
    for things that depend on each other and how
  • 1:44 - 1:47
    they interact, then you know everything else
    you need
  • 1:47 - 1:50
    to know about component-based architectures
    and you just need
  • 1:50 - 1:53
    to start doing them to what I think will
  • 1:53 - 1:56
    be improving the quality of your application
    and the
  • 1:56 - 1:58
    quality of your code.
  • 1:58 - 2:01
    Since I called this talk refactoring towards
    component-based Rails
  • 2:01 - 2:03
    architectures, this talk assumes that you
    all know what
  • 2:03 - 2:06
    that is. So, no. I will actually explain what
  • 2:06 - 2:07
    that is to you. You're not screwed if you
  • 2:07 - 2:10
    don't know what that is.
  • 2:10 - 2:15
    So, I started talking and actually writing
    applications pretty
  • 2:15 - 2:19
    much exclusively in this kind of odd way,
    so,
  • 2:19 - 2:23
    like, two, three years ago. And it, I wrote
  • 2:23 - 2:26
    this sample app that you find at this address.
  • 2:26 - 2:30
    I'm shageman with one n on GitHub. And there's
  • 2:30 - 2:33
    just the_next_big_thing sample app.
  • 2:33 - 2:36
    It does nothing. Only it shows you the structure
  • 2:36 - 2:37
    and how to hook certain things up. And let
  • 2:37 - 2:40
    me quickly go through what that means. So
    this
  • 2:40 - 2:43
    is the root of the project. And, as you
  • 2:43 - 2:45
    can see, it's not a Rails application. But
    it
  • 2:45 - 2:48
    is. There's actually no particular prescribed
    way on how
  • 2:48 - 2:50
    to do this. In many apps where I've done
  • 2:50 - 2:52
    this, the Rails application is still at the
    root
  • 2:52 - 2:54
    of the project. But in this particular one,
    I
  • 2:54 - 2:57
    chose the other version, where Rails moves
    into a
  • 2:57 - 2:59
    sub-folder and, as you can see here, so this
  • 2:59 - 3:03
    looks pretty much like Rails. But it doesn't
    have
  • 3:03 - 3:05
    an app folder. There, and you might be asking,
  • 3:05 - 3:07
    is there nothing happening in this app?
  • 3:07 - 3:10
    Well, there is. Here, we see there's, at least
  • 3:10 - 3:12
    one thing is mounted. There is an engine that's
  • 3:12 - 3:18
    mounted. So, Teaser::Engine. I don't know
    if anyone has
  • 3:18 - 3:21
    ever downloaded that from RubyGems. Well,
    don't try. I
  • 3:21 - 3:23
    don't know what that gem would be. But I
  • 3:23 - 3:24
    didn't upload it there.
  • 3:24 - 3:25
    Let's look at the gem file to find out
  • 3:25 - 3:28
    what that gem is. So this is the, the
  • 3:28 - 3:30
    only kind of trick that you need to employ
  • 3:30 - 3:34
    when you want to write component-based architectures.
    And that
  • 3:34 - 3:36
    is, you use gems as not a, not as
  • 3:36 - 3:39
    a distribution mechanism, but just as a packaging
    mechanism
  • 3:39 - 3:41
    for parts of your application.
  • 3:41 - 3:43
    You leave them in the same source tree and
  • 3:43 - 3:46
    you just reference them. And then you can
    do
  • 3:46 - 3:48
    everything you're used to with those things.
  • 3:48 - 3:49
    So, as you can see here, if we go
  • 3:49 - 3:51
    to the components folder, we expect to see
    a
  • 3:51 - 3:53
    teaser folder. Ah. Which we do. And there
    is
  • 3:53 - 3:56
    an engine. So that's just a Rails. Ah, sorry.
  • 3:56 - 3:59
    A RubyGem that is pimped a little bit so
  • 3:59 - 4:03
    it has Active star. All the Actives. So Rails
  • 4:03 - 4:06
    in it. And this, indeed, now looks like an
  • 4:06 - 4:07
    application.
  • 4:07 - 4:10
    If you don't know what an engine is, it's
  • 4:10 - 4:12
    essentially Rails minus everything you need
    to actually get
  • 4:12 - 4:16
    it booted. So, if we look in here, what
  • 4:16 - 4:18
    we can see, you know, there's a routes file
  • 4:18 - 4:21
    and this engine is doing something, right.
    There's. It's
  • 4:21 - 4:24
    normal. Here we'll look in apps. So the controller.
  • 4:24 - 4:26
    So you can see this is namespaced under the
  • 4:26 - 4:29
    name, which is nice. But it's just, you know,
  • 4:29 - 4:33
    your ordinary controller. But, again, everything's
    namespaced.
  • 4:33 - 4:38
    There's assets in here. Yeah. This is pretty
    normal,
  • 4:38 - 4:43
    standard stuff. We even have migrations down
    here in
  • 4:43 - 4:46
    this engine. What else would I talk about?
    Well,
  • 4:46 - 4:48
    ah, yes. Maybe the coolest part. There's specs
    in
  • 4:48 - 4:50
    here. I like to use rSpec. That could be
  • 4:50 - 4:52
    tests in here if you're doing this and liking
  • 4:52 - 4:53
    those better.
  • 4:53 - 4:58
    But there's, there's a spec here for this
    controller
  • 4:58 - 5:00
    that I just looked at, and the cool thing
  • 5:00 - 5:03
    about that, and I don't know how to emphasize
  • 5:03 - 5:04
    it more than to come up to the front
  • 5:04 - 5:07
    of the stage and say it's very important that
  • 5:07 - 5:09
    I can run these tests, and the only thing
  • 5:09 - 5:11
    that these tests are gonna load is the code
  • 5:11 - 5:14
    from this engine, and not from all the other
  • 5:14 - 5:16
    stuff in my Big Rails application.
  • 5:16 - 5:20
    So, just by there being a spec folder in
  • 5:20 - 5:22
    here, I have a part of which I can
  • 5:22 - 5:25
    prove that it is small. Or, at least, as
  • 5:25 - 5:27
    big as only this part, and not depending on
  • 5:27 - 5:29
    anything else.
  • 5:29 - 5:33
    I, for, what I typically do, then, to kind
  • 5:33 - 5:36
    of bind these components together - and there's
    more
  • 5:36 - 5:38
    in this folder, as you can see. There's this
  • 5:38 - 5:40
    event counter signup and whatnot. So I write
    a
  • 5:40 - 5:42
    little script here that binds all the tests.
    As
  • 5:42 - 5:44
    you can see there's some request specs and
    some
  • 5:44 - 5:46
    Jasmine specs, and if you look into the other
  • 5:46 - 5:49
    folders, you find more of these test files.
    And
  • 5:49 - 5:54
    then in the root. I typically put this, this
  • 5:54 - 5:56
    build script here. And what this does is loops
  • 5:56 - 5:58
    over all the folders and tries to find test
  • 5:58 - 5:59
    files and runs them.
  • 5:59 - 6:01
    So you can still run this as the app,
  • 6:01 - 6:03
    as the specs to one application. But if you
  • 6:03 - 6:05
    just change one part, you can just test that
  • 6:05 - 6:09
    one part and still be sure that it works.
  • 6:09 - 6:12
    So, now that you know what these applications
    are,
  • 6:12 - 6:13
    you don't need to think about all those little
  • 6:13 - 6:15
    things. How to hook them up. You'll find out
  • 6:15 - 6:16
    about that when you try to do it. What's
  • 6:16 - 6:18
    important about them is that you can now talk
  • 6:18 - 6:22
    about your application as a sum of smaller
    parts.
  • 6:22 - 6:24
    For example, the app that I just showed you
  • 6:24 - 6:27
    is a empty Rails container that mounts an
    engine
  • 6:27 - 6:28
    that uses two other engines that I didn't
    talk
  • 6:28 - 6:30
    about and another gem.
  • 6:30 - 6:32
    This is a project that it recently, it o-
  • 6:32 - 6:34
    that was a tiny project, so this was Tiny
  • 6:34 - 6:38
    Rails. Empty Rails container. Two engines.
    The one was
  • 6:38 - 6:41
    using two gems to talk to APIs, and the
  • 6:41 - 6:45
    other one was just straight-up, pretty much
    normal application.
  • 6:45 - 6:47
    Or this site that was a travel site. It
  • 6:47 - 6:50
    was so small, we didn't even bother to use
  • 6:50 - 6:52
    engines. We just put a couple gems in there
  • 6:52 - 6:54
    that were talking to APIs.
  • 6:54 - 6:56
    This site was a bit bigger. It started out
  • 6:56 - 6:59
    like this. We had six engines, one gem, and
  • 6:59 - 7:01
    it ended up about like this. But this is
  • 7:01 - 7:03
    a lie, because there were about twice as many
  • 7:03 - 7:05
    engines, only the other ones are abstracted
    away for
  • 7:05 - 7:07
    clarity in this picture. As you can see, it's
  • 7:07 - 7:08
    a very clear picture.
  • 7:08 - 7:12
    Now, this looks chaotic. But the fact that
    I
  • 7:12 - 7:15
    can draw such a chaotic picture about your
    application,
  • 7:15 - 7:17
    but if you, if you were to draw the
  • 7:17 - 7:19
    arrows a bit straighter, you would see that
    the
  • 7:19 - 7:23
    dependencies all go in one direction, and
    that there
  • 7:23 - 7:26
    are parts that other parts are based upon,
    right.
  • 7:26 - 7:28
    So this app is composed of parts, and it's
  • 7:28 - 7:31
    no longer a ball of mud.
  • 7:31 - 7:33
    The fact that you can see that this is
  • 7:33 - 7:37
    a complicated domain is an improvement, despite
    this picture
  • 7:37 - 7:38
    looking a bit weird. This picture is from
    Ben
  • 7:38 - 7:41
    Smith's talk about how he architected his
    Big Rails
  • 7:41 - 7:44
    app for success, which he gave at Rocky Mountain
  • 7:44 - 7:47
    Ruby last year. And I recommend you watch
    that
  • 7:47 - 7:48
    talk.
  • 7:48 - 7:51
    So, if you're like, what? Now? Why would I
  • 7:51 - 7:54
    do that? As I just said. Because it helps.
  • 7:54 - 7:57
    When applications get big, I believe it's
    fundamentally important
  • 7:57 - 7:59
    to be able to think about the parts of
  • 7:59 - 8:05
    the application independently, as much as
    possible.
  • 8:05 - 8:08
    There's a bunch of resources that, you know.
    I've
  • 8:08 - 8:10
    given talks about this. Ben's given talks
    about this.
  • 8:10 - 8:13
    There's blog posts about this. And there's,
    most importantly,
  • 8:13 - 8:17
    that repository that I recommend you look
    at.
  • 8:17 - 8:23
    OK. Back to Big Rails. How big? Does anyone
  • 8:23 - 8:25
    here think they're working on a big Rails
    application?
  • 8:25 - 8:30
    OK. That's about a third. So, I've, I think
  • 8:30 - 8:32
    I've worked on a couple, but I didn't know
  • 8:32 - 8:34
    what to show, because I work for Pivatol Labs
  • 8:34 - 8:36
    and we consult and the code is our clients',
  • 8:36 - 8:39
    so I can't show it here, so I won't.
  • 8:39 - 8:41
    But I went onto this thing called Google and
  • 8:41 - 8:43
    I searched for open source Rails apps, and
    there
  • 8:43 - 8:45
    they were. So these claim to be big Rails
  • 8:45 - 8:46
    apps.
  • 8:46 - 8:50
    How big, I wondered. Well, if you have, currently,
  • 8:50 - 8:54
    on your laptop, your company's code, please,
    execute this
  • 8:54 - 8:57
    script and Tweet the result with a #cbra hashtag,
  • 8:57 - 8:59
    cause this is just gonna open how many lines
  • 8:59 - 9:01
    of code your app has.
  • 9:01 - 9:03
    And here's the result for this list of applications.
  • 9:03 - 9:07
    So, as you can see, they're not all simi-
  • 9:07 - 9:10
    not all the same interpretation of big. So
    we're
  • 9:10 - 9:14
    going from about 400,000 lines of code to
    still
  • 9:14 - 9:17
    in the thousands. If you look at the files,
  • 9:17 - 9:21
    same picture. Thousands of files for the biggest
    apps,
  • 9:21 - 9:25
    and still hundreds for the smaller ones.
  • 9:25 - 9:28
    I'll accept that as big. And I hope you
  • 9:28 - 9:33
    will too. Ever wonder what happens to the
    complexity
  • 9:33 - 9:37
    within a system as it grows? Something like
    this
  • 9:37 - 9:40
    happens. And maybe this is bad as that, and
  • 9:40 - 9:44
    you just can't take it anymore.
  • 9:44 - 9:47
    When you introduce structure, you fundamentally
    change the game.
  • 9:47 - 9:50
    Oh. I'm supposed to say, first, that this
    is
  • 9:50 - 9:53
    because the number of interactions between
    the elements inside
  • 9:53 - 9:56
    the system grows somewhat like an exponential,
    in an
  • 9:56 - 10:00
    exponential function when you add new, new
    parts to
  • 10:00 - 10:02
    this system.
  • 10:02 - 10:06
    So it explodes in complexity. Well, what if
    you
  • 10:06 - 10:11
    were able to split a system and use a
  • 10:11 - 10:15
    complex web of service objects, maybe, to
    connect the
  • 10:15 - 10:17
    two. But you have two smaller parts that can
  • 10:17 - 10:20
    now, that are now isolated, in some way, what
  • 10:20 - 10:22
    happens to the complexity?
  • 10:22 - 10:26
    Well, turns out, it's still this, and probably
    still
  • 10:26 - 10:33
    that. But only half as fast. And that's good.
  • 10:36 - 10:37
    If you. I wish I could run up to
  • 10:37 - 10:39
    the slide right now. But, you see that green
  • 10:39 - 10:42
    line at the bottom? It's almost flat. Now
    imagine
  • 10:42 - 10:45
    you could split it again, and again, and again,
  • 10:45 - 10:47
    and you always stay in this flatter part,
    so
  • 10:47 - 10:50
    your complexity never really explodes. You
    get those crazy
  • 10:50 - 10:52
    diagrams that I was showing earlier, but your
    complexity
  • 10:52 - 10:55
    doesn't explode quite as badly. You're still
    writing a
  • 10:55 - 10:57
    huge app, and that's something that I'm not
    gonna
  • 10:57 - 11:00
    discuss away. But you might be able to manage
  • 11:00 - 11:06
    it better.
  • 11:06 - 11:11
    The rich get rich and the poor get. Anyone?
  • 11:11 - 11:17
    Children. I. This is from a song from the
  • 11:17 - 11:20
    1920s, and while it's funny, the, the first
    part
  • 11:20 - 11:26
    of this alludes to a thing called preferential
    attachment.
  • 11:26 - 11:29
    Preferential attachment is a set of processes
    where, when,
  • 11:29 - 11:33
    where, god. This is so hard to say. Where,
  • 11:33 - 11:37
    when you, where the amount of things you have,
  • 11:37 - 11:38
    whatever that might be - the thing, or you
  • 11:38 - 11:43
    - defines how much you will get.
  • 11:43 - 11:48
    So, 2006, Chris Anderson I think, wrote about
    the
  • 11:48 - 11:51
    long tail in, in publishing and books. And
    he,
  • 11:51 - 11:54
    this, this curve became very popular. He called,
    I
  • 11:54 - 11:56
    think he even called the book The Long Tail.
  • 11:56 - 11:57
    And he was concentrated on the right side
    of
  • 11:57 - 11:59
    this tail.
  • 11:59 - 12:01
    So you have many, many small things that don't
  • 12:01 - 12:05
    get any traction. But, you know, Netflix allows
    us
  • 12:05 - 12:07
    to view all those movies that no one wants,
  • 12:07 - 12:09
    that no one else wants to see. But there's
  • 12:09 - 12:11
    just a very few movies at the front that
  • 12:11 - 12:14
    everyone wants to see. The Blockbusters. And,
    while the
  • 12:14 - 12:17
    long tail is very interesting, it's the ones
    in
  • 12:17 - 12:23
    the front that harvest most of the benefits,
    well
  • 12:23 - 12:25
    I guess in the case of movies.
  • 12:25 - 12:28
    So, the green to the yellow relationship is
    about,
  • 12:28 - 12:33
    80% of the, the tail versus 20% is inverse
  • 12:33 - 12:35
    in the relationship to how much they have.
    So
  • 12:35 - 12:38
    it's 20/80, 80/20.
  • 12:38 - 12:43
    And, preferential attachment, as I said, happens
    when you
  • 12:43 - 12:46
    already have a lot, so you get more. And
  • 12:46 - 12:48
    I have seen so many code bases that I
  • 12:48 - 12:50
    have the feeling there's something like that
    going on
  • 12:50 - 12:53
    in code. So I looked at these code bases,
  • 12:53 - 12:56
    and again, I typed in this bash script. First
  • 12:56 - 13:01
    try of course.
  • 13:01 - 13:02
    And I urge you to do the same. Now,
  • 13:02 - 13:04
    you will not be able to Tweet this, because
  • 13:04 - 13:07
    this lists all the files, all the Ruby files,
  • 13:07 - 13:11
    in your app by size. And when you do
  • 13:11 - 13:15
    that, that looks about like this for these
    applications.
  • 13:15 - 13:20
    Now, does that not look similar?
  • 13:20 - 13:22
    There's another way of saying this, you know,
    the
  • 13:22 - 13:25
    rich get richer. There's a German proverb.
    I'm from
  • 13:25 - 13:30
    Germany. Hi. That proverb is that Der Teufel
    scheißt
  • 13:30 - 13:32
    immer auf den größten Haufen. Or, the Devil
    always
  • 13:32 - 13:36
    shits on the biggest pile.
  • 13:36 - 13:39
    And I think something like that is going on
  • 13:39 - 13:46
    here. And which file might that be? So who
  • 13:46 - 13:48
    thinks that might be a good guess as to
  • 13:48 - 13:52
    which file that is? And, lower your, don't
    lower
  • 13:52 - 13:54
    your hand, because it's probably actually
    yours. I said
  • 13:54 - 13:56
    this two days ago and then the guy next
  • 13:56 - 13:58
    to me shows me his Ruby, his user file
  • 13:58 - 14:00
    and it's literally this long and I'm like,
    oh
  • 14:00 - 14:02
    god, don't do this to me.
  • 14:02 - 14:05
    But everyone else knows this problem. The
    user is
  • 14:05 - 14:07
    around earlier. He is important to the system,
    so
  • 14:07 - 14:11
    he attaches, he attracts functionality. But
    to the point
  • 14:11 - 14:13
    where I would say that is a pile of
  • 14:13 - 14:15
    shit, man.
  • 14:15 - 14:20
    And I thought that would be something else
    I
  • 14:20 - 14:22
    could find. So I looked at associations. Associations
    are
  • 14:22 - 14:29
    another way of expressing dependencies. In
    fact, so when,
  • 14:29 - 14:30
    I want to talk about has_manys, because I
    find
  • 14:30 - 14:32
    them particularly interesting.
  • 14:32 - 14:39
    So, you have something that has_many. User,
    maybe. So
  • 14:40 - 14:42
    since I assumed it was user, I want you
  • 14:42 - 14:45
    to read this code and, kind of reflecting
    on
  • 14:45 - 14:49
    yesterday's keynote, I find this file very
    readable. The
  • 14:49 - 14:56
    user has_many :cars, :flowers, :trees, :houses,
    :moods, :checks. Hopefully.
  • 14:56 - 14:57
    I think we can agree that it's very readable.
  • 14:57 - 15:00
    It makes a lot of sense and we can,
  • 15:00 - 15:02
    we can empathize with this class.
  • 15:02 - 15:04
    Have you ever wondered what's funny about
    this when
  • 15:04 - 15:06
    you look at the table and there is no
  • 15:06 - 15:09
    mention of :cars, :flowers, :trees, :houses,
    :moods, and :checks
  • 15:09 - 15:13
    in that table at all? You don't find it
  • 15:13 - 15:15
    funny to write that user class, but would
    you
  • 15:15 - 15:17
    find it funny if I wrote a color class
  • 15:17 - 15:19
    like that?
  • 15:19 - 15:20
    Why do we not write that color class? Why
  • 15:20 - 15:22
    do we always write that user class? I'll tell
  • 15:22 - 15:25
    you why. Because users are important to us,
    and
  • 15:25 - 15:27
    we always write them first, and then we attach
  • 15:27 - 15:30
    all sorts of stuff to them that doesn't belong
  • 15:30 - 15:35
    to them. This table clearly says what belongs
    to,
  • 15:35 - 15:37
    sorry, a user. Namely, in this case, a name
  • 15:37 - 15:40
    and a home.
  • 15:40 - 15:42
    So I've kind of gotten the opinion that we
  • 15:42 - 15:47
    shouldn't be using has_many too much. You
    can check,
  • 15:47 - 15:49
    and I would be very interested in the results,
  • 15:49 - 15:53
    again, so there's another gist. Please, try
    it out
  • 15:53 - 15:56
    if you can.
  • 15:56 - 16:03
    Whoops. And guess which file is on the left?
  • 16:03 - 16:07
    Yeah. He shat on that again. The, it's the
  • 16:07 - 16:11
    user. And it's ot always actually the user.
    I
  • 16:11 - 16:13
    shouldn't be saying that. I should say, it's
    probably
  • 16:13 - 16:16
    always, to some extent, the user. But what's
    your
  • 16:16 - 16:21
    domain? If your domain is, I don't know, money?
  • 16:21 - 16:26
    Houses? Properties? I don't know. It's probably
    that file.
  • 16:26 - 16:28
    Whatever I just said or whatever is in your
  • 16:28 - 16:30
    name. That's that file.
  • 16:30 - 16:32
    And that attracts all the functionality. But
    the user
  • 16:32 - 16:36
    is typically not far behind. And, because
    I want
  • 16:36 - 16:39
    to. Yeah, I just. I think this is very
  • 16:39 - 16:41
    enlightening. So, I just opened to the project
    I
  • 16:41 - 16:43
    just showed you. I opened all the user files,
  • 16:43 - 16:46
    and I'm just gonna scroll through them, K.
  • 16:46 - 16:53
    This is not very intimidating. Eh. This is
    a
  • 16:55 - 17:02
    bit better. Ooh. I'm trying to be non-discriminatory
    here
  • 17:02 - 17:09
    and go the same speed
  • 17:15 - 17:16
    all the time. Ooh.
  • 17:16 - 17:22
    Oh. Oh you wait. Now, I have to speed
  • 17:22 - 17:26
    up.
  • 17:26 - 17:30
    And it's, you, this one file looks particularly
    bad
  • 17:30 - 17:33
    maybe, but it's probably the case that these
    user
  • 17:33 - 17:36
    files are big to the extent that their applications
  • 17:36 - 17:41
    are big. These files just tend to do that.
  • 17:41 - 17:44
    These models just attract that.
  • 17:44 - 17:51
    So, what does that mean?
  • 17:52 - 17:54
    To recap. We have things that grow, and when
  • 17:54 - 17:57
    they grow, they get exponentially more, they
    get more
  • 17:57 - 18:00
    complex. They get exponentially more complex.
    And then in
  • 18:00 - 18:01
    those things, there are certain things that
    are, you
  • 18:01 - 18:06
    know, that are the top of the badness scale.
  • 18:06 - 18:10
    And, and those things that also depend on
    everything
  • 18:10 - 18:16
    else in the system.
  • 18:16 - 18:22
    I don't know. I think we can do better.
  • 18:22 - 18:24
    We can try to reduce the size of the
  • 18:24 - 18:28
    parts. Maybe flatten out that curve and reduce
    the
  • 18:28 - 18:35
    number of dependencies in between those parts.
    Something that
  • 18:35 - 18:38
    has helped me in doing that has been Solid,
  • 18:38 - 18:45
    the five ideas, principles. Signs, truths.
    I don't know.
  • 18:45 - 18:46
    No.
  • 18:46 - 18:49
    And especially for this problem, the Single
    Responsibility Principle.
  • 18:49 - 18:53
    I think if you just apply that as a
  • 18:53 - 18:56
    rule of thumb, as a, as a starter for
  • 18:56 - 19:01
    a conversation, it will, over time, on average,
    improve
  • 19:01 - 19:04
    the quality of your code. But I think there's
  • 19:04 - 19:07
    something funny going on when we discuss single
    responsibility.
  • 19:07 - 19:11
    Oh. Yes. What's single responsibility for?
    To find things
  • 19:11 - 19:18
    that don't belong. Clearly it's the cat with
    the
  • 19:18 - 19:21
    green eyes.
  • 19:21 - 19:28
    Where, where to apply Single Responsibility
    Principle? If you've
  • 19:28 - 19:29
    been to any of the refactoring talks - I
  • 19:29 - 19:31
    didn't have a chance this time - but I'm
  • 19:31 - 19:36
    pretty sure you refactored some methods. We
    look at
  • 19:36 - 19:38
    methods, we want them to be better. We make
  • 19:38 - 19:40
    them smaller. We find what they are about
    and
  • 19:40 - 19:44
    we give them one responsibility. Class. We
    probably did
  • 19:44 - 19:47
    the same, right. We look at a class, we're
  • 19:47 - 19:49
    like, oh, this does a little bit much. But
  • 19:49 - 19:51
    then we're like, OK, ActiveRecord is cool.
    I'm like,
  • 19:51 - 19:54
    allowing it to save itself and soforth. So
    maybe
  • 19:54 - 19:56
    that's OK. But it still kind of should be
  • 19:56 - 19:58
    about this one thing.
  • 19:58 - 20:00
    Except for user.
  • 20:00 - 20:01
    So we're, on these two levels, I think we're
  • 20:01 - 20:07
    really good. Module, and by that I mean a
  • 20:07 - 20:09
    namespace. If you use module as mixin, I get
  • 20:09 - 20:11
    like that I don't want to talk about that,
  • 20:11 - 20:14
    and that's why I continue to say namespace.
    Why
  • 20:14 - 20:16
    do I think this about mixins? I should maybe
  • 20:16 - 20:19
    explain in one sentence. If you mixin stuff
    into
  • 20:19 - 20:21
    your objects, the only thing you're doing
    is hiding
  • 20:21 - 20:23
    away the fact that you have more complexity
    than
  • 20:23 - 20:25
    you can bear to look at on one screen,
  • 20:25 - 20:26
    so you put it on another so you don't
  • 20:26 - 20:29
    have to see it. I would not do that.
  • 20:29 - 20:31
    I mean, I have done it. I have written
  • 20:31 - 20:33
    apps like that, and now I hate myself for
  • 20:33 - 20:35
    it. But, I want to not do it anymore.
  • 20:35 - 20:38
    So I think we shouldn't. So I use modules
  • 20:38 - 20:42
    a lot, but as namespaces, to group things
    together.
  • 20:42 - 20:44
    I think you should do that. You know, look
  • 20:44 - 20:47
    at modules or namespaces and, and analyze
    whether they
  • 20:47 - 20:52
    have one responsibility. But have you done
    that lately?
  • 20:52 - 20:54
    It's harder, right? It doesn't mean a lot.
    You
  • 20:54 - 20:56
    can, it doesn't, you know, no one cares if
  • 20:56 - 20:58
    you go across these things. You just, you
    can
  • 20:58 - 21:02
    load any class anyways.
  • 21:02 - 21:06
    So I think we could get better at that.
  • 21:06 - 21:09
    Let me jump a level. Application. And I think,
  • 21:09 - 21:11
    again, you should. And the fact that we have
  • 21:11 - 21:13
    this Big Rails track, and the fact that I'm
  • 21:13 - 21:15
    talking about components, but pretty much
    everyone else is
  • 21:15 - 21:19
    talking about SOAs, shows that we are talking
    about,
  • 21:19 - 21:22
    what do applications mean? What does it mean
    for
  • 21:22 - 21:25
    an application to do something? Or, yeah.
    To have
  • 21:25 - 21:28
    a function in, in something bigger.
  • 21:28 - 21:31
    So, I encourage you to go to all those
  • 21:31 - 21:34
    tracks and make your applications better on
    that level
  • 21:34 - 21:36
    as well. But I just talked to you about
  • 21:36 - 21:38
    the component, and I think that sits in the
  • 21:38 - 21:41
    middle. And in, in a certain way, the component
  • 21:41 - 21:44
    is, is an improved namespace. Because of that
    thing
  • 21:44 - 21:46
    I said earlier, namely, I can run tests and
  • 21:46 - 21:49
    I can prove that those tests run without ever
  • 21:49 - 21:52
    touching any code that is not in that namespace.
  • 21:52 - 21:57
    So, now you can. And I urge you to
  • 21:57 - 22:02
    do it. Because the cat picture, the discussion
    of
  • 22:02 - 22:05
    what doesn't belong. If you are in your Big
  • 22:05 - 22:08
    Rails app and you're writ- painting all those
    classes
  • 22:08 - 22:11
    as boxes and the dependencies they have as
    arrows,
  • 22:11 - 22:15
    first off, it's really easy to screw that
    up.
  • 22:15 - 22:16
    Because there's no, you can't really prove
    that you're
  • 22:16 - 22:18
    not using another class. At least not in run
  • 22:18 - 22:22
    time with big applications.
  • 22:22 - 22:26
    So components give you an arbitrarily scalable
    and provably
  • 22:26 - 22:30
    independent way to talk about parts of your
    application.
  • 22:30 - 22:33
    So I use it. Now, I said you should
  • 22:33 - 22:36
    look at SOAs, and when, if you're considering
    refactoring
  • 22:36 - 22:38
    your application to improve its quality and
    to make
  • 22:38 - 22:40
    it more maintainable, I think there are a
    couple
  • 22:40 - 22:45
    things you should know about or consider when
    deciding
  • 22:45 - 22:48
    between the two. Right, you're kind of feeling
    pains
  • 22:48 - 22:51
    right now, or you're not even yet feeling
    pains.
  • 22:51 - 22:53
    Great place to be in, too. But there's a
  • 22:53 - 22:56
    couple things that are really cool about just
    splitting
  • 22:56 - 22:57
    up your application into these components.
  • 22:57 - 23:01
    And that is, you stick with one repo. You
  • 23:01 - 23:04
    have one test suite. But you can split it
  • 23:04 - 23:08
    up. You have, still, one deployment. You can,
    however,
  • 23:08 - 23:11
    use, like, a load balancer to push traffic
    to
  • 23:11 - 23:14
    certain parts of the application to make the
    one
  • 23:14 - 23:16
    faster, the other, you know, has less of a
  • 23:16 - 23:20
    demand or, you know, you can go crazy. But
  • 23:20 - 23:22
    you don't get these additional versioning
    constraints of where,
  • 23:22 - 23:24
    like, if you, if you have this app and
  • 23:24 - 23:26
    it needs that app and that app doesn't have
  • 23:26 - 23:28
    the API yet, then I need to add this
  • 23:28 - 23:30
    stuff here at the same time, and I need
  • 23:30 - 23:32
    to deploy them at the same time. And if
  • 23:32 - 23:34
    I didn't do that then everything goes down.
  • 23:34 - 23:35
    You don't have that because you're still talking
    about
  • 23:35 - 23:40
    one application. And also, one other thing
    that's very
  • 23:40 - 23:42
    interesting to me, at least, is that, I never
  • 23:42 - 23:45
    know which parts I need. On this crazy graph
  • 23:45 - 23:47
    project that I just showed you, it went on
  • 23:47 - 23:50
    for about six months. And, and there were
    three
  • 23:50 - 23:54
    pairs on that. And at some point. Four pairs.
  • 23:54 - 23:55
    And at some point, there was always one pair
  • 23:55 - 23:58
    refactoring something. And they created, I
    think there were
  • 23:58 - 24:00
    a couple weeks where they created basically
    a component
  • 24:00 - 24:03
    a day. But they also removed a component.
  • 24:03 - 24:04
    Try to do that with a SOA. Try to
  • 24:04 - 24:06
    move that stuff around quickly. You can do
    a
  • 24:06 - 24:10
    SOA, I think, when you, when you're sure you
  • 24:10 - 24:12
    need pieces. But when you're playing around
    with parts
  • 24:12 - 24:15
    of your application and you, you want to just
  • 24:15 - 24:16
    structure it, and you want to still be able
  • 24:16 - 24:19
    to move a part from one to the other,
  • 24:19 - 24:21
    SOA is a bit heavy.
  • 24:21 - 24:27
    Within a SOA, you can still think about your
  • 24:27 - 24:30
    applications as being built of these components.
    There's, you
  • 24:30 - 24:34
    know, nothing is exclusive there. Just do
    both.
  • 24:34 - 24:41
    So, I've now spent about, most of my time
  • 24:41 - 24:44
    telling you why you should refactor towards
    this. But
  • 24:44 - 24:46
    I haven't done what I said in my title
  • 24:46 - 24:47
    I would do, namely tell you how to refactor
  • 24:47 - 24:51
    towards it. I'm sorry about that. But I gave
  • 24:51 - 24:55
    you this idea, right. And you all believed
    me.
  • 24:55 - 24:59
    This is easy.
  • 24:59 - 25:02
    Today's day of the, International Day of the
    Book.
  • 25:02 - 25:07
    I looked in these books. Refactoring to Patterns.
    Refactoring.
  • 25:07 - 25:11
    Awesome books. But they don't talk about this
    either.
  • 25:11 - 25:12
    And I think the reason is that this stuff
  • 25:12 - 25:15
    is not very important in other languages.
    In Java,
  • 25:15 - 25:18
    you do packages every day and you have implicit
  • 25:18 - 25:20
    imports. In Go, you do that. Other languages
    do
  • 25:20 - 25:23
    not have this problem, because other languages
    do not
  • 25:23 - 25:26
    allow for this kind of freedom and openness
    that
  • 25:26 - 25:31
    we've gotten because we do Ruby.
  • 25:31 - 25:35
    So, I call these two refactorings, teasing
    out an
  • 25:35 - 25:39
    app component and extracting a functional
    component. And the
  • 25:39 - 25:40
    reason I don't want to spend much time on
  • 25:40 - 25:42
    it is because it's actually very simple to
    do
  • 25:42 - 25:46
    it. The devil's just in the details.
  • 25:46 - 25:49
    And there is no book about this. But I'm
  • 25:49 - 25:52
    trying to write one. And if you, I don't
  • 25:52 - 25:54
    know, show, if you're interested in this,
    send a
  • 25:54 - 25:56
    message there and I might be more inclined
    to
  • 25:56 - 25:58
    actually sit down.
  • 25:58 - 26:02
    All right. But to the first one - teasing
  • 26:02 - 26:09
    out an app component. So, step zero. Got tests?
  • 26:09 - 26:11
    If, if you don't have tests, I wouldn't move
  • 26:11 - 26:14
    as much code as we're about to move. I
  • 26:14 - 26:17
    mean, virtually. But, you should add some
    tests around
  • 26:17 - 26:19
    the stuff that you want to extract.
  • 26:19 - 26:21
    And then you, for the app component. So that's
  • 26:21 - 26:25
    this teaser thing we looked at. So we're,
    a
  • 26:25 - 26:27
    component of your application, where you almost
    thing, this
  • 26:27 - 26:30
    could be its own application, maybe. So you
    look
  • 26:30 - 26:35
    for this vertical. Views, controllers, models.
    You find that
  • 26:35 - 26:38
    vertical that makes sense on its own and you
  • 26:38 - 26:39
    namespace it.
  • 26:39 - 26:42
    A funny thing happens when you just namespace
    it.
  • 26:42 - 26:45
    Suddenly, the things in there. Well, first
    off, what's
  • 26:45 - 26:46
    awful about it is you have to rename all
  • 26:46 - 26:49
    your tables. OK. But that aside, you suddenly
    start
  • 26:49 - 26:53
    seeing what's actually in your vertical and
    what's not.
  • 26:53 - 26:55
    You could actually put colon colon in front
    of
  • 26:55 - 26:57
    everything else that's not, and you would
    get a
  • 26:57 - 27:00
    really easy view parsing or, or way of seeing
  • 27:00 - 27:02
    in your files what's not in your vertical.
  • 27:02 - 27:06
    Those are your external dependencies to, an
    external to
  • 27:06 - 27:08
    the app. So when you do this at first,
  • 27:08 - 27:10
    you're apps gonna be unhappy. So please make
    your
  • 27:10 - 27:13
    tests green. And to do that, you will need
  • 27:13 - 27:15
    to find other parts that you didn't know you
  • 27:15 - 27:20
    depended upon, and you move them into what's
    gonna
  • 27:20 - 27:25
    be the component. Into this vertical.
  • 27:25 - 27:29
    And when you got this vertical green, you
    extract
  • 27:29 - 27:34
    it into an engine. Extracting into an engine
    is
  • 27:34 - 27:38
    rails plugin new component dash dash full,
    dash dash
  • 27:38 - 27:40
    mountable. In most cases.
  • 27:40 - 27:41
    It doesn't matter.
  • 27:41 - 27:48
    And step three, profit. Now, most of the time,
  • 27:49 - 27:52
    this vertical will not be as easy to find
  • 27:52 - 27:55
    as I just pretended it would be. And that's
  • 27:55 - 28:02
    because of, you guessed it, user. Right? The
    user
  • 28:02 - 28:05
    is probably somewhere, and other things as
    well, are
  • 28:05 - 28:09
    used somewhere, are needed somewhere, but
    don't really belong
  • 28:09 - 28:10
    to this verticle.
  • 28:10 - 28:13
    And what I've found is when you refactor towards
  • 28:13 - 28:15
    this, if you abstract. If you, if you're coming
  • 28:15 - 28:18
    from one big piece, if you want to abstract
  • 28:18 - 28:21
    one thing, you're gonna abstract two. The
    one thing
  • 28:21 - 28:24
    you wanted and the common stuff. But please
    do
  • 28:24 - 28:26
    not call that stuff common, because that's
    just gonna
  • 28:26 - 28:28
    be another pile of shit that you can attach
  • 28:28 - 28:30
    stuff to. Call it something else. Call it
    user
  • 28:30 - 28:34
    if you have to.
  • 28:34 - 28:36
    So this special case is not a special case.
  • 28:36 - 28:38
    I think this is, of course there is lots
  • 28:38 - 28:41
    of meat in how to do this and where
  • 28:41 - 28:43
    you get hung up on certain gem dependencies
    and
  • 28:43 - 28:45
    engines not doing it exactly the way that
    Rails
  • 28:45 - 28:48
    does it and blah, blah, blah. But essentially
    this
  • 28:48 - 28:52
    is it.
  • 28:52 - 28:55
    The other side to this is, is, something even
  • 28:55 - 29:02
    more interesting. It's abstracting functional
    components. Now your app
  • 29:02 - 29:05
    is round, suddenly. I don't know why. Again,
    got
  • 29:05 - 29:09
    tests? Let's start there.
  • 29:09 - 29:11
    So you find a functional component, and yes,
    I
  • 29:11 - 29:14
    made that much smaller than that verticle.
    Because typically
  • 29:14 - 29:16
    you find a piece that is really, really separate.
  • 29:16 - 29:20
    A very special functionality. Maybe even something
    mathematically a
  • 29:20 - 29:24
    function. In and out. Some processing. You
    find that
  • 29:24 - 29:28
    and you create a gem.
  • 29:28 - 29:30
    And you move the tests in there as well,
  • 29:30 - 29:32
    and your gem is, when you run those tests,
  • 29:32 - 29:34
    the gem's gonna be unhappy, because of all
    those
  • 29:34 - 29:38
    dependencies that you didn't see coming. So,
    you take
  • 29:38 - 29:42
    all those and you move them in. And you
  • 29:42 - 29:45
    make your tests happy.
  • 29:45 - 29:47
    Well, and now you require that gem in the
  • 29:47 - 29:50
    main app, and your main app is totally unhappy.
  • 29:50 - 29:52
    Because it doesn't know how to talk to that
  • 29:52 - 29:58
    gem anymore. And if there were any ActiveRecord
    dependencies,
  • 29:58 - 30:01
    or other dependencies on, on stuff that came
    from
  • 30:01 - 30:04
    Rails, I would urge you to try and keep
  • 30:04 - 30:06
    that out of, of these kinds of gems, because
  • 30:06 - 30:08
    it just adds such a huge surface area and
  • 30:08 - 30:11
    stuff that could happen, could be done and
    could
  • 30:11 - 30:12
    go wrong.
  • 30:12 - 30:15
    I, I would urge you to find these connections,
  • 30:15 - 30:21
    these, the shims, maybe. Call them ports and
    adapters.
  • 30:21 - 30:23
    And move them in the app closer to the
  • 30:23 - 30:26
    surface area of this gem, so that you can
  • 30:26 - 30:28
    do the processing of whatever that is there,
    and
  • 30:28 - 30:31
    that talks to the gem and makes it work
  • 30:31 - 30:34
    again. So now the app is happy. And you
  • 30:34 - 30:37
    got this weird kind of lump on the side.
  • 30:37 - 30:38
    But that's a good thing.
  • 30:38 - 30:41
    In, in one of the books, actually I think
  • 30:41 - 30:43
    it's Eric Evans, it's called Bound to Context.
    Now
  • 30:43 - 30:45
    you have a thing that is only relevant for
  • 30:45 - 30:50
    a context. But that's how you take from that,
  • 30:50 - 30:52
    from that curve that has the huge left side.
  • 30:52 - 30:54
    That's how you chip away at the top and
  • 30:54 - 30:57
    put it somewhere at the end. Because this
    thing,
  • 30:57 - 30:59
    in a bound context, it only has one meaning.
  • 30:59 - 31:01
    And that's why it's gonna be smaller.
  • 31:01 - 31:08
    So, step three. Profit.
  • 31:08 - 31:14
    I hope that made sense. And I know. It
  • 31:14 - 31:17
    doesn't work that easily. It's not five steps.
    It
  • 31:17 - 31:20
    can take weeks. The first time we tried this,
  • 31:20 - 31:22
    it took three attempts and four weeks in one
  • 31:22 - 31:25
    app that we wanted to split into two. And
  • 31:25 - 31:27
    we ended up with three, and now I think
  • 31:27 - 31:30
    it's about ten. But, trust me, you can get
  • 31:30 - 31:31
    there.
  • 31:31 - 31:36
    And I kind of felt challenged by Far- by
  • 31:36 - 31:40
    Farrah's keynote yesterday. So, I will help.
    If you
  • 31:40 - 31:42
    want to attempt this, and you don't find the
  • 31:42 - 31:44
    resources and any of those links that I gave
  • 31:44 - 31:47
    you, Tweet at me, talk to me, send me
  • 31:47 - 31:50
    an email. I'll respond to all of them. Maybe
  • 31:50 - 31:53
    publicly so it helps others, too. I just think
  • 31:53 - 31:56
    this is a great way to structure applications
    and
  • 31:56 - 31:58
    to make them better, and that's why I just
  • 31:58 - 32:01
    will help.
  • 32:01 - 32:04
    So don't let these guys ruin your day. Make
  • 32:04 - 32:07
    friends with the #cbra, and thanks for your
    attention.
Title:
RailsConf 2014 - Refactoring Towards Component-based Rails Architectures
Description:

more » « less
Duration:
32:35

English subtitles

Revisions