Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Practical dependency injection for Ruby

Practical dependency injection for Ruby

Stephen Best

August 18, 2016
Tweet

More Decks by Stephen Best

Other Decks in Programming

Transcript

  1. PRACTICAL
    DEPENDENCY
    INJECTION
    (for Ruby)
    @thebestie

    View Slide

  2. WHAT'S COVERED
    What is dependency injection?
    What problems can it solve?
    How do we write code that takes advantage of it?

    View Slide

  3. WHAT IS IT?
    Something, something, inversion of control technique ...

    View Slide

  4. WHAT PROBLEMS CAN IT SOLVE?
    It can be a real help to code that is
    Complex to test
    Slow to test
    Hard to change
    Difficult to re-use, even for *very* similar tasks

    View Slide

  5. The root cause is
    COUPLING

    View Slide

  6. Today we'll explore how our applications o en end up
    coupled to global variables
    In Ruby constants are global and can be overwritten
    c
    l
    a
    s
    s F
    o
    o
    # .
    .
    .
    e
    n
    d
    F
    o
    o = C
    l
    a
    s
    s
    .
    n
    e
    w d
    o
    # .
    .
    .
    e
    n
    d
    $
    f
    o
    o
    _
    c
    l
    a
    s
    s = C
    l
    a
    s
    s
    .
    n
    e
    w d
    o
    # .
    .
    .
    e
    n
    d

    View Slide

  7. The sky isn't falling.
    We still build stuff that works.
    We still build stuff that makes money.
    How on earth do we manage?

    View Slide

  8. MONKEY PATCHING
    Let's see how we can decouple from globals and reduce our
    reliance on monkey patching.

    View Slide

  9. FRUIT OF THE MONTH CLUB
    Subscribers receive a box of fruit
    Every month
    The fruit changes
    We're looking to raise $1.000.000 at a $10.000.000
    valuation
    We're also hiring senior Rails engineers with 3+ months
    experience

    View Slide

  10. Feature 1
    G
    i
    v
    e
    n I a
    m a f
    r
    u
    i
    t e
    n
    t
    h
    u
    s
    i
    a
    s
    t
    A
    n
    d I l
    i
    v
    e f
    o
    r t
    o
    d
    a
    y b
    e
    c
    a
    u
    s
    e t
    o
    m
    o
    r
    r
    o
    w m
    a
    y n
    e
    v
    e
    r c
    o
    m
    e
    W
    h
    e
    n I v
    i
    s
    i
    t t
    h
    e i
    n s
    e
    a
    s
    o
    n n
    o
    w p
    a
    g
    e
    T
    h
    e
    n I s
    e
    e a l
    i
    s
    t o
    f f
    r
    u
    i
    t
    s t
    h
    a
    t a
    r
    e a
    v
    a
    i
    l
    a
    b
    l
    e t
    o
    d
    a
    y

    View Slide

  11. c
    l
    a
    s
    s F
    r
    u
    i
    t
    s
    C
    o
    n
    t
    r
    o
    l
    l
    e
    r < A
    p
    p
    l
    i
    c
    a
    t
    i
    o
    n
    C
    o
    n
    t
    r
    o
    l
    l
    e
    r
    d
    e
    f i
    n
    _
    s
    e
    a
    s
    o
    n
    r
    e
    n
    d
    e
    r
    (
    j
    s
    o
    n
    : F
    r
    u
    i
    t
    .
    i
    n
    _
    s
    e
    a
    s
    o
    n
    )
    e
    n
    d
    e
    n
    d

    View Slide

  12. c
    l
    a
    s
    s F
    r
    u
    i
    t < A
    c
    t
    i
    v
    e
    R
    e
    c
    o
    r
    d
    :
    :
    B
    a
    s
    e
    d
    e
    f s
    e
    l
    f
    .
    i
    n
    _
    s
    e
    a
    s
    o
    n
    a
    l
    l
    .
    w
    h
    e
    r
    e
    (
    "
    s
    e
    a
    s
    o
    n
    _
    s
    t
    a
    r
    t >
    = ?
    "
    , D
    a
    t
    e
    .
    t
    o
    d
    a
    y
    )
    .
    w
    h
    e
    r
    e
    (
    "
    s
    e
    a
    s
    o
    n
    _
    e
    n
    d <
    = ?
    "
    , D
    a
    t
    e
    .
    t
    o
    d
    a
    y
    )
    e
    n
    d
    e
    n
    d

    View Slide

  13. R
    S
    p
    e
    c
    .
    d
    e
    s
    c
    r
    i
    b
    e F
    r
    u
    i
    t d
    o
    d
    e
    s
    c
    r
    i
    b
    e "
    .
    i
    n
    _
    s
    e
    a
    s
    o
    n
    " d
    o
    b
    e
    f
    o
    r
    e { s
    e
    e
    d
    _
    f
    r
    u
    i
    t
    s }
    c
    o
    n
    t
    e
    x
    t "
    i
    n s
    u
    m
    m
    e
    r
    " d
    o
    b
    e
    f
    o
    r
    e { T
    i
    m
    e
    c
    o
    p
    .
    t
    r
    a
    v
    e
    l
    (
    D
    a
    t
    e
    .
    n
    e
    w
    (
    2
    0
    1
    6
    , 7
    , 1
    )
    ) }
    i
    t "
    r
    e
    t
    u
    r
    n
    s s
    u
    m
    m
    e
    r f
    r
    u
    i
    t
    s
    " d
    o
    e
    x
    p
    e
    c
    t
    (
    F
    r
    u
    i
    t
    .
    i
    n
    _
    s
    e
    a
    s
    o
    n
    )
    .
    t
    o i
    n
    c
    l
    u
    d
    e
    (
    *
    s
    u
    m
    m
    e
    r
    _
    f
    r
    u
    i
    t
    s
    )
    e
    n
    d
    i
    t "
    e
    x
    c
    l
    u
    d
    e
    s w
    i
    n
    t
    e
    r f
    r
    u
    i
    t
    s
    " d
    o
    e
    x
    p
    e
    c
    t
    (
    F
    r
    u
    i
    t
    .
    i
    n
    _
    s
    e
    a
    s
    o
    n
    )
    .
    n
    o
    t
    _
    t
    o i
    n
    c
    l
    u
    d
    e
    (
    *
    w
    i
    n
    t
    e
    r
    _
    f
    r
    u
    i
    t
    s
    )
    e
    n
    d
    e
    n
    d
    c
    o
    n
    t
    e
    x
    t "
    i
    n w
    i
    n
    t
    e
    r
    " d
    o
    # .
    .
    .
    e
    n
    d
    e
    n
    d
    e
    n
    d

    View Slide

  14. SO WHAT'S WRONG WITH THAT?
    Classic example of an unnecessarily hardcoded
    dependency (system time)
    They worked around it with monkey patching
    The design is rigid and limits functionality, what about
    next month?

    View Slide

  15. LISTEN TO YOUR TESTS
    R
    S
    p
    e
    c
    .
    d
    e
    s
    c
    r
    i
    b
    e F
    r
    u
    i
    t d
    o
    d
    e
    s
    c
    r
    i
    b
    e "
    .
    i
    n
    _
    s
    e
    a
    s
    o
    n
    " d
    o
    b
    e
    f
    o
    r
    e { s
    e
    e
    d
    _
    f
    r
    u
    i
    t
    s }
    c
    o
    n
    t
    e
    x
    t "
    i
    n s
    u
    m
    m
    e
    r
    " d
    o
    l
    e
    t
    (
    :
    d
    a
    t
    e
    ) { D
    a
    t
    e
    .
    n
    e
    w
    (
    2
    0
    1
    6
    , 7
    , 1
    ) }
    i
    t "
    r
    e
    t
    u
    r
    n
    s s
    u
    m
    m
    e
    r f
    r
    u
    i
    t
    s
    " d
    o
    e
    x
    p
    e
    c
    t
    (
    F
    r
    u
    i
    t
    .
    i
    n
    _
    s
    e
    a
    s
    o
    n
    (
    d
    a
    t
    e
    )
    )
    .
    t
    o i
    n
    c
    l
    u
    d
    e
    (
    *
    s
    u
    m
    m
    e
    r
    _
    f
    r
    u
    i
    t
    s
    )
    e
    n
    d
    i
    t "
    e
    x
    c
    l
    u
    d
    e
    s w
    i
    n
    t
    e
    r f
    r
    u
    i
    t
    s
    " d
    o
    e
    x
    p
    e
    c
    t
    (
    F
    r
    u
    i
    t
    .
    i
    n
    _
    s
    e
    a
    s
    o
    n
    (
    d
    a
    t
    e
    )
    )
    .
    n
    o
    t
    _
    t
    o i
    n
    c
    l
    u
    d
    e
    (
    *
    w
    i
    n
    t
    e
    r
    _
    f
    r
    u
    i
    t
    s
    )
    e
    n
    d
    e
    n
    d
    c
    o
    n
    t
    e
    x
    t "
    i
    n w
    i
    n
    t
    e
    r
    " d
    o
    # .
    .
    .
    e
    n
    d
    e
    n
    d
    e
    n
    d

    View Slide

  16. c
    l
    a
    s
    s F
    r
    u
    i
    t < A
    c
    t
    i
    v
    e
    R
    e
    c
    o
    r
    d
    :
    :
    B
    a
    s
    e
    d
    e
    f s
    e
    l
    f
    .
    i
    n
    _
    s
    e
    a
    s
    o
    n
    (
    d
    a
    t
    e
    )
    a
    l
    l
    .
    w
    h
    e
    r
    e
    (
    "
    s
    e
    a
    s
    o
    n
    _
    s
    t
    a
    r
    t >
    = ?
    "
    , d
    a
    t
    e
    )
    .
    w
    h
    e
    r
    e
    (
    "
    s
    e
    a
    s
    o
    n
    _
    e
    n
    d <
    = ?
    "
    , d
    a
    t
    e
    )
    e
    n
    d
    e
    n
    d

    View Slide

  17. c
    l
    a
    s
    s F
    r
    u
    i
    t
    s
    C
    o
    n
    t
    r
    o
    l
    l
    e
    r < A
    p
    p
    l
    i
    c
    a
    t
    i
    o
    n
    C
    o
    n
    t
    r
    o
    l
    l
    e
    r
    d
    e
    f i
    n
    _
    s
    e
    a
    s
    o
    n
    r
    e
    n
    d
    e
    r
    (
    j
    s
    o
    n
    : F
    r
    u
    i
    t
    .
    i
    n
    _
    s
    e
    a
    s
    o
    n
    (
    d
    a
    t
    e
    )
    )
    e
    n
    d
    p
    r
    i
    v
    a
    t
    e
    d
    e
    f d
    a
    t
    e
    p
    a
    r
    a
    m
    s
    .
    f
    e
    t
    c
    h
    (
    "
    d
    a
    t
    e
    "
    , D
    a
    t
    e
    .
    t
    o
    d
    a
    y
    )
    e
    n
    d
    e
    n
    d

    View Slide

  18. Feature 2
    G
    i
    v
    e
    n I a
    m a f
    r
    u
    i
    t e
    n
    t
    h
    u
    s
    i
    a
    s
    t
    A
    n
    d I l
    i
    k
    e t
    o d
    r
    e
    a
    m a
    b
    o
    u
    t t
    h
    e f
    u
    t
    u
    r
    e
    W
    h
    e
    n I v
    i
    s
    i
    t t
    h
    e i
    n s
    e
    a
    s
    o
    n p
    a
    g
    e f
    o
    r J
    a
    n
    u
    a
    r
    y
    T
    h
    e
    n I s
    e
    e t
    h
    e f
    r
    u
    i
    t
    s t
    h
    a
    t w
    i
    l
    l a
    v
    a
    i
    l
    a
    b
    l
    e i
    n J
    a
    n
    u
    a
    r
    y

    View Slide

  19. Remember what we did?
    We just got this feature for free.

    View Slide

  20. Feature 3
    G
    i
    v
    e
    n I a
    m a f
    r
    u
    i
    t e
    n
    t
    h
    u
    s
    i
    a
    s
    t
    A
    n
    d I h
    a
    v
    e a g
    o
    o
    g
    l
    e a
    c
    c
    o
    u
    n
    t
    W
    h
    e
    n I s
    i
    g
    n i
    n
    T
    h
    e
    n I c
    a
    n a
    u
    t
    h
    e
    n
    t
    i
    c
    a
    t
    e w
    i
    t
    h G
    o
    o
    g
    l
    e r
    a
    t
    h
    e
    r t
    h
    a
    n u
    s
    e a p
    a
    s
    s
    w
    o
    r
    d

    View Slide

  21. We may expect our controller to look something like this
    c
    l
    a
    s
    s U
    s
    e
    r
    S
    e
    s
    s
    i
    o
    n
    s
    C
    o
    n
    t
    r
    o
    l
    l
    e
    r
    d
    e
    f c
    r
    e
    a
    t
    e
    s
    i
    g
    n
    _
    i
    n
    (
    u
    s
    e
    r
    )
    r
    e
    d
    i
    r
    e
    c
    t
    _
    t
    o
    (
    h
    o
    m
    e
    _
    p
    a
    t
    h
    )
    e
    n
    d
    p
    r
    i
    v
    a
    t
    e
    d
    e
    f u
    s
    e
    r
    # .
    .
    .
    e
    n
    d
    e
    n
    d
    How exactly do we get the authenticated user?

    View Slide

  22. Google gives us their email address (in a roundabout way)
    c
    l
    a
    s
    s U
    s
    e
    r
    S
    e
    s
    s
    i
    o
    n
    s
    C
    o
    n
    t
    r
    o
    l
    l
    e
    r
    # .
    .
    .
    d
    e
    f u
    s
    e
    r
    U
    s
    e
    r
    .
    f
    i
    n
    d
    _
    b
    y
    _
    e
    m
    a
    i
    l
    (
    e
    m
    a
    i
    l
    )
    e
    n
    d
    d
    e
    f e
    m
    a
    i
    l
    u
    s
    e
    r
    _
    i
    n
    f
    o
    .
    f
    e
    t
    c
    h
    (
    "
    e
    m
    a
    i
    l
    "
    )
    e
    n
    d
    d
    e
    f u
    s
    e
    r
    _
    i
    n
    f
    o
    # .
    .
    .
    e
    n
    d
    e
    n
    d

    View Slide

  23. We exchange an authentication code for the user's details
    c
    l
    a
    s
    s U
    s
    e
    r
    S
    e
    s
    s
    i
    o
    n
    s
    C
    o
    n
    t
    r
    o
    l
    l
    e
    r
    # .
    .
    .
    d
    e
    f u
    s
    e
    r
    _
    i
    n
    f
    o
    a
    u
    t
    h
    _
    c
    l
    i
    e
    n
    t
    .
    c
    o
    d
    e = p
    a
    r
    a
    m
    s
    .
    f
    e
    t
    c
    h
    (
    "
    c
    o
    d
    e
    "
    )
    a
    u
    t
    h
    _
    c
    l
    i
    e
    n
    t
    .
    f
    e
    t
    c
    h
    _
    a
    c
    c
    e
    s
    s
    _
    t
    o
    k
    e
    n
    !
    a
    u
    t
    h
    _
    c
    l
    i
    e
    n
    t
    .
    d
    e
    c
    o
    d
    e
    _
    j
    w
    t
    e
    n
    d
    d
    e
    f a
    u
    t
    h
    _
    c
    l
    i
    e
    n
    t
    @
    a
    u
    t
    h
    _
    c
    l
    i
    e
    n
    t |
    |
    = S
    i
    g
    n
    e
    t
    :
    :
    O
    A
    u
    t
    h
    2
    :
    :
    C
    l
    i
    e
    n
    t
    .
    n
    e
    w
    (
    s
    c
    o
    p
    e
    : "
    e
    m
    a
    i
    l p
    r
    o
    f
    i
    l
    e
    "
    ,
    c
    l
    i
    e
    n
    t
    _
    i
    d
    : R
    a
    i
    l
    s
    .
    a
    p
    p
    l
    i
    c
    a
    t
    i
    o
    n
    .
    s
    e
    c
    r
    e
    t
    s
    .
    g
    o
    o
    g
    l
    e
    _
    c
    l
    i
    e
    n
    t
    _
    i
    d
    ,
    c
    l
    i
    e
    n
    t
    _
    s
    e
    c
    r
    e
    t
    : R
    a
    i
    l
    s
    .
    a
    p
    p
    l
    i
    c
    a
    t
    i
    o
    n
    .
    s
    e
    c
    r
    e
    t
    s
    .
    g
    o
    o
    g
    l
    e
    _
    c
    l
    i
    e
    n
    t
    _
    s
    e
    c
    r
    e
    t
    ,
    a
    u
    t
    h
    o
    r
    i
    z
    a
    t
    i
    o
    n
    _
    u
    r
    i
    : "
    h
    t
    t
    p
    s
    :
    /
    /
    a
    c
    c
    o
    u
    n
    t
    s
    .
    g
    o
    o
    g
    l
    e
    .
    c
    o
    m
    /
    o
    /
    o
    a
    u
    t
    h
    2
    /
    a
    u
    t
    h
    "
    t
    o
    k
    e
    n
    _
    c
    r
    e
    d
    e
    n
    t
    i
    a
    l
    _
    u
    r
    i
    : "
    h
    t
    t
    p
    s
    :
    /
    /
    w
    w
    w
    .
    g
    o
    o
    g
    l
    e
    a
    p
    i
    s
    .
    c
    o
    m
    /
    o
    a
    u
    t
    h
    2
    /
    v
    3
    /
    t
    o
    k
    e
    n
    "
    r
    e
    d
    i
    r
    e
    c
    t
    _
    u
    r
    i
    : "
    h
    t
    t
    p
    :
    /
    /
    e
    x
    a
    m
    p
    l
    e
    .
    c
    o
    m
    /
    u
    s
    e
    r
    _
    s
    e
    s
    s
    i
    o
    n
    s
    /
    c
    r
    e
    a
    t
    e
    "
    )
    e
    n
    d
    e
    n
    d

    View Slide

  24. The response from Google contains a JSON web token
    /
    / i
    d
    _
    t
    o
    k
    e
    n h
    e
    r
    e i
    s t
    h
    e J
    S
    O
    N w
    e
    b t
    o
    k
    e
    n c
    o
    n
    t
    a
    i
    n
    i
    n
    g t
    h
    e u
    s
    e
    r
    '
    s d
    e
    t
    a
    i
    l
    s
    {
    "
    a
    c
    c
    e
    s
    s
    _
    t
    o
    k
    e
    n
    "
    : "
    y
    a
    2
    9
    .
    C
    i
    8
    O
    A
    1
    n
    0
    b
    x
    I
    5
    h
    l
    K
    D
    U
    U
    C
    z
    2
    f
    J
    J
    Z
    m
    9
    H
    w
    c
    u
    K
    r
    q
    c
    k
    Y
    5
    S
    E
    C
    X
    T
    O
    5
    H
    x
    V
    i
    0
    6
    "
    t
    o
    k
    e
    n
    _
    t
    y
    p
    e
    "
    : "
    B
    e
    a
    r
    e
    r
    "
    ,
    "
    e
    x
    p
    i
    r
    e
    s
    _
    i
    n
    "
    : 3
    6
    0
    0
    ,
    "
    r
    e
    f
    r
    e
    s
    h
    _
    t
    o
    k
    e
    n
    "
    : "
    1
    /
    T
    -
    O
    z
    b
    2
    5
    L
    3
    4
    Z
    C
    r
    M
    S
    k
    r
    1
    v
    M
    1
    q
    H
    M
    O
    2
    T
    -
    0
    B
    t
    m
    M
    e
    X
    o
    x
    q
    5
    K
    E
    M
    0
    "
    ,
    "
    i
    d
    _
    t
    o
    k
    e
    n
    "
    : "
    e
    y
    J
    h
    b
    G
    c
    i
    O
    i
    J
    S
    U
    z
    I
    1
    N
    i
    I
    s
    I
    m
    t
    p
    Z
    C
    I
    6
    I
    m
    V
    k
    Z
    D
    F
    j
    Z
    m
    F
    j
    N
    T
    E
    y
    O
    D
    c
    z
    Z
    j
    U
    z
    Y
    j
    A
    2
    M
    G
    Q
    y
    }

    View Slide

  25. We can test this with our usual monkey patching appproach
    # T
    e
    s
    t h
    e
    l
    p
    e
    r
    d
    e
    f s
    t
    u
    b
    _
    a
    c
    c
    e
    s
    s
    _
    t
    o
    k
    e
    n
    (
    a
    u
    t
    h
    c
    o
    d
    e
    )
    s
    t
    u
    b
    _
    r
    e
    q
    u
    e
    s
    t
    (
    :
    p
    o
    s
    t
    , "
    h
    t
    t
    p
    s
    :
    /
    /
    w
    w
    w
    .
    g
    o
    o
    g
    l
    e
    a
    p
    i
    s
    .
    c
    o
    m
    /
    o
    a
    u
    t
    h
    2
    /
    v
    3
    /
    t
    o
    k
    e
    n
    "
    )
    .
    w
    i
    t
    h
    (
    b
    o
    d
    y
    : {
    "
    c
    o
    d
    e
    " =
    > a
    u
    t
    h
    c
    o
    d
    e
    ,
    "
    g
    r
    a
    n
    t
    _
    t
    y
    p
    e
    " =
    > "
    a
    u
    t
    h
    o
    r
    i
    z
    a
    t
    i
    o
    n
    _
    c
    o
    d
    e
    "
    ,
    "
    r
    e
    d
    i
    r
    e
    c
    t
    _
    u
    r
    i
    " =
    > "
    h
    t
    t
    p
    :
    /
    /
    e
    x
    a
    m
    p
    l
    e
    .
    c
    o
    m
    /
    u
    s
    e
    r
    _
    s
    e
    s
    s
    i
    o
    n
    s
    /
    c
    r
    e
    a
    t
    e
    "
    "
    c
    l
    i
    e
    n
    t
    _
    i
    d
    " =
    > R
    a
    i
    l
    s
    .
    a
    p
    p
    l
    i
    c
    a
    t
    i
    o
    n
    .
    s
    e
    c
    r
    e
    t
    s
    .
    g
    o
    o
    g
    l
    e
    _
    c
    l
    i
    e
    n
    t
    _
    i
    d
    ,
    "
    c
    l
    i
    e
    n
    t
    _
    s
    e
    c
    r
    e
    t
    " =
    > R
    a
    i
    l
    s
    .
    a
    p
    p
    l
    i
    c
    a
    t
    i
    o
    n
    .
    s
    e
    c
    r
    e
    t
    s
    .
    g
    o
    o
    g
    l
    e
    _
    c
    l
    i
    e
    n
    t
    _
    s
    e
    c
    r
    e
    t
    }
    )
    .
    t
    o
    _
    r
    e
    t
    u
    r
    n
    (
    b
    o
    d
    y
    : J
    S
    O
    N
    .
    d
    u
    m
    p
    (
    g
    o
    o
    g
    l
    e
    _
    a
    c
    c
    e
    s
    s
    _
    t
    o
    k
    e
    n
    _
    f
    i
    x
    t
    u
    r
    e
    )
    ,
    h
    e
    a
    d
    e
    r
    s
    : { "
    C
    o
    n
    t
    e
    n
    t
    -
    T
    y
    p
    e
    " =
    > "
    a
    p
    p
    l
    i
    c
    a
    t
    i
    o
    n
    /
    j
    s
    o
    n
    " }
    )
    e
    n
    d

    View Slide

  26. Seems ok until the next day...
    S
    i
    g
    n
    a
    t
    u
    r
    e h
    a
    s e
    x
    p
    i
    r
    e
    d (
    J
    W
    T
    :
    :
    E
    x
    p
    i
    r
    e
    d
    S
    i
    g
    n
    a
    t
    u
    r
    e
    )
    .
    /
    a
    p
    p
    /
    c
    o
    n
    t
    r
    o
    l
    l
    e
    r
    s
    /
    u
    s
    e
    r
    _
    s
    e
    s
    s
    i
    o
    n
    s
    _
    c
    o
    n
    t
    r
    o
    l
    l
    e
    r
    .
    r
    b
    :
    3
    5
    :
    i
    n `
    u
    s
    e
    r
    _
    i
    n
    f
    o
    '
    .
    /
    a
    p
    p
    /
    c
    o
    n
    t
    r
    o
    l
    l
    e
    r
    s
    /
    u
    s
    e
    r
    _
    s
    e
    s
    s
    i
    o
    n
    s
    _
    c
    o
    n
    t
    r
    o
    l
    l
    e
    r
    .
    r
    b
    :
    5
    :
    i
    n `
    c
    r
    e
    a
    t
    e
    '
    .
    /
    f
    e
    a
    t
    u
    r
    e
    s
    /
    s
    u
    p
    p
    o
    r
    t
    /
    f
    e
    a
    t
    u
    r
    e
    _
    a
    p
    p
    l
    i
    c
    a
    t
    i
    o
    n
    _
    a
    c
    t
    i
    o
    n
    s
    .
    r
    b
    :
    3
    :
    i
    n `
    s
    i
    m
    u
    l
    a
    t
    e
    _
    g
    o
    o
    g
    l
    e
    _
    a
    u
    t
    .
    /
    f
    e
    a
    t
    u
    r
    e
    s
    /
    s
    t
    e
    p
    _
    d
    e
    f
    i
    n
    i
    t
    i
    o
    n
    s
    /
    a
    u
    t
    h
    e
    n
    t
    i
    c
    a
    t
    i
    o
    n
    _
    s
    t
    e
    p
    s
    .
    r
    b
    :
    1
    6
    :
    i
    n `
    /
    ^
    I s
    i
    g
    n i
    n
    $
    /
    '
    f
    e
    a
    t
    u
    r
    e
    s
    /
    a
    u
    t
    h
    e
    n
    t
    i
    c
    a
    t
    i
    o
    n
    .
    f
    e
    a
    t
    u
    r
    e
    :
    5
    :
    i
    n `
    W
    h
    e
    n I s
    i
    g
    n i
    n
    '

    View Slide

  27. It turns out it was more complex than we thought.
    JWTs present a few inconveniences:
    Time sensitive (configurable)
    Opaquely encoded
    Optionally encryped
    HMAC

    View Slide

  28. We have two options now for our integration tests
    Monkeypatch time for every test
    Remove the time constraint (opening us to replay
    attacks)
    Furthermore, to sign in a different user we need another
    opauque awkward fixture!

    View Slide

  29. We need to be able to mock out complex components to
    reduce complexity.
    We need to create 'slots' that we can fit swappable
    components into.
    We should not rely on the presence of globals.

    View Slide

  30. Step 1: Wrap the authication client in an adapter
    c
    l
    a
    s
    s S
    i
    g
    n
    e
    t
    A
    d
    a
    p
    t
    e
    r
    d
    e
    f i
    n
    i
    t
    i
    a
    l
    i
    z
    e
    (
    c
    l
    i
    e
    n
    t
    _
    i
    d
    :
    , c
    l
    i
    e
    n
    t
    _
    s
    e
    c
    r
    e
    t
    :
    , r
    e
    d
    i
    r
    e
    c
    t
    _
    u
    r
    i
    :
    )
    @
    c
    l
    i
    e
    n
    t
    _
    i
    d = c
    l
    i
    e
    n
    t
    _
    i
    d
    @
    c
    l
    i
    e
    n
    t
    _
    s
    e
    c
    r
    e
    t = c
    l
    i
    e
    n
    t
    _
    s
    e
    c
    r
    e
    t
    @
    r
    e
    d
    i
    r
    e
    c
    t
    _
    u
    r
    i = r
    e
    d
    i
    r
    e
    c
    t
    _
    u
    r
    i
    e
    n
    d
    d
    e
    f a
    u
    t
    h
    e
    n
    t
    i
    c
    a
    t
    e
    (
    c
    o
    d
    e
    )
    c
    l
    i
    e
    n
    t
    .
    c
    o
    d
    e = c
    o
    d
    e
    c
    l
    i
    e
    n
    t
    .
    f
    e
    t
    c
    h
    _
    a
    c
    c
    e
    s
    s
    _
    t
    o
    k
    e
    n
    !
    c
    l
    i
    e
    n
    t
    .
    d
    e
    c
    o
    d
    e
    d
    _
    i
    d
    _
    t
    o
    k
    e
    n
    e
    n
    d
    p
    r
    i
    v
    a
    t
    e
    d
    e
    f c
    l
    i
    e
    n
    t
    @
    c
    l
    i
    e
    n
    t |
    |
    = S
    i
    g
    n
    e
    t
    :
    :
    O
    A
    u
    t
    h
    2
    :
    :
    C
    l
    i
    e
    n
    t
    .
    n
    e
    w
    (
    # .
    .
    .
    )
    e
    n
    d
    # .
    .
    .
    e
    n
    d

    View Slide

  31. We need somewhere to inject it. A service object!
    c
    l
    a
    s
    s A
    u
    t
    h
    e
    n
    t
    i
    c
    a
    t
    e
    U
    s
    e
    r
    d
    e
    f i
    n
    i
    t
    i
    a
    l
    i
    z
    e
    (
    a
    u
    t
    h
    _
    c
    l
    i
    e
    n
    t
    , u
    s
    e
    r
    s
    , c
    o
    d
    e
    )
    @
    a
    u
    t
    h
    _
    c
    l
    i
    e
    n
    t = a
    u
    t
    h
    _
    c
    l
    i
    e
    n
    t
    @
    u
    s
    e
    r
    s = u
    s
    e
    r
    s
    @
    c
    o
    d
    e = c
    o
    d
    e
    e
    n
    d
    d
    e
    f c
    a
    l
    l
    u
    s
    e
    r
    s
    .
    f
    i
    n
    d
    _
    b
    y
    _
    e
    m
    a
    i
    l
    (
    e
    m
    a
    i
    l
    )
    e
    n
    d
    p
    r
    i
    v
    a
    t
    e
    d
    e
    f e
    m
    a
    i
    l
    u
    s
    e
    r
    _
    i
    n
    f
    o
    .
    f
    e
    t
    c
    h
    (
    "
    e
    m
    a
    i
    l
    "
    )
    e
    n
    d
    d
    e
    f u
    s
    e
    r
    _
    i
    n
    f
    o
    a
    u
    t
    h
    _
    c
    l
    i
    e
    n
    t
    .
    a
    u
    t
    h
    e
    n
    t
    i
    c
    a
    t
    e
    (
    c
    o
    d
    e
    )
    e
    n
    d
    e
    n
    d

    View Slide

  32. This is an intermediate step
    auth_client still has to come from somewhere
    The controller still has lots of knowledge
    c
    l
    a
    s
    s U
    s
    e
    r
    S
    e
    s
    s
    i
    o
    n
    s
    C
    o
    n
    t
    r
    o
    l
    l
    e
    r
    d
    e
    f c
    r
    e
    a
    t
    e
    s
    i
    g
    n
    _
    i
    n
    (
    u
    s
    e
    r
    )
    r
    e
    d
    i
    r
    e
    c
    t
    _
    t
    o
    (
    h
    o
    m
    e
    _
    p
    a
    t
    h
    )
    e
    n
    d
    p
    r
    i
    v
    a
    t
    e
    d
    e
    f u
    s
    e
    r
    A
    u
    t
    h
    e
    n
    t
    i
    c
    a
    t
    e
    U
    s
    e
    r
    .
    n
    e
    w
    (
    a
    u
    t
    h
    _
    c
    l
    i
    e
    n
    t
    , U
    s
    e
    r
    , p
    a
    r
    a
    m
    s
    .
    f
    e
    t
    c
    h
    (
    "
    c
    o
    d
    e
    "
    )
    )
    e
    n
    d
    e
    n
    d

    View Slide

  33. Add another layer to handle dependencies
    c
    l
    a
    s
    s U
    s
    e
    r
    S
    e
    s
    s
    i
    o
    n
    s
    C
    o
    n
    t
    r
    o
    l
    l
    e
    r
    d
    e
    f c
    r
    e
    a
    t
    e
    s
    i
    g
    n
    _
    i
    n
    (
    u
    s
    e
    r
    )
    r
    e
    d
    i
    r
    e
    c
    t
    _
    t
    o
    (
    h
    o
    m
    e
    _
    p
    a
    t
    h
    )
    e
    n
    d
    p
    r
    i
    v
    a
    t
    e
    d
    e
    f u
    s
    e
    r
    a
    p
    p
    .
    a
    u
    t
    h
    e
    n
    t
    i
    c
    a
    t
    e
    _
    u
    s
    e
    r
    (
    p
    a
    r
    a
    m
    s
    .
    f
    e
    t
    c
    h
    (
    "
    c
    o
    d
    e
    "
    )
    )
    e
    n
    d
    e
    n
    d

    View Slide

  34. An application is an object that offers services
    c
    l
    a
    s
    s F
    r
    u
    i
    t
    O
    f
    T
    h
    e
    M
    o
    n
    t
    h
    A
    p
    p
    d
    e
    f i
    n
    i
    t
    i
    a
    l
    i
    z
    e
    (
    a
    u
    t
    h
    _
    c
    l
    i
    e
    n
    t
    : .
    .
    .
    )
    # I
    n
    j
    e
    c
    t a
    l
    l e
    x
    t
    e
    r
    n
    a
    l d
    e
    p
    e
    n
    d
    e
    n
    c
    i
    e
    s h
    e
    r
    e .
    .
    .
    e
    n
    d
    d
    e
    f a
    u
    t
    h
    e
    n
    t
    i
    c
    a
    t
    e
    _
    u
    s
    e
    r
    (
    c
    o
    d
    e
    )
    A
    u
    t
    h
    e
    n
    t
    i
    c
    a
    t
    e
    U
    s
    e
    r
    .
    n
    e
    w
    (
    a
    u
    t
    h
    _
    c
    l
    i
    e
    n
    t
    , U
    s
    e
    r
    , c
    o
    d
    e
    )
    .
    c
    a
    l
    l
    e
    n
    d
    e
    n
    d

    View Slide

  35. Create a differently configured app instance for each env
    No need for env checks - a pernicious source of ifs
    # c
    o
    n
    f
    i
    g
    /
    e
    n
    v
    i
    r
    o
    n
    m
    e
    n
    t
    s
    /
    t
    e
    s
    t
    .
    r
    b
    A
    P
    P = F
    r
    u
    i
    t
    O
    f
    T
    h
    e
    M
    o
    n
    t
    h
    A
    p
    p
    .
    n
    e
    w
    (
    a
    u
    t
    h
    _
    c
    l
    i
    e
    n
    t
    : M
    O
    C
    K
    _
    A
    U
    T
    H
    _
    C
    L
    I
    E
    N
    T
    )
    c
    l
    a
    s
    s A
    p
    p
    l
    i
    c
    a
    t
    i
    o
    n
    C
    o
    n
    t
    r
    o
    l
    l
    e
    r
    p
    r
    i
    v
    a
    t
    e
    d
    e
    f a
    p
    p
    A
    P
    P
    e
    n
    d
    e
    n
    d

    View Slide

  36. Finally we create a mock authentication client.
    c
    l
    a
    s
    s M
    o
    c
    k
    G
    o
    o
    g
    l
    e
    A
    u
    t
    h
    e
    n
    t
    i
    c
    a
    t
    i
    o
    n
    d
    e
    f i
    n
    i
    t
    i
    a
    l
    i
    z
    e
    (
    u
    s
    e
    r
    _
    i
    n
    f
    o
    )
    @
    u
    s
    e
    r
    _
    i
    n
    f
    o = u
    s
    e
    r
    _
    i
    n
    f
    o
    e
    n
    d
    d
    e
    f a
    u
    t
    h
    e
    n
    t
    i
    c
    a
    t
    e
    (
    _
    c
    o
    d
    e
    )
    @
    u
    s
    e
    r
    _
    i
    n
    f
    o
    e
    n
    d
    e
    n
    d
    M
    O
    C
    K
    _
    A
    U
    T
    H
    _
    C
    L
    I
    E
    N
    T = M
    o
    c
    k
    G
    o
    o
    g
    l
    e
    A
    u
    t
    h
    e
    n
    t
    i
    c
    a
    t
    i
    o
    n
    .
    n
    e
    w
    (
    "
    e
    m
    a
    i
    l
    " =
    > "
    b
    e
    s
    t
    i
    e
    @
    g
    m
    a
    i
    l
    .
    c
    o

    View Slide

  37. Now we have control over the implementation of our
    authentication mechanism.
    Feature tests that are not concerned with authentication can
    skip the process vastly reducing setup overhead.

    View Slide

  38. DI has helped us
    Isolate complex components
    Reduce coupling
    Reduce if statements
    Improve tests
    Features for cheap through re-use

    View Slide

  39. WHO WAS THAT GUY?
    STEPHEN BEST
    Freelance consultant
    @thebestie
    theaudaciouscodeexperiment.com
    github.com/bestie

    View Slide