< Return to Video

Ruby Conf 2013 - Promiscuous: A robust service-oriented architecture framework

  • 0:16 - 0:20
    KAREEN KOUDDOUS: All right. Let's get started.
  • 0:20 - 0:24
    Hi, I'm Kareem Kouddous. I'm currently CTO
  • 0:24 - 0:28
    and founder at Crowdtap. I'm also a side project
    addict.
  • 0:28 - 0:32
    You can find me on GitHub and Twitter at kareemk.
  • 0:32 - 0:35
    So Ruby is cute. And what I mean by
  • 0:35 - 0:39
    that is, you know, it's optimized for developer
    joy.
  • 0:39 - 0:43
    I mean, anyone who attended Matz's keynote,
    you know,
  • 0:43 - 0:46
    can, can feel that. I personally wanted to
    go
  • 0:46 - 0:49
    up and hug him after the keynote. It's so
  • 0:49 - 0:51
    clear that, you know, the genesis of Ruby
    came
  • 0:51 - 0:56
    from a place of wanting to create joy in
  • 0:56 - 1:00
    what you do every day. Happiness in web development.
  • 1:00 - 1:03
    You know, and Rails, arguably could be cuter.
    You
  • 1:03 - 1:07
    know, Rails took those same principles of
    really loving
  • 1:07 - 1:10
    what you do every day as a web developer
  • 1:10 - 1:14
    or software engineer and taking that to the
    web
  • 1:14 - 1:17
    stack. And, I'm sure all of you remember the,
  • 1:17 - 1:19
    you know, blog in fifteen minutes. And that
    was
  • 1:19 - 1:22
    magical, because it was so painful before
    to get
  • 1:22 - 1:24
    a web application up and running.
  • 1:24 - 1:27
    And Rails changed everything.
  • 1:27 - 1:29
    But, I'm sure, as a lot of you also
  • 1:29 - 1:35
    know, over time as your team grows and you
  • 1:35 - 1:42
    start to actually build very interesting features,
    you, you
  • 1:42 - 1:46
    tend to, things start to get difficult. You
    know,
  • 1:46 - 1:49
    tests start to take a long time. You know,
  • 1:49 - 1:53
    there's great testing ethos in the Ruby community,
    but,
  • 1:53 - 1:54
    you know, you have a lot of tests, you
  • 1:54 - 1:55
    build a lot of features and things start to
  • 1:55 - 1:56
    get slow.
  • 1:56 - 1:58
    And what does that do, you know, instead of
  • 1:58 - 2:00
    being able to push out code into your staging
  • 2:00 - 2:03
    or production environment immediately, you
    have to wait, you
  • 2:03 - 2:06
    know, minutes, maybe even hours, before that
    gets in
  • 2:06 - 2:09
    there and you lose flow. You have to context
  • 2:09 - 2:13
    switch. That's horrible. You know. Your fat
    models become
  • 2:13 - 2:14
    obese.
  • 2:14 - 2:17
    You know, suddenly, you know, you have six
    engineers
  • 2:17 - 2:21
    touching your user model and people are repeating
    the
  • 2:21 - 2:22
    code all over the place, because they're trying
    to
  • 2:22 - 2:25
    do, you know, something that's the same but
    slightly
  • 2:25 - 2:29
    different. And, you know, instead of trying
    to refactor
  • 2:29 - 2:30
    the app, you know, you want to push features
  • 2:30 - 2:35
    out. They're duplicating code. And then these
    things become
  • 2:35 - 2:40
    really hard to work with and less joyful.
  • 2:40 - 2:42
    You know, you start to use a lot of
  • 2:42 - 2:44
    gems, and that's great. You know, that's one
    of
  • 2:44 - 2:47
    the wonderful things about the Ruby community
    is there's
  • 2:47 - 2:49
    a lot of us and we've contributed so much
  • 2:49 - 2:51
    to it. But then you, your app starts to
  • 2:51 - 2:53
    take a long time and, you know, you're building
  • 2:53 - 2:55
    an interesting application so it has a lot
    of
  • 2:55 - 2:57
    features and you have a lot of gems and
  • 2:57 - 3:00
    that takes a long time. And you stop experimenting.
  • 3:00 - 3:03
    You stop just putting up console and trying
    stuff.
  • 3:03 - 3:06
    That joy of, that first experience with Rails
    or
  • 3:06 - 3:10
    Ruby, you know, starts to erode. And then
    hugs
  • 3:10 - 3:15
    turn into yelling, right. You, you're in the,
    you
  • 3:15 - 3:17
    know, you're in your chat room, just trying
    to
  • 3:17 - 3:20
    figure out what's going on, and yelling at
    each
  • 3:20 - 3:23
    other. It's, it's, it's no longer joyful.
  • 3:23 - 3:25
    And fundamentally what that means is you've
    lost your
  • 3:25 - 3:27
    agility. And I think that's what Matz was
    really
  • 3:27 - 3:31
    trying to say is, agility is about happiness,
    right.
  • 3:31 - 3:33
    If you're happy and free to do what you
  • 3:33 - 3:36
    want with your code, you're gonna take, you're
    gonna
  • 3:36 - 3:39
    innovate. You're gonna do interesting things.
    You're gonna be
  • 3:39 - 3:40
    creative.
  • 3:40 - 3:43
    And, as your app, though, this, this starts
    to
  • 3:43 - 3:45
    change, and you lose your agility, and we're
    back
  • 3:45 - 3:49
    to, you know, waterfall, but, you know, same
    pain
  • 3:49 - 3:52
    points, but just manifested in a different
    way. So.
  • 3:52 - 3:57
    So, you know, what was really cute, you know,
  • 3:57 - 4:04
    suddenly is this really scary, ugly thing
    that has
  • 4:04 - 4:06
    appeared in your life, and you don't know
    what
  • 4:06 - 4:10
    to do with it. You know, you, you want
  • 4:10 - 4:12
    to figure out a way to solve this, and
  • 4:12 - 4:14
    so you need to figure out what the root
  • 4:14 - 4:16
    cause is, right. That's how you solve problems.
  • 4:16 - 4:18
    So you need to figure out the root cause
  • 4:18 - 4:20
    and solve this problem. You want this guy
    out
  • 4:20 - 4:22
    of your life.
  • 4:22 - 4:25
    So to illustrate that, I'm gonna go through
    how
  • 4:25 - 4:29
    this manifested itself, this problem, this
    beast in, at
  • 4:29 - 4:33
    Crowdtap, and, and walk through that to show
    how
  • 4:33 - 4:36
    we got to where we are now. And, I'm
  • 4:36 - 4:39
    gonna start by just giving you a quick overview
  • 4:39 - 4:42
    of what Crowdtap is. You know, it's, we're
    the
  • 4:42 - 4:45
    leading social influence marketing platform.
    You know we, we
  • 4:45 - 4:48
    ally with big brands, collaborate with their
    customers which
  • 4:48 - 4:52
    inspires advocacy and drives unmatched social
    activity.
  • 4:52 - 4:54
    And what all this marketing speak boils down
    to
  • 4:54 - 5:00
    is we create awesome tasks, engaging fun tasks,
    for
  • 5:00 - 5:03
    the brand's launch that users complete to
    help brands
  • 5:03 - 5:06
    market. And those tasks span the full marketing
    life
  • 5:06 - 5:10
    cycle. Everything from completing a poll to
    taking a
  • 5:10 - 5:12
    photo of doing something fun and sharing that
    on
  • 5:12 - 5:15
    Facebook, to getting free product from the
    brand, sharing
  • 5:15 - 5:17
    that with friends, throwing a party around
    it. And
  • 5:17 - 5:20
    we're constantly adding different tasks, engaging,
    fun, engaging tasks,
  • 5:20 - 5:24
    so that the brands can collaborate with their
    consumers
  • 5:24 - 5:27
    to market, instead of just shouting at them.
  • 5:27 - 5:29
    And that's what our vision is for, for Crowdtap.
  • 5:29 - 5:31
    So let's, let's take a look at this and
  • 5:31 - 5:33
    you know, a screenshot. And this is one of
  • 5:33 - 5:36
    our more popular actions, which is a poll.
    Brands
  • 5:36 - 5:40
    can get real time feedback on whatever they
    want.
  • 5:40 - 5:43
    And here they're asking, specifically, you
    know, what Cable
  • 5:43 - 5:47
    networks do, does, do the users currently
    watch, or
  • 5:47 - 5:48
    receive.
  • 5:48 - 5:52
    And the really powerful thing with Crowdtap
    is we
  • 5:52 - 5:56
    take all this data that a user, that, that
  • 5:56 - 6:00
    users generate from answering all these questions
    and participating
  • 6:00 - 6:03
    with the brand, and we give the brands very
  • 6:03 - 6:07
    rich and deep targeting ability, so that not
    only
  • 6:07 - 6:09
    can they target based on all the demographic
    data
  • 6:09 - 6:12
    on the user: their age, income, et cetera,
    which
  • 6:12 - 6:15
    we collect. We, they can also target based
    on
  • 6:15 - 6:18
    everything that user has done. The entire
    history of
  • 6:18 - 6:22
    what that user has done with, with that brand.
  • 6:22 - 6:23
    And they can also target based on what they
  • 6:23 - 6:27
    haven't done. So, it's a very, very rich targeting
  • 6:27 - 6:30
    engine. But as you can imagine, this becomes
    a
  • 6:30 - 6:35
    performance bottleneck very quickly, because
    on every page load,
  • 6:35 - 6:39
    we need to know which tasks are available
    for
  • 6:39 - 6:41
    a user, and, if targeting, we need to -
  • 6:41 - 6:42
    you can target based on anything that user
    has
  • 6:42 - 6:44
    done. You have to load up the entire history
  • 6:44 - 6:46
    of that user.
  • 6:46 - 6:48
    And so, to be clear, this is a really
  • 6:48 - 6:52
    big performance bottleneck. And this was the
    first painpoint
  • 6:52 - 6:56
    that we encountered. Or, or, a major painpoint
    that
  • 6:56 - 7:00
    we encountered, along with everything I was
    discussing. So
  • 7:00 - 7:03
    we need, you know, we needed to solve this.
  • 7:03 - 7:06
    And the way to solve this is, you know,
  • 7:06 - 7:09
    we need to tailor our data structure for the
  • 7:09 - 7:11
    problem at hand. So, what I mean by that
  • 7:11 - 7:14
    is, we're generating data, everything that
    that user is
  • 7:14 - 7:16
    doing, and we're collecting it in a way from
  • 7:16 - 7:20
    our main application that makes sense, you
    know, when
  • 7:20 - 7:22
    you're doing just basic CRUD. But then we
    want
  • 7:22 - 7:24
    to take that data and we want to have
  • 7:24 - 7:27
    the freedom to denormalize the data. Maybe
    put in
  • 7:27 - 7:30
    caching. Maybe use a different database technology.
  • 7:30 - 7:34
    We want the freedom to experiment and explore
    with
  • 7:34 - 7:37
    this data to be able to solve the problem.
  • 7:37 - 7:39
    And at the same time, we want to do
  • 7:39 - 7:42
    it in a way that takes us back to
  • 7:42 - 7:45
    the joy. Back to the little cute, fuzzy animals
  • 7:45 - 7:48
    we had in our lives and not these beasts,
  • 7:48 - 7:49
    right.
  • 7:49 - 7:51
    So how do you do this? So, you know,
  • 7:51 - 7:53
    the first thing we thought was, OK, we've
    been
  • 7:53 - 7:56
    reading, people have blogged about the services.
    What about
  • 7:56 - 7:59
    just extracting and, you know, this functionality
    in services?
  • 7:59 - 8:01
    But that doesn't work, right. Because even
    if you
  • 8:01 - 8:04
    extract your functionality into services,
    what you really care
  • 8:04 - 8:06
    about is your models. Right, that's your data.
  • 8:06 - 8:09
    So if you, there, we're not talking about
    extracting
  • 8:09 - 8:13
    business logic, you know, into, you know,
    single purpose
  • 8:13 - 8:17
    files. We're, we're talking about being able
    to work
  • 8:17 - 8:18
    with our data in a flexible way. And so
  • 8:18 - 8:22
    extracting it to services doesn't really help.
  • 8:22 - 8:25
    And, you know, Rails, what about a Rails engine
  • 8:25 - 8:28
    or gem extraction. Essentially this is all
    the same
  • 8:28 - 8:30
    thing. It's just moving furniture around.
    What you really
  • 8:30 - 8:33
    want to do is be able to mutate your
  • 8:33 - 8:34
    data. You want to be able to play with
  • 8:34 - 8:40
    your, your data structure, and have freedom
    there.
  • 8:40 - 8:43
    And this brought us to, you know, what about
  • 8:43 - 8:45
    app extraction? Why don't we extract this
    into a
  • 8:45 - 8:48
    separate app? You know, we can go back to
  • 8:48 - 8:51
    the, the little cute animal because it's a
    smaller
  • 8:51 - 8:54
    app and solve all of those other painpoints.
    But
  • 8:54 - 8:56
    at the same time, have, you know, some freedom
  • 8:56 - 8:58
    to solve the performance problem which was
    a very
  • 8:58 - 9:00
    big business problem for us.
  • 9:00 - 9:03
    And so the first thing we considered is, how
  • 9:03 - 9:05
    about extracting the app and sharing the database?
    Well,
  • 9:05 - 9:08
    this def, this doesn't work, right. Because
    all, everything
  • 9:08 - 9:10
    you need to do with your data is in
  • 9:10 - 9:12
    your main app. Your main app holds that model.
  • 9:12 - 9:14
    And so if you're gonna do anything interesting
    with
  • 9:14 - 9:15
    your data, you're gonna have to do it in
  • 9:15 - 9:16
    your main app, so what have you done?
  • 9:16 - 9:19
    Your targeting app isn't, the splitting up
    of the
  • 9:19 - 9:24
    app is not solving anything, right? OK. So
    let's
  • 9:24 - 9:26
    do this. Let's to synchronous API. And this
    is,
  • 9:26 - 9:28
    this is probably what most people think of
    as
  • 9:28 - 9:32
    SOA, right. SOA is some RPC mechanism between
    apps.
  • 9:32 - 9:36
    But, again, this does not solve this problem,
    because,
  • 9:36 - 9:37
    if you're gonna do anything interesting with
    your data
  • 9:37 - 9:39
    and you want to mutate your data, you're gonna
  • 9:39 - 9:41
    have to do that in your main app.
  • 9:41 - 9:43
    And so you're, you're adding complexity to
    your main
  • 9:43 - 9:45
    app. We want to remove complexity from the
    main
  • 9:45 - 9:48
    app and put it somewhere else, right, and,
    and
  • 9:48 - 9:50
    deal with it somewhere else. So this doesn't,
    this
  • 9:50 - 9:54
    doesn't solve the problem. This just adds
    more layers.
  • 9:54 - 9:59
    So I hope, by now, it's clear what the
  • 9:59 - 10:01
    right way to do this is. And for us,
  • 10:01 - 10:02
    it was.
  • 10:02 - 10:06
    You, we need to have a separate database for
  • 10:06 - 10:08
    this, for our targeting application, and we
    need to
  • 10:08 - 10:13
    replicate data from our main application into
    this separate
  • 10:13 - 10:15
    app, and have the freedom in our main application
  • 10:15 - 10:18
    to mutate the data as we wish, experiment
    with
  • 10:18 - 10:23
    different databases, really go back to being
    agile in
  • 10:23 - 10:26
    solving, in solving the problem.
  • 10:26 - 10:27
    And that's what we did. And it's at that
  • 10:27 - 10:29
    point that the heavens parted and Nico fell
    into
  • 10:29 - 10:33
    our laps. And, and helped us take this architecture
  • 10:33 - 10:34
    to the next level. So I'll just, just pass
  • 10:34 - 10:36
    this onto Nico.
  • 10:36 - 10:41
    NICOLAS VIENNOT: Hello. How are you? My name
    is
  • 10:41 - 10:44
    Nico. I'm a PhD student at Columbia University
    in
  • 10:44 - 10:46
    the system department. I love, I love opensource,
    and
  • 10:46 - 10:49
    you can find me on Twitter and GitHub at
  • 10:49 - 10:50
    nviennot.
  • 10:50 - 10:52
    So last year, I came at Crowdtap, and they
  • 10:52 - 10:56
    just extracted that targeting logic to its
    own separate
  • 10:56 - 10:58
    app that we call Sniper. So that was a
  • 10:58 - 11:02
    great win, because we were able to finally
    see
  • 11:02 - 11:04
    the big picture of this application, of that
    logic,
  • 11:04 - 11:07
    and that, and so when we extracted that it
  • 11:07 - 11:09
    was like ten, I mean, five thousand, five
    thousand
  • 11:09 - 11:13
    lines of code. And since we, we were on
  • 11:13 - 11:15
    that app, we could really refactor it quickly
    because
  • 11:15 - 11:18
    the tests were running in, like, you know,
    thirty
  • 11:18 - 11:19
    seconds.
  • 11:19 - 11:21
    And, and we, we got to a point where
  • 11:21 - 11:23
    the app was just less than a thousand lines
  • 11:23 - 11:25
    of code, because now, because it, it, it got
  • 11:25 - 11:28
    really intuitive - oh, look, we should put
    our
  • 11:28 - 11:31
    data structure like this. What if, what if
    we
  • 11:31 - 11:33
    generalize this way around and all? Which
    we couldn't
  • 11:33 - 11:35
    do in the main application because everything
    was kind
  • 11:35 - 11:37
    of coupled together and it was really hard
    to
  • 11:37 - 11:39
    see, you know, the big picture of things.
  • 11:39 - 11:43
    So, performance went really well after that.
    We went
  • 11:43 - 11:45
    from, you know, a second or two to fifty
  • 11:45 - 11:48
    milliseconds. That was like, yay! Big win!
  • 11:48 - 11:50
    But, we came to another problem, which was
    data
  • 11:50 - 11:54
    replication. And it's actually hard. So, so
    what we
  • 11:54 - 11:58
    did first was something pretty naive. So,
    on the
  • 11:58 - 12:01
    main application, the publisher's side, we're
    like, well, let's
  • 12:01 - 12:05
    just add some callbacks and post the, the
    data
  • 12:05 - 12:08
    to Sniper. And then Sniper, the subscribers
    can be
  • 12:08 - 12:11
    like, oh, I can take that data and save
  • 12:11 - 12:13
    it to its database.
  • 12:13 - 12:15
    But things started to break down in production.
    We're
  • 12:15 - 12:17
    like, it's funny, these two databases don't
    have the
  • 12:17 - 12:21
    same user count. It's weird. Because, so,
    we realized,
  • 12:21 - 12:23
    wait, it's in a different system. Things fail
    all
  • 12:23 - 12:24
    the time.
  • 12:24 - 12:27
    So, for example, if your web server, right
    after
  • 12:27 - 12:31
    writing its data to the database, dies, and
    is
  • 12:31 - 12:33
    not able to the callback, then, oops, Sniper
    doesn't
  • 12:33 - 12:36
    know about it. What if Sniper is down? Well,
  • 12:36 - 12:39
    it won't receive some updates for five minutes.
  • 12:39 - 12:41
    So that's a problem.
  • 12:41 - 12:43
    So we're like, OK, so this is, this is
  • 12:43 - 12:46
    a problem. And, and at the same time, we're
  • 12:46 - 12:48
    looking at this. We're like, oh, that's funny.
    That
  • 12:48 - 12:50
    looks really like an observer, like in the
    Rails
  • 12:50 - 12:54
    sense, right, like, the Sni- the subscriber
    is really
  • 12:54 - 12:56
    like observing the data that's changing on
    the other
  • 12:56 - 12:59
    app. And we're like, well, that's, that's
    a cool
  • 12:59 - 13:01
    concept. What can it do, then? And what we
  • 13:01 - 13:04
    really want to do with that is to have,
  • 13:04 - 13:06
    to split our app in a lot of different
  • 13:06 - 13:07
    services, right.
  • 13:07 - 13:09
    Like, if we could have this remote observer
    and,
  • 13:09 - 13:12
    and rip the data around, we're like, well,
    why
  • 13:12 - 13:15
    don't we apply the same thoughts to the email
  • 13:15 - 13:18
    service. But we couldn't just add callbacks
    and see
  • 13:18 - 13:21
    the production system kind of like blowing
    away like
  • 13:21 - 13:22
    this.
  • 13:22 - 13:25
    Which is why we introduced Promiscuous. Promiscuous
    is a
  • 13:25 - 13:29
    transparent application level causally consistent
    data replication framework for
  • 13:29 - 13:32
    service-oriented architecture. And, I'm gonna
    explain to you what
  • 13:32 - 13:34
    it all means.
  • 13:34 - 13:38
    So Promiscuous is essentially the glue between
    all of
  • 13:38 - 13:40
    your services. So you can think of it as
  • 13:40 - 13:43
    a message bus, where you're gonna have services
    publishing
  • 13:43 - 13:46
    their data, and then you're gonna have subscriber
    apps
  • 13:46 - 13:48
    that are like, oh, I'm intruding that model
    and
  • 13:48 - 13:50
    this one and that, and it's gonna do something
  • 13:50 - 13:51
    interesting.
  • 13:51 - 13:55
    And Promiscuous sits at, on your models, between
    the
  • 13:55 - 13:58
    models and the database layer. So everything
    that the
  • 13:58 - 14:01
    publisher would do, it's gonna propagate those
    changes down
  • 14:01 - 14:04
    to the subscriber models that have a view
    to
  • 14:04 - 14:06
    anything.
  • 14:06 - 14:08
    So that's Promiscuous in a nutshell.
  • 14:08 - 14:11
    And, and because we are really trying to get
  • 14:11 - 14:14
    back that joy and the simplicity of Rails
    and
  • 14:14 - 14:18
    Ruby, Promiscuous had to, like, to, to provide
    those
  • 14:18 - 14:19
    three key features.
  • 14:19 - 14:23
    So first, it tackles data replication in a
    novel
  • 14:23 - 14:28
    way, which scales and is actually consistent.
    It provides
  • 14:28 - 14:30
    a very simple API, because as a developer,
    like,
  • 14:30 - 14:31
    we just want to write one line of code
  • 14:31 - 14:33
    and be done with it. And, of course, since
  • 14:33 - 14:36
    we're Rubyists, we want a good testing framework.
  • 14:36 - 14:39
    So I'm gonna go through all these three points.
  • 14:39 - 14:43
    So data replication. It's pretty hard to,
    to get
  • 14:43 - 14:45
    your head around this. But let's go through
    an
  • 14:45 - 14:48
    example. So say you have some sort of Facebook
  • 14:48 - 14:50
    app where you have users and they can send
  • 14:50 - 14:52
    messages to each other.
  • 14:52 - 14:54
    And, and so here, like, say I want to
  • 14:54 - 14:57
    implement an email service that sends an email
    to
  • 14:57 - 15:02
    whoever receive a message, right. Simple.
    So here, if,
  • 15:02 - 15:04
    if you would to subscribe to the data that
  • 15:04 - 15:06
    is interesting, you would see, oh, our user
    just
  • 15:06 - 15:08
    signed up. So create user.
  • 15:08 - 15:10
    And then, that guy just sent a message to
  • 15:10 - 15:12
    another guy. OK. Create message, great. So
    when you
  • 15:12 - 15:15
    create message, you're gonna be like, oh,
    fetch from
  • 15:15 - 15:17
    my database. Oh, OK, I have that user, I
  • 15:17 - 15:21
    can send random a email. OK, hi, whoever,
    oh
  • 15:21 - 15:23
    hi and all that.
  • 15:23 - 15:25
    But since we need to scale, because, you know,
  • 15:25 - 15:27
    we have a lot of users, we're gonna add
  • 15:27 - 15:29
    some more curves. So that's what's gonna happen.
    On
  • 15:29 - 15:34
    your email service, we can have, say, two
    workers,
  • 15:34 - 15:36
    and now, since we need to process this message
  • 15:36 - 15:39
    in parallel, what's gonna happen? Well, if
    worker one
  • 15:39 - 15:43
    is a bit slow sometimes, maybe it's not gonna
  • 15:43 - 15:46
    process that create user quick enough to put
    in
  • 15:46 - 15:48
    database, and so the worker two is gonna be
  • 15:48 - 15:50
    like, oh, who is, who is that user? Oh,
  • 15:50 - 15:51
    well I don't find it in my database. Boom
  • 15:51 - 15:53
    exception. So that's a problem.
  • 15:53 - 15:56
    And that's, that's a consistency problem.
  • 15:56 - 15:59
    But promiscuous, it is going to solve this
    problem
  • 15:59 - 16:03
    for you, under, transparently, without you
    having to do
  • 16:03 - 16:06
    anything. And so it's going to try to paralyze
  • 16:06 - 16:10
    as much as, messages that it can, but still
  • 16:10 - 16:12
    serialize the messages that are important.
  • 16:12 - 16:16
    For example, the create user happens before
    the create
  • 16:16 - 16:20
    message. And that's what we mean by causal
    consistency.
  • 16:20 - 16:23
    So as in cause and effect.
  • 16:23 - 16:25
    So let's see how that kind of works. So
  • 16:25 - 16:30
    why, how is the, is doing this transparently?
  • 16:30 - 16:31
    So when you send, so when you have a
  • 16:31 - 16:33
    user that wants to send a message to another
  • 16:33 - 16:35
    user, it's gonna hit your controller in some
    ways.
  • 16:35 - 16:37
    In your controller, what you're gonna do,
    you're gonna
  • 16:37 - 16:39
    interact with your models. So what you gonna
    do?
  • 16:39 - 16:42
    You're gonna fetch, first of all the current
    user,
  • 16:42 - 16:44
    from his cookie, and then you're gonna do
    user
  • 16:44 - 16:47
    find on his friend, and then you're gonna
    finally
  • 16:47 - 16:50
    create the message with the frame keys that
    go
  • 16:50 - 16:51
    by.
  • 16:51 - 16:54
    And, since Promiscuous sits at your model,
    on your
  • 16:54 - 16:56
    models, it can be like, oh, that's what you
  • 16:56 - 16:59
    did. So he going to infer that the message
  • 16:59 - 17:02
    create depends on those two piece of data.
    And
  • 17:02 - 17:05
    that's how it's able to serialize the messages
    that
  • 17:05 - 17:09
    are important and paralyze the ones that are
    not.
  • 17:09 - 17:11
    So you could say, well, that's a bit overkill.
  • 17:11 - 17:14
    Because why don't I just retry until, you
    know,
  • 17:14 - 17:17
    the user is in my database because it would
  • 17:17 - 17:20
    have an exception, right? But it's, it's actually
    moreso
  • 17:20 - 17:23
    than that. SO let's take another example to
    illustrate
  • 17:23 - 17:23
    this.
  • 17:23 - 17:26
    SO say you're on Facebook and you have people
  • 17:26 - 17:29
    posting pictures and you want to provide an
    email
  • 17:29 - 17:31
    service that send an email of the picture
    to
  • 17:31 - 17:34
    your, all of your friends. So say you have
  • 17:34 - 17:36
    a user, consider that scenario where you have
    a
  • 17:36 - 17:38
    user coming back from spring break, and he
    deletes
  • 17:38 - 17:41
    his parents from his friends list and then
    he
  • 17:41 - 17:43
    posts a compromising picture, K.
  • 17:43 - 17:47
    So what happens if you reverse the processing
    of
  • 17:47 - 17:50
    the two messages? Well you're gonna send the
    picture
  • 17:50 - 17:52
    before having to remove the parents. And you're
    not
  • 17:52 - 17:54
    gonna have an exception, you're gonna have
    a funk
  • 17:54 - 17:56
    up.
  • 17:56 - 18:01
    So, so this is how, so, Promiscuous has you
  • 18:01 - 18:03
    covered. And you don't want to, when you're
    developing
  • 18:03 - 18:07
    event-driven services, you, you don't want
    to, to think
  • 18:07 - 18:09
    about all the races you could have and all
  • 18:09 - 18:13
    that. Like, it's way too complicated. But
    we still
  • 18:13 - 18:17
    want a very simple API. So.
  • 18:17 - 18:22
    So essentially, Promiscuous is, is your main
    databus, right.
  • 18:22 - 18:26
    And it does, so, so under the cover you
  • 18:26 - 18:28
    have, you have RabiitMQ which is, which is
    a
  • 18:28 - 18:31
    message broker, so you're gonna have publisher
    applications that
  • 18:31 - 18:36
    are gonna send their messages on RabbitMQ,
    and then
  • 18:36 - 18:39
    you're gonna have subscriber applications
    that are gonna connect
  • 18:39 - 18:41
    to RabbitMQ and each of the services can have
  • 18:41 - 18:43
    their own queue, I think, going to, to receive
  • 18:43 - 18:45
    those messages through RabbitMQ.
  • 18:45 - 18:47
    So no subscriber actually talk to the publisher
    app
  • 18:47 - 18:52
    directly. So you're gonna have some good decoupling
    mechanism.
  • 18:52 - 18:55
    And because we need to synchronize all the
    workers
  • 18:55 - 18:59
    together, we use Reddis. So for example, that
    worker's
  • 18:59 - 19:01
    like, oh wait, so before I can create that
  • 19:01 - 19:03
    message I need for you to wait to create
  • 19:03 - 19:04
    the user, OK. I'm gonna wait for you a
  • 19:04 - 19:07
    little bit. Oh, you died. Well, in that case
  • 19:07 - 19:09
    I'm going to process that message. So all
    of
  • 19:09 - 19:12
    that is done through Reddis.
  • 19:12 - 19:14
    So let's, let's see a bit of the API
  • 19:14 - 19:17
    of Promiscuous. So on the top, I have a
  • 19:17 - 19:21
    publisher application running with ActiveRecord
    on PosGres, for example,
  • 19:21 - 19:23
    and on the bottom I have a subscriber application
  • 19:23 - 19:25
    running on MongoDB.
  • 19:25 - 19:26
    So all I need to do as a developer
  • 19:26 - 19:30
    is to include the Promiscuous publisher mixin
    and publish
  • 19:30 - 19:33
    the field that I'm, I'm interested in, for
    example,
  • 19:33 - 19:34
    email and name.
  • 19:34 - 19:36
    On the subscriber's side, I'm going to include
    the
  • 19:36 - 19:40
    Promiscuous subscriber mixin and, and, in
    my subscribe block,
  • 19:40 - 19:42
    I'm going to put the fields I'm interested
    in,
  • 19:42 - 19:43
    too. And that's it.
  • 19:43 - 19:44
    That's all you need to do. That's the entire
  • 19:44 - 19:46
    API. That's it.
  • 19:46 - 19:51
    So, of course, once you start developing this,
    you
  • 19:51 - 19:53
    want to start testing that. And Promiscuous
    provides you
  • 19:53 - 19:57
    with a testing framework. So, for us, we leave
  • 19:57 - 20:00
    that interpretation tests are extremely important,
    and we, we
  • 20:00 - 20:02
    have to, to test our subscribers in a way
  • 20:02 - 20:05
    that is decoupled from the publishers.
  • 20:05 - 20:09
    So the publishers actually, so Promiscuous
    allows publishers to,
  • 20:09 - 20:11
    to create a gem to publish a gem with
  • 20:11 - 20:15
    factories that represent the kind of data
    that, if
  • 20:15 - 20:17
    you were to subscribe to their model, you,
    the
  • 20:17 - 20:19
    kind of data that you would get.
  • 20:19 - 20:23
    So to illustrate this, I'm going to show you,
  • 20:23 - 20:26
    an, a real test of Sniper, and you can
  • 20:26 - 20:29
    see, on the top, like, we just do create
  • 20:29 - 20:33
    Crowdtap member instead of the regular Crowdtap
    create member.
  • 20:33 - 20:36
    And so by doing this, Promiscuous is going
    to
  • 20:36 - 20:40
    take the factory of Crowdtap and, and package
    the
  • 20:40 - 20:43
    payload that you have received for real in
    production
  • 20:43 - 20:45
    and send it through your, your cloud client.
    And
  • 20:45 - 20:49
    so you're gonna be able to test a really
  • 20:49 - 20:54
    well your application as if it was in production.
  • 20:54 - 20:58
    So to really demonstrate how easy it is to
  • 20:58 - 21:01
    use Promiscuous, Kareem is going to show you
    a
  • 21:01 - 21:04
    live demonstration.
  • 21:04 - 21:11
    K.K.: Hello. Thanks Nico. All right. Let's,
    let's show
  • 21:21 - 21:23
    you guys how awesome this is.
  • 21:23 - 21:27
    OK, so what I'm gonna do is I'm gonna
  • 21:27 - 21:31
    show, show you guys adding, taking one of
    our
  • 21:31 - 21:35
    existing models on our, on, on one of our
  • 21:35 - 21:38
    apps, and subscribing to it in another. So
    on
  • 21:38 - 21:41
    the, on the left side, we've got Crowdtap.
    And
  • 21:41 - 21:43
    I've got the, one of our models that we're
  • 21:43 - 21:47
    actually not publishing yet, which is Package,
    and so
  • 21:47 - 21:49
    we're gonna take this and we're going to publish
  • 21:49 - 21:52
    this model, and then, on the, on the other
  • 21:52 - 21:54
    side, which is Sniper on the right side, which
  • 21:54 - 21:57
    is the targeting app we were discussing, I'm
    going
  • 21:57 - 22:01
    to subscribe to that model so that any changes
  • 22:01 - 22:04
    to the publisher app are reflected to the,
    to,
  • 22:04 - 22:06
    on the subscriber app. And I'm also gonna
    put
  • 22:06 - 22:09
    some callbacks in there to bind to any changes
  • 22:09 - 22:10
    that are happening.
  • 22:10 - 22:14
    So let's, let's go ahead and do that. So,
  • 22:14 - 22:16
    all you need to do first is just include,
  • 22:16 - 22:19
    you know, the Promiscuous publisher, which
    Nico showed you
  • 22:19 - 22:23
    in that API example. And then just wrap, you
  • 22:23 - 22:26
    know, whatever fields you want to publish
    in a
  • 22:26 - 22:28
    publish block. And so this case, you don't
    need
  • 22:28 - 22:31
    to publish everything. And, and that's important,
    you want
  • 22:31 - 22:34
    to figure out what's your public, what's your
    API,
  • 22:34 - 22:36
    right, and doesn't need to be the entire model.
  • 22:36 - 22:38
    So you publish what you want, so in this
  • 22:38 - 22:43
    case, let's publish name and features. And
    that's it
  • 22:43 - 22:45
    on the publisher's side, and so let's go ahead
  • 22:45 - 22:48
    and do the, or, write the subscriber. So the
  • 22:48 - 22:49
    only thing you need to do is create a
  • 22:49 - 22:53
    model with exactly the same name - so, Package.
  • 22:53 - 22:57
    You know, we're gonna store it in Mongo.
  • 22:57 - 22:59
    Include the Promiscuous subscriber, so we're,
    you know, reflection
  • 22:59 - 23:04
    of the Promiscuous publisher. And then mirror,
    again, the
  • 23:04 - 23:08
    publish block with the subscribe block. And
    let's only
  • 23:08 - 23:12
    subscribe to the, the name. Just for this
    example.
  • 23:12 - 23:14
    And then let's print out the name every time
  • 23:14 - 23:18
    the name changes. OK.
  • 23:18 - 23:20
    So that's it. So that's all the code you
  • 23:20 - 23:24
    have to write. So let's start up the Promiscuous
  • 23:24 - 23:31
    subscriber
    and take a look at RabbitMQ.
  • 23:32 - 23:36
    So RabbitMQ, it's an awesome admin AP- UI,
    and
  • 23:36 - 23:38
    we just started the subscriber. There are
    no queues
  • 23:38 - 23:43
    here. We should see a queue any second now.
  • 23:43 - 23:50
    I type bad.
  • 23:50 - 23:57
    There we go.
  • 23:58 - 24:01
    So we have a queue in, in Rabbit. We're
  • 24:01 - 24:05
    gonna kill the worker. Let's go back to Rabbit,
  • 24:05 - 24:07
    and this is a reason that we, we, we
  • 24:07 - 24:10
    chose Rabbit is it supports persistent queues.
    And what
  • 24:10 - 24:12
    that means is, even if a worker dies, your
  • 24:12 - 24:16
    queue is still there. It's pers- it's durable.
    And
  • 24:16 - 24:20
    any messages that would be consumed or buffered
    by
  • 24:20 - 24:21
    Rabbit, and when you start the worker up again
  • 24:21 - 24:22
    you get those messages.
  • 24:22 - 24:24
    So you guarantee that those messages are gonna
    be
  • 24:24 - 24:24
    delivered.
  • 24:24 - 24:27
    And that's a property that Rabbit gives you.
    It's
  • 24:27 - 24:32
    awesome. So let's go back and let's, let's
    publish
  • 24:32 - 24:34
    some of these. So first let's make sure we
  • 24:34 - 24:39
    save this. Let's reload. Just to get those
    changes.
  • 24:39 - 24:43
    And then I want to also illustrate how dependencies
  • 24:43 - 24:44
    are tracked, so let's do a read, so I'm
  • 24:44 - 24:47
    just gonna read the last member that we have
  • 24:47 - 24:50
    in our database, and then let's actually create
    a
  • 24:50 - 24:57
    package.
  • 24:58 - 25:05
    Ok. So there we go. We've created that package
  • 25:08 - 25:12
    on Crowdtap. Let's, let's pop over back to
    Rabbit
  • 25:12 - 25:15
    and take a look at the payload of that
  • 25:15 - 25:18
    message.
  • 25:18 - 25:20
    And so here it is. So you can see
  • 25:20 - 25:23
    a lot of metadata here. Types is, you know,
  • 25:23 - 25:26
    the class we support inheritance, so you can,
    you
  • 25:26 - 25:28
    can publish an entire inheritance tree. You
    can publish
  • 25:28 - 25:32
    embedded documents. If you're using Mongoid,
    that's all supported.
  • 25:32 - 25:35
    Which, you know, is very powerful. Obviously,
    the ID,
  • 25:35 - 25:39
    the attributes that changed, the operation,
    here's some more
  • 25:39 - 25:41
    metadata. Importantly in the namespace so
    it's the name
  • 25:41 - 25:46
    of the app. Crowdtap. Some more information
    helps debugging,
  • 25:46 - 25:48
    like the host that was published from. Current
    user
  • 25:48 - 25:51
    if you're in a controller and you're, you're
    logged
  • 25:51 - 25:54
    in. Publish that. That's really useful for
    debugging, and
  • 25:54 - 25:57
    then, the most interesting part is the dependencies.
  • 25:57 - 25:59
    So we did a read in, in console, and
  • 25:59 - 26:02
    here's the associated dependency on that user.
    So here's
  • 26:02 - 26:05
    the ID and the version. WE use versioning
    to
  • 26:05 - 26:07
    make sure that when this message is consumed
    on
  • 26:07 - 26:11
    the subscriber's side, that user exists in
    that exact
  • 26:11 - 26:11
    state.
  • 26:11 - 26:13
    So that's how we manage all the dependencies
    and
  • 26:13 - 26:17
    do causal consistencies, and here's the right
    dependency which
  • 26:17 - 26:20
    is the, the creation, the object that we just
  • 26:20 - 26:21
    created.
  • 26:21 - 26:22
    So that's it. That's the payload. So let's,
    let's
  • 26:22 - 26:24
    go ahead and subscribe. And so what we should
  • 26:24 - 26:29
    see here is you know, hello world being printed
  • 26:29 - 26:34
    out. Drum roll.
  • 26:34 - 26:35
    Magic!
  • 26:35 - 26:40
    OK, so let's, you know, let's show that, let's
  • 26:40 - 26:47
    show update. OK. Much easier to type when
    you're
  • 26:50 - 26:58
    in your room than in front of people. OK.
  • 27:01 - 27:05
    OK.
  • 27:05 - 27:12
    All right. Sorry guys.
  • 27:21 - 27:28
    OK. Well. For some reason this isn't working.
    But,
  • 27:33 - 27:40
    we, let me try once more.
  • 27:40 - 27:47
    OK.That's weird. I'm like typing. OK. Let's,
    if, if,
  • 27:51 - 27:53
    if I had typed any change, it would be
  • 27:53 - 27:57
    immediate propogated over to the publisher's
    side and trust
  • 27:57 - 28:01
    me, it works. I can show you after.
  • 28:01 - 28:07
    So let's, you know, so, so, let's, you know,
  • 28:07 - 28:08
    what did this to us? So we started, you
  • 28:08 - 28:11
    know, with these two applications. The main
    app, which
  • 28:11 - 28:14
    is Crowdtap, and the targeting app, which
    is, you
  • 28:14 - 28:18
    know, Sniper, because it's targeting. And
    then we pulled
  • 28:18 - 28:21
    out all of our analytics in fiancé. You now
  • 28:21 - 28:25
    fiancé because it's tracks engagements, obviously.
  • 28:25 - 28:27
    And Bobby, you know, because he's the policeman
    that
  • 28:27 - 28:30
    makes sure that, you know, when people are
    posting
  • 28:30 - 28:33
    stuff, that you know, it's not spam or, and
  • 28:33 - 28:35
    if it's awesome, that it gets starred. So,
    you
  • 28:35 - 28:38
    know, we can iterate on using, you know, AEI
  • 28:38 - 28:43
    techniques here to, to moderate our, our,
    our posts.
  • 28:43 - 28:46
    And then Paparazzi, you know, is out there
    scraping
  • 28:46 - 28:48
    Facebook and Twitter and gathering, you know,
    data, so
  • 28:48 - 28:53
    that we can report on that for our clients.
  • 28:53 - 28:56
    And then Casanova, you know, generates CSVs
    and it's
  • 28:56 - 29:02
    Casanova because, because it works, because
    it spreads the
  • 29:02 - 29:05
    love. I still don't, I still don't get that
  • 29:05 - 29:06
    name.
  • 29:06 - 29:12
    But. You know. WE have creative developers.
    And then
  • 29:12 - 29:16
    email service, Iris, which is the, the, the
    nor,
  • 29:16 - 29:23
    the notification God, and then most interestingly
    is, at
  • 29:23 - 29:25
    least in my perspective is Captain Planet.
    And Captain
  • 29:25 - 29:27
    Planet came out of a two day hack-a-thon that
  • 29:27 - 29:32
    we recently had, where a developer was able
    to,
  • 29:32 - 29:35
    on his, on his laptop, subscribe to the production
  • 29:35 - 29:39
    database, production Rabbit, and generate
    ten reports off of
  • 29:39 - 29:41
    that data to solve a really big pain point
  • 29:41 - 29:44
    that we have that our account team has, and
  • 29:44 - 29:47
    actually do that in a completely isolated
    way that
  • 29:47 - 29:50
    didn't impact the production system at all.
  • 29:50 - 29:52
    And was actually running that on his laptop,
    just
  • 29:52 - 29:55
    like the fire hose of production data, on
    his
  • 29:55 - 29:57
    laptop, and did that in a couple of days
  • 29:57 - 30:00
    and worked with it. That is, that's joy, right.
  • 30:00 - 30:02
    That's back to the joy of the fifteen minute
  • 30:02 - 30:06
    blog. That's taking a really complex system
    and making
  • 30:06 - 30:08
    it, you know, easy to use, and it took,
  • 30:08 - 30:12
    you know, this, and went back to something
    ugly
  • 30:12 - 30:16
    to a lot of little cute fun cuddly apps
  • 30:16 - 30:18
    that we, that we now have.
  • 30:18 - 30:20
    And with that, I'm gonna pass it back to
  • 30:20 - 30:23
    Nico to wrap things up.
  • 30:23 - 30:27
    N.V.: So to wrap things up, we've seen that
  • 30:27 - 30:31
    Promiscuous is very useful to do event-driven
    services. So
  • 30:31 - 30:33
    you can trigger callbacks realtime. For example,
    you want
  • 30:33 - 30:36
    to send emails when some piece of data is
  • 30:36 - 30:39
    changing. You want to keep your caches warm.
    Whenever,
  • 30:39 - 30:42
    or, say, you know, whenever some piece of
    data
  • 30:42 - 30:45
    changes, you wanna is, instead of invalidating
    your caches,
  • 30:45 - 30:47
    you can actually reconfig the, the right thing.
  • 30:47 - 30:50
    You could push data asynchronously to your
    browsers to
  • 30:50 - 30:53
    improve the user experience. And we want to
    do
  • 30:53 - 30:58
    all that also by, and also doing database
    replication,
  • 30:58 - 31:00
    but different kind of databases, right. So
    I want
  • 31:00 - 31:02
    to be able to replicate my PosGres database
    to
  • 31:02 - 31:07
    ElasticSearch and maybe MongoDB and maybe
    Riot - whatever
  • 31:07 - 31:09
    it is. And I want this to be decoupled,
  • 31:09 - 31:11
    and I want this to be, do this at
  • 31:11 - 31:14
    scale and with good consistency.
  • 31:14 - 31:16
    So that was gonna allow you to, to really
  • 31:16 - 31:19
    see the data that you want for the feature
  • 31:19 - 31:22
    that you need to implement. And so real time
  • 31:22 - 31:25
    is really, really important these days. And,
    and if
  • 31:25 - 31:30
    you can embrace the arch, the, the asynchronous
    layer
  • 31:30 - 31:33
    of your application and to really, to really
    unleash
  • 31:33 - 31:37
    the power of your data, right. So you can
  • 31:37 - 31:40
    really innovate now. You can hire some interns
    for
  • 31:40 - 31:43
    a summer and get them to do some matching
  • 31:43 - 31:47
    learning project directly in production without
    having you to
  • 31:47 - 31:49
    be worrying about, oh my god, they're gonna
    drop
  • 31:49 - 31:52
    my system and they're gonna pollute the code
    and
  • 31:52 - 31:53
    all that.
  • 31:53 - 31:55
    Like, if you don't like their stuff, eventually
    you
  • 31:55 - 31:58
    just delete their app and you're done, right.
    So,
  • 31:58 - 32:00
    so you can really go back to being agile
  • 32:00 - 32:02
    and try things really with, without having,
    oh my
  • 32:02 - 32:04
    god it's, I need to change so much things.
  • 32:04 - 32:08
    Like, you, you get back to, to really the,
  • 32:08 - 32:11
    to the agility of, of, of your team.
  • 32:11 - 32:13
    So that's, that's about it. So we invite you
  • 32:13 - 32:17
    to try it out. It's on GitHub, on Promiscuous
  • 32:17 - 32:20
    dash io slash Promiscuous. So we've been using
    it
  • 32:20 - 32:22
    in production for a year now and we're very
  • 32:22 - 32:24
    happy with it. But it requires a bit of
  • 32:24 - 32:26
    babysitting for now.
  • 32:26 - 32:28
    So we're still working on it, and we're trying
  • 32:28 - 32:31
    to make it really a hands-free experience.
    So that
  • 32:31 - 32:33
    you can just plug it in and you have
  • 32:33 - 32:35
    nothing to worry about and you have all the
  • 32:35 - 32:38
    different recovery mechanism that kicks in
    at the right
  • 32:38 - 32:40
    time and everything.
  • 32:40 - 32:42
    So if you feel adventurous, you can try to
  • 32:42 - 32:45
    extract your email logic out of your main
    application
  • 32:45 - 32:48
    because that's, like, the obvious, like, you
    have no,
  • 32:48 - 32:50
    it's an observer, really.
  • 32:50 - 32:53
    And, and perhaps build some reporting service,
    also, for
  • 32:53 - 32:57
    some, some of your fancy clients. So, if you
  • 32:57 - 32:59
    try it out, we'll be super happy to help
  • 32:59 - 33:03
    you with the, to go, with Promiscuous. And
    we,
  • 33:03 - 33:06
    you can find us on Twitter and GitHub, kareemk
  • 33:06 - 33:07
    and nviennot.
  • 33:07 - 33:10
    Thank you. And now we'll take questions.
Title:
Ruby Conf 2013 - Promiscuous: A robust service-oriented architecture framework
Description:

more » « less
Duration:
33:34

English subtitles

Revisions