< Return to Video

RailsConf 2014 - Ultra Light and Maintainable Rails Wizards by Andy Maleh

  • 0:17 - 0:18
    ANDY MALEH: Sorry everybody. I lost the slides.
  • 0:18 - 0:21
    I had to reconstruct them right now.
  • 0:21 - 0:24
    Right, like in ten minutes.
  • 0:24 - 0:27
    Ultra light and maintainable Rails wizards.
  • 0:27 - 0:30
    Who has written a wizard in their lifetime?
  • 0:30 - 0:34
    OK. It's, it's almost like the most common
    web
  • 0:34 - 0:40
    use case, yet it's the least under, under-valued
    with
  • 0:40 - 0:45
    regards to providing patterns for doing, like,
    writing good
  • 0:45 - 0:47
    code in order to provide for maintainable
    wizards.
  • 0:47 - 0:53
    A lot of the time, people write, like, multi-step
  • 0:53 - 0:54
    wizards, where they end up doing a lot of
  • 0:54 - 0:58
    copy-paste between the steps or between a
    bunch of
  • 0:58 - 1:00
    controllers. And that makes it a hell of a
  • 1:00 - 1:03
    problem to maintain that code a year or two
  • 1:03 - 1:04
    later. And every code base is, you know, meant
  • 1:04 - 1:07
    to be created for a year at least. Maintenance
  • 1:07 - 1:09
    cost is what's really expensive. It's not,
    you know,
  • 1:09 - 1:12
    I can write a wizard in two weeks but
  • 1:12 - 1:13
    will I be able to maintain it cheaply over
  • 1:13 - 1:17
    a year. And that, that's really why I'm giving
  • 1:17 - 1:19
    a talk about this subject.
  • 1:19 - 1:22
    So just to give you an overview, I'll be
  • 1:22 - 1:26
    talking about, why do we even use a wizard?
  • 1:26 - 1:32
    Provide an example. Some implementation goals.
    The 1001 wizard
  • 1:32 - 1:36
    implementations out there. And, finally, I'll
    talk about what
  • 1:36 - 1:38
    I think is a good ultra light and maintainable
  • 1:38 - 1:40
    wizard approach.
  • 1:40 - 1:45
    So first of all, we don't want to overwhelm
  • 1:45 - 1:48
    the user with a huge form of information,
    kind
  • 1:48 - 1:50
    of like those government forms that we have
    in
  • 1:50 - 1:56
    Canada. So I come from Montreal, by the way.
  • 1:56 - 1:59
    This is painful on a computer screen. Computers
    should
  • 1:59 - 2:03
    enable people to do better than actual physical
    paper.
  • 2:03 - 2:05
    So one way of tackling this problem is to
  • 2:05 - 2:11
    divide it into multiple steps in a wizard.
  • 2:11 - 2:16
    So also it's about simplifying the workflow
    into multiple
  • 2:16 - 2:18
    steps that make them digestible, just like
    this protein
  • 2:18 - 2:24
    shake. And finally it, it gives you the opportunity
  • 2:24 - 2:27
    to provide more explanation for what each
    form does,
  • 2:27 - 2:30
    by being able to fit more information when
    you
  • 2:30 - 2:32
    break it up across multiple pages, like what
    they
  • 2:32 - 2:34
    do with TurboTax.
  • 2:34 - 2:39
    Who here has filed their taxes?
  • 2:39 - 2:43
    Yeah. I did not. I just did this so
  • 2:43 - 2:47
    I see who raised his hand.
  • 2:47 - 2:54
    OK. So I had a, a software architecture gig
  • 2:54 - 2:57
    at EarlyShare about a couple of years ago
    where
  • 2:57 - 3:01
    I helped them launch their site. EarlyShare
    is kind
  • 3:01 - 3:05
    of like KickStarter or Indiegogo, except it's
    focused on
  • 3:05 - 3:09
    allowing people to do crowd investment in
    businesses.
  • 3:09 - 3:12
    And it was a website that was being built
  • 3:12 - 3:14
    fast in order to catch up with some legal
  • 3:14 - 3:20
    laws in the U.S. that would allow crowd investment.
  • 3:20 - 3:24
    So I helped them launch the site and they
  • 3:24 - 3:29
    had, they, as part of their website, they
    needed
  • 3:29 - 3:33
    a couple of onboarding wizards. One for investors
    and
  • 3:33 - 3:36
    one for business people.
  • 3:36 - 3:39
    But there were other requirements. Like, the
    business was
  • 3:39 - 3:44
    bootstrapped. We were only two developers.
    Me as the
  • 3:44 - 3:46
    senior and then there was a junior with a
  • 3:46 - 3:49
    CTO and a designer and that's it. He wanted
  • 3:49 - 3:51
    us to move super fast, and I was brought
  • 3:51 - 3:55
    in as the Rails expert.
  • 3:55 - 3:57
    So I had not written a wizard in like
  • 3:57 - 3:59
    four years before that. Or maybe five years.
    Like,
  • 3:59 - 4:02
    maybe since the days I did Java development.
    And
  • 4:02 - 4:05
    when I started tackling this problem in Ruby,
    you
  • 4:05 - 4:06
    know, I like, I went online, checked some
    Google
  • 4:06 - 4:11
    guides and all that or StackOverflow, whatever.
  • 4:11 - 4:16
    And none of their approaches satisfied me.
    So let's
  • 4:16 - 4:18
    talk about what I found.
  • 4:18 - 4:21
    So the wizard example, though, is basically,
    you have
  • 4:21 - 4:24
    four steps. Step one is collect basic info.
    Step
  • 4:24 - 4:27
    two is details, more details. Step three is
    upload
  • 4:27 - 4:30
    some document content. Step four is just preview
    before
  • 4:30 - 4:32
    you finish the wizard. And then once it's
    done,
  • 4:32 - 4:35
    it shows you a summary, like a landing page
  • 4:35 - 4:38
    for the project that, that the business is
    proposing
  • 4:38 - 4:40
    for investment.
  • 4:40 - 4:47
    OK. So, I mean, the goals I had was
  • 4:47 - 4:49
    the Rails server had to persist every progress
    on
  • 4:49 - 4:53
    every step. So no, like, js client-side tricks.
    That
  • 4:53 - 4:57
    was out of scope. I wanted it to still,
  • 4:57 - 5:01
    like, be RESTful, like, which is a common
    issue
  • 5:01 - 5:03
    with wizard, like, building wizards. How to
    make them
  • 5:03 - 5:05
    properly RESTful.
  • 5:05 - 5:09
    I wanted to also stick with MVC, object-oriented
    principles
  • 5:09 - 5:12
    because we're using an object-oriented language.
    So I wanted
  • 5:12 - 5:14
    to make sure that the code is maintainable
    by
  • 5:14 - 5:18
    other developers going to the feature.
  • 5:18 - 5:22
    And then some non-functional requirements,
    like productivity. So that
  • 5:22 - 5:27
    was part of the concern that the CTO had,
  • 5:27 - 5:28
    which is he wanted us to move fast, like,
  • 5:28 - 5:30
    really, really fast. That was part of the
    reason
  • 5:30 - 5:32
    why he brought me in. Well, big mistake. I,
  • 5:32 - 5:36
    I pay attention to details and nice design
    concerns.
  • 5:36 - 5:38
    So I will slow him down but for good
  • 5:38 - 5:39
    reasons.
  • 5:39 - 5:41
    I'll slow him down and then he'll go much
  • 5:41 - 5:44
    faster later on.
  • 5:44 - 5:49
    Still, the story does have a happy ending.
    So
  • 5:49 - 5:54
    maintainability, by both junior and senior
    developers. They had
  • 5:54 - 5:57
    one senior developer in Brazil as well. Which
    I
  • 5:57 - 6:00
    just remembered. He was brought in a little
    later
  • 6:00 - 6:02
    on.
  • 6:02 - 6:04
    Performance concerns. Security concerns.
  • 6:04 - 6:07
    So it's pretty, it's pretty basic stuff. Like,
    I
  • 6:07 - 6:09
    mean, these are the concerns that we should
    care
  • 6:09 - 6:13
    about whenever we build any feature, really.
  • 6:13 - 6:17
    So one approach that I've seen on actual code
  • 6:17 - 6:18
    bases, I actually saw it on a code base
  • 6:18 - 6:21
    that I maintained on a following project after
    that
  • 6:21 - 6:27
    one, was one controller per wizard step.
  • 6:27 - 6:31
    So you create a REST resource per wizard step.
  • 6:31 - 6:37
    And you had multiple controllers, multiple
    sets of views
  • 6:37 - 6:39
    and helpers. And then each controller redirects
    to the
  • 6:39 - 6:42
    next one. So something like this. And you
    could
  • 6:42 - 6:45
    do it either with one ActiveRecord that has
    conditional
  • 6:45 - 6:46
    validations for each step, where it says OK,
    if
  • 6:46 - 6:50
    step one, validate presence of name, if step
    two,
  • 6:50 - 6:53
    validate presence of blah, blah, blah. Or
    you could
  • 6:53 - 6:54
    have multiple ActiveRecords.
  • 6:54 - 7:02
    But either way, who here could find concerns
    with
  • 7:02 - 7:04
    this approach, or at least something that
    could be
  • 7:04 - 7:07
    improved on? Somebody volunteer? Go ahead.
  • 7:07 - 7:10
    AUDIENCE: [indecipherable - 00:07:10]
  • 7:10 - 7:14
    A.M.: And what's the concern with that? So
    what
  • 7:14 - 7:18
    if you have a whole bunch of controllers?
  • 7:18 - 7:21
    AUDIENCE: [indecipherable - 00:07:16]
  • 7:22 - 7:26
    A.M.: OK. I mean, I've built applications
    that managed
  • 7:27 - 7:34
    user profiles, user accounts, blog posts,
    for example, whatever.
  • 7:35 - 7:37
    You need a controller for each one of those.
  • 7:37 - 7:38
    I don't think you could escape that.
  • 7:38 - 7:41
    So I'm gonna give other people a chance to
  • 7:41 - 7:43
    talk, but I do get your point. I want
  • 7:43 - 7:44
    to clarify it.
  • 7:44 - 7:44
    Go ahead.
  • 7:44 - 7:47
    AUDIENCE: I was gonna say repetition-
  • 7:47 - 7:48
    A.M.: Exactly.
  • 7:48 - 7:49
    AUDIENCE: Re-usability and dependencies.
  • 7:49 - 7:52
    A.M.: Yeah. So quite a bit of that code
  • 7:52 - 7:54
    is repetitive. It was just, it was always
    loading
  • 7:54 - 7:58
    the resource. It's almost the same resource.
    Actually, if
  • 7:58 - 8:00
    you use one ActiveRecord, it is the same resource.
  • 8:00 - 8:03
    And then we'd run some validations and then
    it
  • 8:03 - 8:05
    would pass to the next controller. So, I mean,
  • 8:05 - 8:07
    there was quite a bit of repetition.
  • 8:07 - 8:11
    We try to add features a couple of months
  • 8:11 - 8:14
    after the, after a developer had built that
    wizard
  • 8:14 - 8:18
    on that project, and they wanted us to deliver
  • 8:18 - 8:24
    something in a week, and apparently another
    developer, before
  • 8:24 - 8:26
    I joined that team, had tried to implement
    that
  • 8:26 - 8:28
    feature and it took him a month. And he
  • 8:28 - 8:30
    still couldn't do it with the, with the design
  • 8:30 - 8:31
    they had.
  • 8:31 - 8:33
    It was still, it was just taking a long
  • 8:33 - 8:35
    time. Like, he was still not done. And then
  • 8:35 - 8:39
    that guy left. So I ended up solving the
  • 8:39 - 8:42
    problem with another senior guy. And it was,
    so,
  • 8:42 - 8:44
    I ended up applying this ultra light maintainable
    wizard
  • 8:44 - 8:48
    approach that I discovered on the EarlyShares
    dot com
  • 8:48 - 8:51
    project, and it worked out really well. So,
    which,
  • 8:51 - 8:54
    I'll talk about a little later. But that helped
  • 8:54 - 8:58
    us actually develop it in, if I remember right,
  • 8:58 - 9:02
    it was about seven days.
  • 9:02 - 9:07
    Test first, and rewriting the entire thing,
    also.
  • 9:07 - 9:09
    But it was specifically because we didn't
    have that
  • 9:09 - 9:11
    many controllers anymore. So, we wrote a lot
    less
  • 9:11 - 9:13
    tests so we had a lot less code to
  • 9:13 - 9:15
    maintain. So that was part of it.
  • 9:15 - 9:17
    So, another approach I've seen is one controller.
    Sorry.
  • 9:17 - 9:21
    Oh, OK, that's just the critique. We already
    went
  • 9:21 - 9:22
    over that. I don't think I want to go
  • 9:22 - 9:25
    too much into details for that cause we're
    limited
  • 9:25 - 9:25
    on time.
  • 9:25 - 9:28
    But yeah, let's go next to one action and
  • 9:28 - 9:31
    presenter per wizard step. So, I mean, another
    approach
  • 9:31 - 9:33
    is, OK, keep one ActiveRecord, but I've also
    seen
  • 9:33 - 9:38
    this approach in a code base, where there
    were
  • 9:38 - 9:44
    different, say, new_step1, create_step1, new_step2,
    create_step2. So there were
  • 9:44 - 9:47
    just, like, eight actions on that controller,
    each mimicking
  • 9:47 - 9:51
    the new and, and, and create, say, on the
  • 9:51 - 9:52
    RESTful resource.
  • 9:52 - 9:56
    So, although it feels RESTful, it was not
    REST
  • 9:56 - 10:01
    anymore. It already broke out of the REST
    paradigm.
  • 10:01 - 10:03
    So we can improve over that.
  • 10:03 - 10:07
    Also, it still had some repetitive code across
    the
  • 10:07 - 10:10
    actions. So, I mean, it was, it was just
  • 10:10 - 10:14
    a slight improvement to the problem. Not much.
  • 10:14 - 10:18
    Using presenters, which is an abstraction
    layer between the
  • 10:18 - 10:21
    ActiveRecord and the controller is an improvement
    in the
  • 10:21 - 10:23
    sense that you can put the validations for
    each
  • 10:23 - 10:28
    presenter per step separately and not have
    conditional validations.
  • 10:28 - 10:32
    I'll talk more about that going forward.
  • 10:32 - 10:35
    So it was more something like this, where
    the
  • 10:35 - 10:39
    controller had a whole bunch of actions that
    are
  • 10:39 - 10:44
    connecting to presenters that are talking
    to an ActiveRecord.
  • 10:44 - 10:46
    OK.
  • 10:48 - 10:52
    So I already went over the caveats of that.
  • 10:52 - 10:56
    OK. Who here has written a wizard with session
  • 10:56 - 11:01
    accumulation approach? How, how did that work
    out for
  • 11:01 - 11:02
    you or, do you think-
  • 11:02 - 11:04
    AUDIENCE: That's why I'm here.
  • 11:04 - 11:07
    -well, I'm sorry if it sounds. Well, tell
    me
  • 11:07 - 11:08
    why you're here. I'm curious.
  • 11:08 - 11:08
    AUDIENCE: Well, I mean, right now it's just
    that
  • 11:08 - 11:12
    it's to the point where we're breaking it
    down
  • 11:12 - 11:18
    further, it was a very basic general implementation.
    And
  • 11:18 - 11:22
    now dealing with the fact that we have so
  • 11:22 - 11:26
    much session iteration that I have to pass
    it
  • 11:26 - 11:27
    between, you know, controllers. We deal with
    it from
  • 11:27 - 11:27
    multiple angles, and it's, I mean, I can't
    put
  • 11:27 - 11:28
    that stuff in a model. So my controllers are
  • 11:28 - 11:29
    getting really out of hand.
  • 11:29 - 11:30
    A.M.: Exactly. Yeah. Yup. Yup. Yup.
  • 11:30 - 11:31
    So you end up with the live session management
  • 11:31 - 11:34
    code in the controller, which breaks MVC.
    So if
  • 11:34 - 11:36
    you're not breaking REST, you break MVC. It's
    really
  • 11:36 - 11:38
    tough. It's a tough problem.
  • 11:38 - 11:41
    AUDIENCE: Can you explain what session accumulation
    is?
  • 11:41 - 11:43
    A.M.: Yes. So, actually, maybe I should have
    somebody
  • 11:43 - 11:45
    explain that. I saw you raise your hand. Would
  • 11:45 - 11:48
    you mind explaining it to the audience.
  • 11:48 - 11:53
    AUDIENCE: Sure. It's basically, as you're
    going through the
  • 11:53 - 11:58
    specs, that you're storing all of the information
    that
  • 11:58 - 12:02
    needs to be in the session. So then, you
  • 12:02 - 12:03
    go through step
  • 12:03 - 12:06
    one. You gather the basic info from the form.
  • 12:06 - 12:09
    When submitting the form, instead of storing
    that in
  • 12:09 - 12:11
    an ActiveRecord, you actually store it in,
    in the
  • 12:11 - 12:16
    session, using the session helper in the,
    in the
  • 12:16 - 12:18
    Rails controller. And then once you move to,
    and
  • 12:18 - 12:20
    then you redirect to step two, and then you
  • 12:20 - 12:22
    submit that form again, and then you add more
  • 12:22 - 12:23
    stuff to the session.
  • 12:23 - 12:25
    Once you reach the last step, kind of like
  • 12:25 - 12:28
    what you see in this diagram, that's when
    you're
  • 12:28 - 12:30
    ready to create the ActiveRecord. So you pass
    all
  • 12:30 - 12:34
    of this as the params and the ActiveRecord
    will
  • 12:34 - 12:41
    validate it and then you're done.
  • 12:41 - 12:48
    OK. So, so I mean as far as critique.
  • 12:49 - 12:53
    So reliance of session, storing objects in
    the session
  • 12:53 - 12:56
    has implications on scalability. Usually you
    want to store
  • 12:56 - 13:00
    ids of primitives because they're easier to
    move across
  • 13:00 - 13:02
    servers when it's primitive data and be able
    to
  • 13:02 - 13:04
    support multiple servers.
  • 13:04 - 13:07
    My understanding is if you have actual objects
    in
  • 13:07 - 13:10
    the session, it makes it harder for you to
  • 13:10 - 13:12
    scale.
  • 13:12 - 13:15
    Controller code is more complex because of
    managing session
  • 13:15 - 13:18
    data. Validations could get defined twice,
    because you might
  • 13:18 - 13:20
    have to validate on every step as well, in
  • 13:20 - 13:23
    JavaScript or in a, in a presenter or something.
  • 13:23 - 13:26
    And, also present at the last step in the
  • 13:26 - 13:26
    model.
  • 13:26 - 13:28
    So again, I mean, if you're not breaking REST,
  • 13:28 - 13:30
    you're breaking MVC. If you're not breaking
    MVC, you're
  • 13:30 - 13:35
    breaking duplication whatever, concerns, so,
    it's a tough problem.
  • 13:35 - 13:39
    Hidden value accumulation. Somebody share
    with us what this
  • 13:39 - 13:42
    is, or, it's very similar to session accumulation.
  • 13:42 - 13:43
    Yeah, go ahead.
  • 13:43 - 13:46
    AUDIENCE: Really, when you're submitting the
    form at each
  • 13:46 - 13:50
    step you're shoving all the values from the
    form
  • 13:50 - 13:53
    into hidden fields on the page, and then eventually,
  • 13:53 - 13:57
    when you hit submit, the final version will
    just
  • 13:57 - 14:00
    set everything to the server.
  • 14:00 - 14:01
    A.M.: Yup.
  • 14:01 - 14:05
    So it's not stateful, it's stateless, because
    it keeps,
  • 14:05 - 14:08
    like, each request has its state. You don't
    have
  • 14:08 - 14:11
    to maintain the state in a session. So the
  • 14:11 - 14:15
    performance implications are gone. Like, it
    has no problems
  • 14:15 - 14:19
    in scalability.
  • 14:19 - 14:22
    But you might, you, you might not want to
  • 14:22 - 14:23
    expose the values all the time on the, on
  • 14:23 - 14:25
    the user page. You can hash them or do
  • 14:25 - 14:29
    encoding on them, so that could improve that,
    that
  • 14:29 - 14:33
    problem with regards to keeping form data
    in a,
  • 14:33 - 14:34
    in hidden fields on the page every step of
  • 14:34 - 14:37
    the way.
  • 14:37 - 14:44
    But there's, yeah, I mean, but the complexity
    is
  • 14:44 - 14:46
    still there, with having to manage the accumulation
    and
  • 14:46 - 14:48
    having to construct the model at the end.
  • 14:48 - 14:50
    So it's a slight improvement.
  • 14:50 - 14:52
    Who here has used the state matching for a
  • 14:52 - 14:53
    wizard?
  • 14:53 - 14:58
    OK. Do you mind sharing with us your experience
  • 14:58 - 14:59
    with it?
  • 14:59 - 15:02
    AUDIENCE: I think main problem that you run
    into
  • 15:02 - 15:06
    is that you get fat models, cause you have
  • 15:06 - 15:07
    to put all of the different validations into
    different
  • 15:07 - 15:09
    states. But overall, I found that it was a
  • 15:09 - 15:12
    better compromise than the other options.
  • 15:12 - 15:16
    A.M.: Generally it is. One, yeah. So, you
    create
  • 15:16 - 15:21
    one ActiveRecord. You make the ActiveRecord
    a state machine.
  • 15:21 - 15:23
    You have to add a step column on that
  • 15:23 - 15:27
    model to support which step you're on when
    it,
  • 15:27 - 15:29
    in order for the validation to know which
    validations
  • 15:29 - 15:31
    to run for what step. So that way you
  • 15:31 - 15:34
    say, OK, on step one, if you have that
  • 15:34 - 15:36
    column, you'll say, OK, you'll have validations
    that say,
  • 15:36 - 15:39
    OK, if it's step one, then I'm gonna check
  • 15:39 - 15:41
    for first name and last name presence. If
    it's
  • 15:41 - 15:42
    step two I'm gonna, I'm gonna check that the
  • 15:42 - 15:44
    project details are present. And so on and
    so
  • 15:44 - 15:49
    forth, depending on what each form, what field,
    what
  • 15:49 - 15:51
    field each form contains on the, in the specific
  • 15:51 - 15:54
    step.
  • 15:54 - 16:01
    So yeah, different view per step. I already
    went
  • 16:02 - 16:03
    over conditional validations.
  • 16:03 - 16:05
    To share an example, it looks something like
    that,
  • 16:05 - 16:12
    like validate :phone, presence: true, if current_step
    is shipping.
  • 16:13 - 16:14
    So that's just one way of doing it. There's
  • 16:14 - 16:16
    other better ways of doing it. There's also
    gems
  • 16:16 - 16:17
    out there that help you with that. But that's
  • 16:17 - 16:18
    one way of doing it.
  • 16:18 - 16:21
    AUDIENCE: ActiveRecord has the ability to
    run conditional validations
  • 16:21 - 16:22
    like that. You don't have to run a block.
  • 16:22 - 16:27
    A.M.: Mhmm. Yup. Yup. I'm familiar with that.
    Yeah,
  • 16:27 - 16:28
    that's why I mentioned, there's multiple ways
    of doing
  • 16:28 - 16:30
    that. That's just one example.
  • 16:30 - 16:32
    AUDIENCE: How does, how is the state machine
    different
  • 16:32 - 16:39
    than the first, better than any of the ones
  • 16:40 - 16:44
    you mentioned, [indecipherable - 00:16:39]
  • 16:44 - 16:47
    A.M.: OK. With the other one, you could cheat
  • 16:47 - 16:50
    a bit and set an in memory variable that
  • 16:50 - 16:52
    represents the step name that you're on and
    then
  • 16:52 - 16:55
    do that conditional validation that way, whereas
    with this
  • 16:55 - 16:58
    one, you have, you're only working with one
    model
  • 16:58 - 17:02
    and you don't, you haven't managed the stepping.
    So
  • 17:02 - 17:04
    yeah, with the other approach, the controller
    is doing
  • 17:04 - 17:06
    management of the stepping. In this one the
    model
  • 17:06 - 17:09
    is doing the management of the stepping.
  • 17:09 - 17:14
    So critique. Well, first of all, it puts in
  • 17:14 - 17:16
    presentation concerns, like adding an extra
    column to our
  • 17:16 - 17:20
    presenter's state, sorry, step, is not part
    of the
  • 17:20 - 17:24
    domain, the business domain. So when you're
    doing MVC,
  • 17:24 - 17:26
    usually the model, you're trying to put in
    it
  • 17:26 - 17:30
    as much decoupled logic that's focused on
    the business
  • 17:30 - 17:33
    at hand as possible in order to maintain that
  • 17:33 - 17:36
    separately from any view concerns or controller
    concerns.
  • 17:36 - 17:39
    I mean, you can put anything in the model,
  • 17:39 - 17:41
    really. But the reason why we do that is,
  • 17:41 - 17:44
    in my experience, when I'm maintaining a code
    base,
  • 17:44 - 17:47
    if I'm not having to manage view concerns
    like
  • 17:47 - 17:50
    stepping into a state machine and a model
    concern,
  • 17:50 - 17:54
    like the business rules of, of what happens
    when,
  • 17:54 - 17:57
    you know, like the project description is
    not present
  • 17:57 - 18:00
    or whatever, then it's easier for me to maintain
  • 18:00 - 18:02
    that model, cause I'm not thinking on one
    thing
  • 18:02 - 18:03
    at a time. I'm not thinking multiple things
    at
  • 18:03 - 18:05
    the same time.
  • 18:05 - 18:10
    Also, it makes those models smaller files,
    if you
  • 18:10 - 18:13
    separate those concerns. You don't want a
    huge model
  • 18:13 - 18:16
    as maintaining a state machine and maintaining
    business rules
  • 18:16 - 18:19
    and maintaining like ten other things. You
    could manage
  • 18:19 - 18:23
    that with splitting that into modules or concerns,
    but
  • 18:23 - 18:27
    still, when I'm working with that model, my
    head
  • 18:27 - 18:29
    will have the context of everything at once.
    SO
  • 18:29 - 18:32
    it wouldn't, like, this is more of an advanced
  • 18:32 - 18:34
    programming thing. Like, once you've been
    programming for three
  • 18:34 - 18:37
    years at least, you'll, you'll start noticing
    that.
  • 18:37 - 18:43
    You'll start noticing the subtleties with
    regards to mixing
  • 18:43 - 18:46
    concerns. Like, you start understanding why
    people say follow
  • 18:46 - 18:49
    the single responsibility principle. I'm not
    a fan of
  • 18:49 - 18:52
    following it dogmatically, I, but I think
    it's a
  • 18:52 - 18:54
    good guideline, like any other guideline,
    where if you
  • 18:54 - 18:57
    could minimize responsibilities in a model
    and have it
  • 18:58 - 19:01
    not manage view concerns, then do that. Especially
    if
  • 19:01 - 19:04
    MVC prescribes that as well as that's what
    all
  • 19:04 - 19:06
    Rails developers on the field would expect.
  • 19:06 - 19:12
    So I think I pretty much sold that. So
  • 19:12 - 19:15
    yeah, so I mean, I think that makes it
  • 19:15 - 19:19
    pretty clear why I don't like this approach
    that
  • 19:19 - 19:20
    much.
  • 19:20 - 19:23
    Also, it's a bit techy. Like, thinking of
    the
  • 19:23 - 19:25
    wizard as a state machine is a bit computer
  • 19:25 - 19:27
    science-y. Like, I mean, I have a background
    in
  • 19:27 - 19:30
    computer science, but, the, the point of anything
    you
  • 19:30 - 19:31
    learn is to apply it in the right place
  • 19:31 - 19:34
    for it, and I don't feel like, when I'm
  • 19:34 - 19:36
    thinking about a wizard I'm thinking about
    the business
  • 19:36 - 19:37
    problem. That's what I really want to think
    about.
  • 19:37 - 19:38
    I don't want to think about a state machine.
  • 19:38 - 19:40
    As cool as that is, that's not the time
  • 19:40 - 19:41
    to think about it.
  • 19:41 - 19:46
    So I mean, a thousand and one approaches is,
  • 19:46 - 19:48
    there's a whole bunch of gems out there. Most
  • 19:48 - 19:50
    of them will simplify the things I mentioned,
    or
  • 19:50 - 19:53
    give you better, shorter DSLs for doing the
    approaches
  • 19:53 - 19:57
    I mentioned. But none of them achieve all
    the
  • 19:57 - 19:59
    goals at once, of having MVC, REST, and all
  • 19:59 - 20:00
    of that.
  • 20:00 - 20:03
    I mean, to get back to that, there's REST,
  • 20:03 - 20:06
    MVC, OO, and then the non-functional requirements.
    So, let's
  • 20:06 - 20:10
    go to, jump into this. I think we have
  • 20:10 - 20:14
    about ten minutes left.
  • 20:14 - 20:18
    So the first thing that, so I, I'm like,
  • 20:18 - 20:20
    OK, let's try to solve this wizard problem
    from
  • 20:20 - 20:22
    scratch, like, as if I just, I'm just gonna,
  • 20:22 - 20:25
    like, get my tools out there. Like, the object-oriented
  • 20:25 - 20:31
    principles, the domain-driven design principles.
    Who, who here has
  • 20:31 - 20:34
    read the book Domain Driven Design? Or heard
    of
  • 20:34 - 20:36
    it, at least?
  • 20:36 - 20:38
    It's a book that I, my team did a
  • 20:38 - 20:41
    book club on, or a previous team, like six
  • 20:41 - 20:44
    years ago, did a book club on for the
  • 20:44 - 20:48
    sake of learning how to do object-oriented
    design on
  • 20:48 - 20:50
    real business problems. Cause a lot of the
    time
  • 20:50 - 20:52
    you learn object orientation, but it's hard
    to figure
  • 20:52 - 20:54
    out how to create the right objects for the
  • 20:54 - 20:56
    real, for the right person's problem. It's,
    that, that
  • 20:56 - 20:58
    book is a very good book on how to
  • 20:58 - 20:59
    tackle that.
  • 20:59 - 21:01
    So I, I started using those tools. Like, whatever
  • 21:01 - 21:02
    I learned from that book, whatever I learned
    from
  • 21:02 - 21:08
    object-oriented programming. Whatever I learned
    from, like REST. To
  • 21:08 - 21:11
    try to figure out what a wizard is.
  • 21:11 - 21:14
    Before I go ahead and talk more of what
  • 21:14 - 21:17
    a wizard is, what do you think a wizard,
  • 21:17 - 21:19
    the wizard's highest goal is?
  • 21:19 - 21:21
    Go ahead.
  • 21:21 - 21:25
    AUDIENCE: To serve views for the user.
  • 21:25 - 21:28
    A.M.: That's correct. So, you stumped me.
    Cause I
  • 21:28 - 21:30
    was gonna ask about the highest goal from
    the
  • 21:30 - 21:32
    developer's point of view, but you're right,
    we should
  • 21:32 - 21:34
    think about the user's perspective first.
  • 21:34 - 21:38
    Now, let's dig, let's dig a little. No, that's
  • 21:38 - 21:41
    good. Let's dig a level lower. So, OK, so
  • 21:41 - 21:44
    we know that. That's our guiding principle,
    is OK,
  • 21:44 - 21:45
    to serve to make things easier for the user.
  • 21:45 - 21:50
    But, next, what, why, why, OK, technically
    what, what
  • 21:50 - 21:51
    is a wizard doing?
  • 21:51 - 21:53
    OK, that's my next question. What is a wizard
  • 21:53 - 21:54
    really doing? Go ahead.
  • 21:54 - 21:57
    AUDIENCE: Collect the proper set of validated
    values.
  • 21:57 - 22:01
    A.M.: That's part of the work. What else?
  • 22:01 - 22:02
    AUDIENCE: Break down the form so they're just
    small
  • 22:02 - 22:02
    steps.
  • 22:02 - 22:04
    A.M.: OK. Break down the data. Yup. Like separate
  • 22:05 - 22:06
    it. What else?
  • 22:06 - 22:07
    AUDIENCE: I was gonna say something really
    similar to
  • 22:07 - 22:09
    that. Organize the data into, like, you know,
    making
  • 22:09 - 22:13
    it weighted or in comprehensible sections.
  • 22:14 - 22:16
    A.M.: OK. And what's the end goal of running
  • 22:16 - 22:19
    through the entire wizard?
  • 22:19 - 22:21
    AUDIENCE: Creating an object.
  • 22:21 - 22:25
    A.M.: Yup. Pretty much. So a wizard is nothing
  • 22:25 - 22:29
    but the good old builder design pattern. Anybody's
    heard
  • 22:29 - 22:31
    of it. I mean, I used to be a
  • 22:31 - 22:33
    hardcore Java geek and design patterns were
    big in-
  • 22:33 - 22:36
    [audio jump] seven days - in Ruby.
  • 22:36 - 22:39
    But it's still good to know about things like
  • 22:39 - 22:41
    that, cause that pattern flashed in my head
    right
  • 22:41 - 22:43
    away. I'm like, oh wow, a wizard is nothing
  • 22:43 - 22:45
    but a builder. Like, it, all it does is
  • 22:45 - 22:47
    like an assembly line of building a car, where
  • 22:47 - 22:50
    step one, you know, whatever, you put the
    chassis,
  • 22:50 - 22:53
    second, like, step two is you add more, I
  • 22:53 - 22:55
    don't know, you add the doors. Step three,
    you
  • 22:55 - 22:57
    add the windows. Four, five, and then all
    of
  • 22:57 - 23:02
    the sudden you've built a car. So that's really
  • 23:02 - 23:07
    what it is.
  • 23:07 - 23:11
    Second part of the philosophy that I was following
  • 23:11 - 23:14
    is, each step in a wizard is nothing but
  • 23:14 - 23:17
    a partial view of that main, full object you're
  • 23:17 - 23:19
    building. So, one, one step is about, say
    I'm
  • 23:19 - 23:21
    ordering a car and I want to customize that
  • 23:21 - 23:23
    car. Like, one step will show me the exterior
  • 23:23 - 23:26
    body and another will show me the interior
    to
  • 23:26 - 23:30
    customize the interior with, whatever, leather
    or mahogany front-panel,
  • 23:30 - 23:32
    whatever. And then, and then a third part
    lets
  • 23:32 - 23:33
    me customize the engine.
  • 23:33 - 23:36
    So it's just, so all what steps are, are
  • 23:36 - 23:39
    views. Like, instead of thinking about them
    as states
  • 23:39 - 23:41
    and in a state machine, this is a more
  • 23:41 - 23:43
    higher level way of thinking about it. It's
    less
  • 23:43 - 23:47
    technical and more, it's just, I'm viewing
    one part
  • 23:47 - 23:50
    of a model.
  • 23:50 - 23:55
    Third part is if you were to, so, with
  • 23:55 - 23:56
    that in mind, if you ever think about the
  • 23:56 - 24:00
    REST resources, it's very simple now. It's
    done. Like,
  • 24:00 - 24:02
    you have the main model, that's the main resource.
  • 24:02 - 24:05
    And then you have the model parts, nested
    model
  • 24:05 - 24:07
    part, under the main model. That's the second
    resource.
  • 24:07 - 24:10
    That's it. You have two RESTful resources.
    Very clean.
  • 24:10 - 24:13
    So every time you're walking through the steps
    of
  • 24:13 - 24:17
    a wizard, you're actually editing a model
    part. So,
  • 24:17 - 24:20
    and, so that makes it very, very clear what
  • 24:20 - 24:22
    the REST resource is.
  • 24:22 - 24:26
    Another thing in my philosophy about it was
    I
  • 24:26 - 24:28
    did not want to have conditional validations,
    cause they
  • 24:28 - 24:30
    make a model hard to maintain. It's harder
    to
  • 24:30 - 24:32
    read if statements. Like, if I can have those
  • 24:32 - 24:35
    without if statements, it would be better.
    Especially when
  • 24:35 - 24:37
    you come back to maintain that wizard six
    months
  • 24:37 - 24:40
    later and then a year later and, on, on
  • 24:40 - 24:42
    both projects I was on, they actually added
    steps
  • 24:42 - 24:44
    to the wizard. So they started with four steps
  • 24:44 - 24:46
    and then they grew to nine steps.
  • 24:46 - 24:51
    And the more I can separate that stuff, the,
  • 24:51 - 24:56
    the better. And then finally I just wanted
    to
  • 24:56 - 24:58
    maintain the views in separate view files
    as well.
  • 24:58 - 25:00
    I didn't want a single view file that would
  • 25:00 - 25:01
    do it the way I used to write code
  • 25:01 - 25:04
    in ASB where I'd have a crazy if-else statement
  • 25:04 - 25:06
    that says if step1 show this part of the
  • 25:06 - 25:10
    form, if step2, show me the project details,
    if
  • 25:10 - 25:13
    step3, show me a document content upload.
    I don't
  • 25:13 - 25:20
    want that. That's, yeah. That's ASP programming.
  • 25:21 - 25:28
    AUDIENCE: If they change the order of the
    steps,
  • 25:28 - 25:31
    you want the steps [indecipherable] step three
    became step
  • 25:32 - 25:33
    four.
  • 25:34 - 25:35
    A.M.: Yeah. It'll work.
  • 25:37 - 25:41
    OK. So, so really I mean, high level is
  • 25:41 - 25:43
    just, I have the main model. That's the main
  • 25:43 - 25:45
    resource. And then the, on the, nested under
    it,
  • 25:45 - 25:49
    there's the four different, so, what I end
    up
  • 25:49 - 25:52
    doing is creating four different presenters.
    One per step.
  • 25:52 - 25:55
    Which manages the validations for that step
    separately, as
  • 25:55 - 25:57
    well as any stepping logic related to what
    happens
  • 25:57 - 25:59
    when you land on that page. What are the
  • 25:59 - 26:01
    defaults for that form? Should we initialize
    the phone
  • 26:01 - 26:04
    number with zero, zero, zero, zeros, or should
    we,
  • 26:04 - 26:06
    like, should, should we prefil the name from
    the
  • 26:06 - 26:09
    logged in user account? These kinds of concerns
    now
  • 26:09 - 26:10
    are uploaded cleanly to the model.
  • 26:10 - 26:13
    So we're adhering to MVC. You handle all the
  • 26:13 - 26:16
    wizard intelligence and business logic in
    the models now.
  • 26:16 - 26:18
    You're not, or presenters. I mean, a presenter
    is
  • 26:18 - 26:20
    just another form of a model that focuses
    on
  • 26:20 - 26:23
    presented a vi- a part of a model. So,
  • 26:23 - 26:26
    really, I'm, I'm using it in a loose sense.
  • 26:26 - 26:27
    There's many ways to do presenters. I don't
    care
  • 26:27 - 26:28
    which way.
  • 26:28 - 26:31
    I do have a prescribed way here, but, the
  • 26:31 - 26:34
    point of first to grasp is that you're operating
  • 26:34 - 26:36
    on a part of the model. You're not operating
  • 26:36 - 26:38
    on the full model. And you're doing the logic
  • 26:38 - 26:41
    in the, in a model, not in a controller.
  • 26:41 - 26:43
    And then the, the controller is the, yeah.
    So
  • 26:43 - 26:45
    there's two of them. There's the one that
    manages
  • 26:45 - 26:47
    the main model creation. So the first step
    of
  • 26:47 - 26:49
    a wizard, when you create it, you create it
  • 26:49 - 26:52
    with a main model controller. So if I have
  • 26:52 - 26:55
    projects controller, I have a create action.
    And then
  • 26:55 - 26:58
    that triggers the wizard. It'll, it'll create
    it and
  • 26:58 - 27:00
    then redirects me to the first step.
  • 27:00 - 27:02
    So when it redirects me to the first step
  • 27:02 - 27:04
    it takes me to the edit page of model
  • 27:04 - 27:08
    part, the nested model part, with id_step1,
    for example.
  • 27:08 - 27:11
    Or id basic info. So you use the step
  • 27:11 - 27:13
    names as the ids of that RESTful resource.
    Which
  • 27:13 - 27:20
    is perfect REST. Like, that's, that, that
    goes with,
  • 27:20 - 27:22
    that gives you an example of why, when people
  • 27:22 - 27:25
    talk about REST outside of Rails, they tell
    you
  • 27:25 - 27:29
    REST does not relate to having a database
    table.
  • 27:29 - 27:31
    You can, so this, this, this is an example
  • 27:31 - 27:35
    where the RESTful resource is a step that
    is
  • 27:35 - 27:38
    a view of the model, but it's not a
  • 27:38 - 27:40
    resource. It's not a database table. It's
    not a
  • 27:40 - 27:43
    separate database table. It's just a virtual
    resource.
  • 27:43 - 27:44
    I need to wrap it up and then I'll
  • 27:44 - 27:47
    take, I'll take questions. So in a nutshell,
    you
  • 27:47 - 27:50
    have the model resource, nested model. So
    you end
  • 27:50 - 27:54
    up with URLs like that, which is very restful,
  • 27:54 - 27:59
    again, cause, like, so you have projects,
    with the
  • 27:59 - 28:00
    id. We were using friendly id on the projects,
  • 28:00 - 28:03
    so the project says, yeah, so project1, then
    project_parts,
  • 28:03 - 28:06
    and then the name of the step. And there'll
  • 28:06 - 28:08
    be four steps for, you know, every time you
  • 28:08 - 28:09
    run through that wizard. So there'll be four
    ids,
  • 28:09 - 28:12
    only. It's a finite set. You don't have to
  • 28:12 - 28:14
    store it in the database.
  • 28:14 - 28:20
    So yeah, step names. There's id, contains
    validations, yeah.
  • 28:20 - 28:23
    I already talked about all of that. So let's
  • 28:23 - 28:24
    skip.
  • 28:24 - 28:26
    So the routes is very, are very simple. You
  • 28:26 - 28:30
    just have a resources projects. It's actually
    only create
  • 28:30 - 28:32
    and show. I left the show out. There should
  • 28:32 - 28:35
    be a show as well. Show is the landing
  • 28:35 - 28:37
    page of the project when you finish the wizard.
  • 28:37 - 28:39
    And then the project parts, which is edit
    and
  • 28:39 - 28:42
    update. And it's that simple.
  • 28:42 - 28:44
    So, so here's the project model. It's got
    the
  • 28:44 - 28:49
    basic definition of that model. And associations
    and so
  • 28:49 - 28:51
    on and so forth. However, what I end up
  • 28:51 - 28:54
    doing is creating a presenter per wizard step,
    so,
  • 28:54 - 28:57
    and I nest them under a directory that matches
  • 28:57 - 28:59
    the model name, so, project, for example.
    And that's
  • 28:59 - 29:01
    one way of doing it. There's many ways of
  • 29:01 - 29:03
    doing it, but.
  • 29:03 - 29:06
    In this case, only step one and two had
  • 29:06 - 29:09
    customizations over that model. Step three
    did not have
  • 29:09 - 29:11
    validations of its own, so I didn't even have
  • 29:11 - 29:15
    to create a file for it. And step four
  • 29:15 - 29:16
    actually didn't have anything either so I
    didn't have
  • 29:16 - 29:17
    to create a file for it.
  • 29:17 - 29:20
    But yeah. Step one, you can't see the details,
  • 29:20 - 29:23
    but the point is that this is, these are
  • 29:23 - 29:27
    validations for step one, only. So that's
    the first,
  • 29:27 - 29:29
    and then the first step, as well as some
  • 29:29 - 29:33
    business logic related to it, like initializing
    default, like
  • 29:33 - 29:38
    initialize from user, which initializes from
    the signed in
  • 29:38 - 29:38
    user.
  • 29:38 - 29:43
    And then there's the project detail model,
    which has
  • 29:43 - 29:46
    a few validations, only. Only three, cause
    it only
  • 29:46 - 29:49
    has three fields on it. So that one is
  • 29:49 - 29:54
    also, like, cleanly separated. Nice, easy
    to maintain. So
  • 29:54 - 29:57
    you go back to maintain the code and it's
  • 29:57 - 29:59
    like, it's like, it's squeaky clean. You know
    it's
  • 29:59 - 30:02
    like so easy. It's like the way programming
    should
  • 30:02 - 30:06
    be.
  • 30:06 - 30:08
    So the project's controller, the create action,
    all it
  • 30:08 - 30:11
    does is it creates the project and then redirects
  • 30:11 - 30:14
    to the edit page of the first step, which
  • 30:14 - 30:19
    is basic info. And then the project parts
    controller
  • 30:19 - 30:21
    has the edit and the update and all it
  • 30:21 - 30:24
    does is it steps through the wizard. Now,
    what
  • 30:24 - 30:25
    I ended up doing here is the way I
  • 30:25 - 30:29
    reasoned about it is that the project in MVC,
  • 30:29 - 30:32
    or, sorry project controller in MVC is, or
    project
  • 30:32 - 30:36
    parts controller, is actually, although it's
    a controller, it's
  • 30:36 - 30:38
    a model of sorts. It's a model focused on
  • 30:38 - 30:39
    control flow.
  • 30:39 - 30:42
    And stepping through a wizard is control flow.
    So
  • 30:42 - 30:44
    then I made the controller responsible for
    it. So
  • 30:44 - 30:48
    the, so here, at the top, it, it defines
  • 30:48 - 30:49
    the order of the steps, and then based on
  • 30:49 - 30:51
    that it walks through them. So in a way
  • 30:51 - 30:53
    the controller is the state machine, except
    I didn't
  • 30:53 - 30:57
    need a state machine cause I'm not maintaining
    state.
  • 30:57 - 30:59
    I do it with, I don't need to maintain
  • 30:59 - 31:00
    state. Every time we finish a step we can
  • 31:00 - 31:02
    redirect to the next step. And I can pass
  • 31:02 - 31:05
    the id of the next step RESTfully and redirect
  • 31:05 - 31:07
    to the next resource.
  • 31:07 - 31:08
    So I, I don't need to maintain what step
  • 31:08 - 31:11
    I'm at, on. It's always on each page. Like,
  • 31:11 - 31:13
    on each page, I can know, if I'm on
  • 31:13 - 31:15
    step two, I know that if I hit submit
  • 31:15 - 31:17
    it'll take me to step three next. I don't
  • 31:17 - 31:19
    have to, like I just know that from this
  • 31:19 - 31:24
    array that we define over here, which orders
    the
  • 31:24 - 31:26
    steps in the wizard.
  • 31:26 - 31:29
    So, yeah, we're almost done. But yeah. I mean,
  • 31:29 - 31:33
    it's got stepping logic. There is, there's
    a gem
  • 31:33 - 31:35
    out there called wicked that helps to implement
    this
  • 31:35 - 31:39
    sort of logic in a controller. I, I'm starting
  • 31:39 - 31:43
    a gem called ultralightwizard that will do
    similar stuff,
  • 31:43 - 31:48
    except it'll add the, the concept of presenters
    to
  • 31:48 - 31:51
    it as well. But until then you could use
  • 31:51 - 31:53
    wicked for the controller part.
  • 31:53 - 31:57
    The views, you'll just have a different wizard
    part
  • 31:57 - 32:00
    view, or sorry, step view. And one thing I
  • 32:00 - 32:03
    didn't know is that this edit action, it actually,
  • 32:03 - 32:04
    when it renders the view, you don't render
    and
  • 32:04 - 32:07
    edit dot html dot erb, you polymorphically
    just render
  • 32:07 - 32:10
    the step name. And then it ends up picking
  • 32:10 - 32:11
    a view matching that step name.
  • 32:11 - 32:13
    So if I render basic_info, it renders basic_info
    dot
  • 32:13 - 32:16
    html dot erb, which contains the edit form
    for
  • 32:16 - 32:20
    that step. If I render the, the detail step,
  • 32:20 - 32:24
    then it renders detail dot html dot erb. So
  • 32:24 - 32:25
    that's why I have these. So that way we
  • 32:25 - 32:27
    have the views separated as well. So we achieve
  • 32:27 - 32:31
    that goal.
  • 32:31 - 32:33
    The form that you put can be the same
  • 32:33 - 32:35
    on all views actually. Because you have, you're
    editing
  • 32:35 - 32:37
    the same model. You're just editing different
    parts of
  • 32:37 - 32:40
    that model, but it's, it's the same model
    on
  • 32:40 - 32:44
    all pages. So the root model is project, but
  • 32:44 - 32:48
    on one page I'm editing nested document content,
    upload
  • 32:48 - 32:51
    the documents. On another page I'm, I'm, I'm
    editing
  • 32:51 - 32:52
    just the first name and last name, and so
  • 32:52 - 32:53
    on and so forth.
  • 32:53 - 32:54
    So you could actually wrap this whole thing
    up
  • 32:54 - 32:59
    in the helper, call it project_form_for. That's
    super short.
  • 32:59 - 33:01
    Just use that. I know on one of my
  • 33:01 - 33:04
    projects, another senior developer on the
    team did that,
  • 33:04 - 33:08
    like he did that as a refactoring step.
  • 33:08 - 33:11
    So, I mean, this is an example, but a
  • 33:11 - 33:15
    view, a very straightforward view form, like,
    straight Rails.
  • 33:15 - 33:20
    Nothing special about it.
  • 33:20 - 33:22
    So that concludes the talk. So, I mean, I
  • 33:22 - 33:23
    talked about why use a wizard, provide a wizard
  • 33:23 - 33:29
    example, implementation goals, other implementations
    out there, and finally
  • 33:29 - 33:31
    talked about what's my recommended approach
    for sticking with
  • 33:31 - 33:35
    REST, MVC, OO, and, you know, all the things
  • 33:35 - 33:37
    that would help ensure that your code is not
  • 33:37 - 33:40
    maintainable only today but also a year from
    now,
  • 33:40 - 33:42
    and also by other developers that will join
    the
  • 33:42 - 33:46
    team with minimal training efforts, hopefully.
  • 33:46 - 33:48
    This is the project that I launched and is
  • 33:48 - 33:50
    empty right now, but I would like to, but
  • 33:50 - 33:52
    I mean, you can star it and monitor it
  • 33:52 - 33:53
    and hopefully I have something out soon. Maybe
    I'll
  • 33:53 - 33:56
    do it at RailsConf. Somebody want to pair
    with
  • 33:56 - 33:58
    me on this, you're welcome to. So yeah, my
  • 33:58 - 34:01
    name is Andy Maleh. I'm the VP of Engineering
  • 34:01 - 34:06
    at a remote only, or 100% remote option consulting
  • 34:06 - 34:10
    company called BigAstronaut. These are my
    folks over here.
  • 34:10 - 34:11
    That's Lance, CTO.
  • 34:11 - 34:16
    Oh, oh yeah, Chief Fun Officer as well.
  • 34:16 - 34:18
    AUDIENCE: We've got t-shirts and stickers
    and we're hiring.
  • 34:18 - 34:21
    A.M.: Sweet. Yeah. Thank you everybody.
Title:
RailsConf 2014 - Ultra Light and Maintainable Rails Wizards by Andy Maleh
Description:

more » « less
Duration:
34:47

English subtitles

Revisions