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

Dependency Injection からモックライブラリまで

daimatz
September 11, 2014

Dependency Injection からモックライブラリまで

daimatz

September 11, 2014
Tweet

More Decks by daimatz

Other Decks in Programming

Transcript

  1. Dependency Injection
    から
    モックライブラリまで
    GolangTestNight (Gunosy.go#10)
    daimatz
    2014-09-11
    1 / 31

    View full-size slide

  2. 自己紹介
    ID: daimatz
    Scala
    でアドテクとかやってます
    あと Haskell
    とか Ruby
    とか好きでした
    Go
    は別にガリガリ使っているわけではない
    2 / 31

    View full-size slide

  3. Go
    の気に入らないところ
    構文
    型推論不要派。
    変数の同時代入のとき型注釈をつけたい
    v
    a
    r n i
    n
    t
    , e
    r
    r e
    r
    r
    o
    r = b
    u
    f
    .
    R
    e
    a
    d
    (
    b
    y
    t
    e
    s
    )
    みたいに書きたい
    変数と型は :
    で区切るでしょ普通
    m
    a
    p
    [
    i
    n
    t
    ]
    s
    t
    r
    i
    n
    g
    の特別感
    型システム
    ジェネリクスほしいっす
    ライブラリのバー
    ジョニングの話
    g
    o g
    e
    t
    するバー
    ジョンを指定できない

    後方互換性をなくすような変更するな」
    は理想論…
    それ以外は大体気に入っている
    3 / 31

    View full-size slide

  4. 今日の話
    Dependency Injection
    アプリケー
    ション初期化と DI
    コンテナ
    インター
    フェー
    ス実装によるモックとモックライブラリ
    4 / 31

    View full-size slide

  5. 今日の話
    Dependency Injection
    アプリケー
    ション初期化と DI
    コンテナ
    インター
    フェー
    ス実装によるモックとモックライブラリ
    5 / 31

    View full-size slide

  6. Dependency Injection
    DI,
    依存性の注入
    依存しているオブジェクトを直接クラスの中に持っておくのではなく、
    コンス
    トラクタなどで受け取れるようにする
    インター
    フェー
    スに対してプログラミングを心がけられる
    モックしてテストしやすくなる
    6 / 31

    View full-size slide

  7. 例: Twitter
    ボットアプリケー
    ション
    f
    u
    n
    c T
    w
    e
    e
    t
    (
    t
    e
    x
    t s
    t
    r
    i
    n
    g
    , i
    n
    R
    e
    p
    l
    y
    T
    o i
    n
    t
    ) (
    i
    n
    t
    , e
    r
    r
    o
    r
    ) { .
    .
    . }
    f
    u
    n
    c G
    e
    t
    T
    i
    m
    e
    l
    i
    n
    e
    (
    c
    o
    u
    n
    t i
    n
    t
    ) (
    [
    ]
    S
    t
    a
    t
    u
    s
    , e
    r
    r
    o
    r
    ) { .
    .
    . }
    t
    y
    p
    e T
    w
    i
    t
    t
    e
    r
    B
    o
    t s
    t
    r
    u
    c
    t { .
    .
    . }
    f
    u
    n
    c (
    t *
    T
    w
    i
    t
    t
    e
    r
    B
    o
    t
    ) E
    v
    e
    n
    t
    L
    o
    o
    p
    (
    ) e
    r
    r
    o
    r {
    f
    o
    r {
    s
    t
    a
    t
    u
    s
    I
    d
    s
    , e
    r
    r :
    = t
    .
    A
    c
    t
    i
    o
    n
    (
    1
    0
    )
    .
    .
    .
    t
    i
    m
    e
    .
    S
    l
    e
    e
    p
    (
    6
    0 * t
    i
    m
    e
    .
    S
    e
    c
    o
    n
    d
    )
    }
    }
    f
    u
    n
    c (
    t
    * T
    w
    i
    t
    t
    e
    r
    B
    o
    t
    ) A
    c
    t
    i
    o
    n
    (
    c
    o
    u
    n
    t i
    n
    t
    ) (
    [
    ]
    i
    n
    t
    , e
    r
    r
    o
    r
    ) {
    t
    l
    , e
    r
    r :
    = G
    e
    t
    T
    i
    m
    e
    l
    i
    n
    e
    (
    c
    o
    u
    n
    t
    )
    r
    e
    t :
    = m
    a
    k
    e
    (
    [
    ]
    i
    n
    t
    , 0
    )
    f
    o
    r i :
    = r
    a
    n
    g
    e t
    l {
    s
    t
    a
    t
    u
    s :
    = t
    l
    [
    i
    ]
    s
    t
    a
    t
    u
    s
    I
    d
    , e
    r
    r :
    = T
    w
    e
    e
    t
    (
    "
    @
    "
    +
    s
    t
    a
    t
    u
    s
    .
    U
    s
    e
    r
    I
    d
    +
    " G
    o
    o
    d m
    o
    r
    n
    i
    n
    g
    !
    "
    , s
    t
    a
    t
    u
    s
    .
    I
    d
    )
    r
    e
    t = a
    p
    p
    e
    n
    d
    (
    r
    e
    t
    , s
    t
    a
    t
    u
    s
    I
    d
    )
    }
    r
    e
    t
    u
    r
    n r
    e
    t
    , n
    i
    l
    }
    f
    u
    n
    c m
    a
    i
    n
    (
    ) {
    b
    o
    t :
    = &
    T
    w
    i
    t
    t
    e
    r
    B
    o
    t
    { .
    .
    . }
    b
    o
    t
    .
    E
    v
    e
    n
    t
    L
    o
    o
    p
    (
    )
    }
    7 / 31

    View full-size slide

  8. 問題点
    T
    w
    i
    t
    t
    e
    r
    B
    o
    t
    が直接 T
    w
    e
    e
    t
    , G
    e
    t
    T
    i
    m
    e
    l
    i
    n
    e
    に依存している
    モックして一時的に振る舞いを変えることができない
    T
    w
    i
    t
    t
    e
    r
    B
    o
    t
    を単体テストしようとしても必然的に T
    w
    e
    e
    t
    および G
    e
    t
    T
    i
    m
    e
    l
    i
    n
    e

    動作を前提としてしまう
    粒度の大きいテストしかできない
    粒度の大きいテストしかできないと、
    問題が起きたときに問題箇所の特定が難
    しくなる
    世の中綺麗なことばかりではない。
    副作用をモックしないと粒度の細かいテス
    トはできない
    8 / 31

    View full-size slide

  9. 動的言語での例
    Ruby
    での例
    d
    e
    s
    c
    r
    i
    b
    e '
    a
    c
    t
    i
    o
    n
    ' d
    o
    i
    t '
    r
    e
    t
    u
    r
    n [
    ] i
    f t
    i
    m
    e
    l
    i
    n
    e i
    s e
    m
    p
    t
    y
    ' d
    o
    # s
    t
    u
    b
    e
    x
    p
    e
    c
    t
    (
    b
    o
    t
    .
    s
    e
    r
    v
    i
    c
    e
    )
    .
    t
    o r
    e
    c
    e
    i
    v
    e
    (
    :
    g
    e
    t
    _
    t
    i
    m
    e
    l
    i
    n
    e
    )
    .
    w
    i
    t
    h
    (
    1
    0
    )
    .
    a
    n
    d
    _
    r
    e
    t
    u
    r
    n
    (
    [
    ]
    )
    e
    x
    p
    e
    c
    t
    (
    b
    o
    t
    .
    a
    c
    t
    i
    o
    n
    (
    1
    0
    )
    )
    .
    t
    o e
    q [
    ]
    e
    n
    d
    e
    n
    d
    後から簡単に挙動を変えられるが、
    静的言語ではそうはいかない
    9 / 31

    View full-size slide

  10. 改善案:
    メソッドを引数に渡してみる
    f
    u
    n
    c (
    t *
    T
    w
    i
    t
    t
    e
    r
    B
    o
    t
    ) E
    v
    e
    n
    t
    L
    o
    o
    p
    (
    t
    w
    e
    e
    t f
    u
    n
    c
    (
    t
    e
    x
    t s
    t
    r
    i
    n
    g
    , i
    n
    R
    e
    p
    l
    y
    T
    o i
    n
    t
    ) (
    i
    n
    t
    , e
    r
    r
    o
    r
    )
    ,
    g
    e
    t
    T
    i
    m
    e
    l
    i
    n
    e f
    u
    n
    c
    (
    c
    o
    u
    n
    t i
    n
    t
    ) (
    [
    ]
    S
    t
    a
    t
    u
    s
    , e
    r
    r
    o
    r
    )
    ,
    ) e
    r
    r
    o
    r {
    .
    .
    .
    }
    f
    u
    n
    c m
    a
    i
    n
    (
    ) {
    b
    o
    t :
    = &
    T
    w
    i
    t
    t
    e
    r
    B
    o
    t
    { .
    .
    . }
    b
    o
    t
    .
    E
    v
    e
    n
    t
    L
    o
    o
    p
    (
    T
    w
    e
    e
    t
    , G
    e
    t
    T
    i
    m
    e
    l
    i
    n
    e
    )
    }
    こうすれば、
    テスト時に t
    w
    e
    e
    t
    と g
    e
    t
    T
    i
    m
    e
    l
    i
    n
    e
    の挙動を変えることができる
    モックして単体テストできる
    究極的には、
    依存しているメソッドを全部引数に渡せばいい
    でも面倒
    この例だと E
    v
    e
    n
    t
    L
    o
    o
    p
    が1
    回しか呼ばれてないからいいけど…
    なんで呼び出し側がモックしたいメソッドを気にかけてやんなきゃいけな
    いの?
    10 / 31

    View full-size slide

  11. 改善案:
    メソッドをまとめたオブジェ
    クトを渡してみる
    t
    y
    p
    e T
    w
    i
    t
    t
    e
    r
    S
    e
    r
    v
    i
    c
    e s
    t
    r
    u
    c
    t
    {
    }
    f
    u
    n
    c (
    t *
    T
    w
    i
    t
    t
    e
    r
    S
    e
    r
    v
    i
    c
    e
    ) T
    w
    e
    e
    t
    (
    t
    e
    x
    t s
    t
    r
    i
    n
    g
    , i
    n
    R
    e
    p
    l
    y
    T
    o i
    n
    t
    ) (
    i
    n
    t
    , e
    r
    r
    o
    r
    ) { .
    .
    . }
    f
    u
    n
    c (
    t *
    T
    w
    i
    t
    t
    e
    r
    S
    e
    r
    v
    i
    c
    e
    ) G
    e
    t
    T
    i
    m
    e
    l
    i
    n
    e
    (
    c
    o
    u
    n
    t i
    n
    t
    ) (
    [
    ]
    S
    t
    a
    t
    u
    s
    , e
    r
    r
    o
    r
    ) { .
    .
    . }
    f
    u
    n
    c (
    t *
    T
    w
    i
    t
    t
    e
    r
    B
    o
    t
    ) E
    v
    e
    n
    t
    L
    o
    o
    p
    (
    s
    e
    r
    v
    i
    c
    e *
    T
    w
    i
    t
    t
    e
    r
    S
    e
    r
    v
    i
    c
    e
    ) e
    r
    r
    o
    r {
    .
    .
    .
    }
    f
    u
    n
    c m
    a
    i
    n
    (
    ) {
    b
    o
    t :
    = &
    T
    w
    i
    t
    t
    e
    r
    B
    o
    t
    { .
    .
    . }
    s
    e
    r
    v
    i
    c
    e :
    = &
    T
    w
    i
    t
    t
    e
    r
    S
    e
    r
    v
    i
    c
    e
    { .
    .
    . }
    b
    o
    t
    .
    E
    v
    e
    n
    t
    L
    o
    o
    p
    (
    s
    e
    r
    v
    i
    c
    e
    )
    }
    呼び出しは少し楽になったけど、
    モックができない
    T
    w
    i
    t
    t
    e
    r
    S
    e
    r
    v
    i
    c
    e
    という実態に依存してしまっている
    差し替えのためには実態でなく型シグネチャ (
    インター
    フェー
    ス)
    を指定しなけ
    ればいけない
    11 / 31

    View full-size slide

  12. 改善案:
    依存しているインター
    フェー
    スを渡してみる
    t
    y
    p
    e T
    w
    i
    t
    t
    e
    r
    S
    e
    r
    v
    i
    c
    e i
    n
    t
    e
    r
    f
    a
    c
    e {
    T
    w
    e
    e
    t
    (
    t
    e
    x
    t s
    t
    r
    i
    n
    g
    , i
    n
    R
    e
    p
    l
    y
    T
    o i
    n
    t
    ) (
    i
    n
    t
    , e
    r
    r
    o
    r
    )
    G
    e
    t
    T
    i
    m
    e
    l
    i
    n
    e
    (
    c
    o
    u
    n
    t i
    n
    t
    ) (
    [
    ]
    S
    t
    a
    t
    u
    s
    , e
    r
    r
    o
    r
    )
    }
    t
    y
    p
    e T
    w
    i
    t
    t
    e
    r
    S
    e
    r
    v
    i
    c
    e
    I
    m
    p
    l s
    t
    r
    u
    c
    t {
    }
    f
    u
    n
    c (
    t *
    T
    w
    i
    t
    t
    e
    r
    S
    e
    r
    v
    i
    c
    e
    I
    m
    p
    l
    ) T
    w
    e
    e
    t
    (
    t
    e
    x
    t s
    t
    r
    i
    n
    g
    , i
    n
    R
    e
    p
    l
    y
    T
    o i
    n
    t
    ) (
    i
    n
    t
    , e
    r
    r
    o
    r
    ) { .
    .
    . }
    f
    u
    n
    c (
    t *
    T
    w
    i
    t
    t
    e
    r
    S
    e
    r
    v
    i
    c
    e
    I
    m
    p
    l
    ) G
    e
    t
    T
    i
    m
    e
    l
    i
    n
    e
    (
    c
    o
    u
    n
    t i
    n
    t
    ) (
    [
    ]
    S
    t
    a
    t
    u
    s
    , e
    r
    r
    o
    r
    ) { .
    .
    . }
    f
    u
    n
    c (
    t *
    T
    w
    i
    t
    t
    e
    r
    B
    o
    t
    ) E
    v
    e
    n
    t
    L
    o
    o
    p
    (
    s
    e
    r
    v
    i
    c
    e T
    w
    i
    t
    t
    e
    r
    S
    e
    r
    v
    i
    c
    e
    ) e
    r
    r
    o
    r {
    .
    .
    .
    }
    f
    u
    n
    c m
    a
    i
    n
    (
    ) {
    b
    o
    t :
    = &
    T
    w
    i
    t
    t
    e
    r
    B
    o
    t
    { .
    .
    . }
    s
    e
    r
    v
    i
    c
    e :
    = &
    T
    w
    i
    t
    t
    e
    r
    S
    e
    r
    v
    i
    c
    e
    I
    m
    p
    l
    { .
    .
    . }
    b
    o
    t
    .
    E
    v
    e
    n
    t
    L
    o
    o
    p
    (
    s
    e
    r
    v
    i
    c
    e
    )
    }
    差し替えがきくようになった
    「T
    w
    i
    t
    t
    e
    r
    S
    e
    r
    v
    i
    c
    e
    のメソッドを実装しているものをちょうだい」
    と言って
    いるだけで、
    具体的な実装は指定していない
    ついでにこれオブジェクトの初期化時に渡して保持しとけばいいよね
    12 / 31

    View full-size slide

  13. 改善案:
    初期化時に渡してみる
    t
    y
    p
    e T
    w
    i
    t
    t
    e
    r
    S
    e
    r
    v
    i
    c
    e i
    n
    t
    e
    r
    f
    a
    c
    e {
    T
    w
    e
    e
    t
    (
    t
    e
    x
    t s
    t
    r
    i
    n
    g
    , i
    n
    R
    e
    p
    l
    y
    T
    o i
    n
    t
    ) (
    i
    n
    t
    , e
    r
    r
    o
    r
    )
    G
    e
    t
    T
    i
    m
    e
    l
    i
    n
    e
    (
    c
    o
    u
    n
    t i
    n
    t
    ) (
    [
    ]
    S
    t
    a
    t
    u
    s
    , e
    r
    r
    o
    r
    )
    }
    t
    y
    p
    e T
    w
    i
    t
    t
    e
    r
    S
    e
    r
    v
    i
    c
    e
    I
    m
    p
    l s
    t
    r
    u
    c
    t
    {
    }
    f
    u
    n
    c (
    t *
    T
    w
    i
    t
    t
    e
    r
    S
    e
    r
    v
    i
    c
    e
    I
    m
    p
    l
    ) T
    w
    e
    e
    t
    (
    t
    e
    x
    t s
    t
    r
    i
    n
    g
    , i
    n
    R
    e
    p
    l
    y
    T
    o i
    n
    t
    ) (
    i
    n
    t
    , e
    r
    r
    o
    r
    ) { .
    .
    . }
    f
    u
    n
    c (
    t *
    T
    w
    i
    t
    t
    e
    r
    S
    e
    r
    v
    i
    c
    e
    I
    m
    p
    l
    ) G
    e
    t
    T
    i
    m
    e
    l
    i
    n
    e
    (
    c
    o
    u
    n
    t i
    n
    t
    ) (
    [
    ]
    S
    t
    a
    t
    u
    s
    , e
    r
    r
    o
    r
    ) { .
    .
    . }
    t
    y
    p
    e T
    w
    i
    t
    t
    e
    r
    B
    o
    t s
    t
    r
    u
    c
    t {
    T
    w
    i
    t
    t
    e
    r
    S
    e
    r
    v
    i
    c
    e T
    w
    i
    t
    t
    e
    r
    S
    e
    r
    v
    i
    c
    e
    ,
    .
    .
    .
    }
    f
    u
    n
    c (
    t *
    T
    w
    i
    t
    t
    e
    r
    B
    o
    t
    ) E
    v
    e
    n
    t
    L
    o
    o
    p
    (
    ) e
    r
    r
    o
    r {
    .
    .
    .
    }
    f
    u
    n
    c m
    a
    i
    n
    (
    ) {
    s
    e
    r
    v
    i
    c
    e :
    = &
    T
    w
    i
    t
    t
    e
    r
    S
    e
    r
    v
    i
    c
    e
    I
    m
    p
    l
    { .
    .
    . }
    b
    o
    t :
    = &
    T
    w
    i
    t
    t
    e
    r
    B
    o
    t
    {
    s
    e
    r
    v
    i
    c
    e
    , .
    .
    . }
    b
    o
    t
    .
    E
    v
    e
    n
    t
    L
    o
    o
    p
    (
    )
    }
    依存オブジェクトの差し替えはきくし、
    呼び出しも簡単
    このように、
    依存しているオブジェクトを具体的に保持せず、
    初期化時に注入
    する手法を Dependency Injection (DI)
    という
    13 / 31

    View full-size slide

  14. 改善案:
    徹底的にやる
    本当は T
    w
    i
    t
    t
    e
    r
    B
    o
    t
    も別のオブジェクトに依存しているかもしれない。
    T
    w
    i
    t
    t
    e
    r
    B
    o
    t
    もインター
    フェー
    スと実装を分けておく
    t
    y
    p
    e T
    w
    i
    t
    t
    e
    r
    S
    e
    r
    v
    i
    c
    e i
    n
    t
    e
    r
    f
    a
    c
    e {
    T
    w
    e
    e
    t
    (
    t
    e
    x
    t s
    t
    r
    i
    n
    g
    , i
    n
    R
    e
    p
    l
    y
    T
    o i
    n
    t
    ) (
    i
    n
    t
    , e
    r
    r
    o
    r
    )
    G
    e
    t
    T
    i
    m
    e
    l
    i
    n
    e
    (
    c
    o
    u
    n
    t i
    n
    t
    ) (
    [
    ]
    S
    t
    a
    t
    u
    s
    , e
    r
    r
    o
    r
    )
    }
    t
    y
    p
    e T
    w
    i
    t
    t
    e
    r
    S
    e
    r
    v
    i
    c
    e
    I
    m
    p
    l s
    t
    r
    u
    c
    t
    {
    }
    f
    u
    n
    c (
    t *
    T
    w
    i
    t
    t
    e
    r
    S
    e
    r
    v
    i
    c
    e
    I
    m
    p
    l
    ) T
    w
    e
    e
    t
    (
    t
    e
    x
    t s
    t
    r
    i
    n
    g
    , i
    n
    R
    e
    p
    l
    y
    T
    o i
    n
    t
    ) (
    i
    n
    t
    , e
    r
    r
    o
    r
    ) { .
    .
    . }
    f
    u
    n
    c (
    t *
    T
    w
    i
    t
    t
    e
    r
    S
    e
    r
    v
    i
    c
    e
    I
    m
    p
    l
    ) G
    e
    t
    T
    i
    m
    e
    l
    i
    n
    e
    (
    c
    o
    u
    n
    t i
    n
    t
    ) (
    [
    ]
    S
    t
    a
    t
    u
    s
    , e
    r
    r
    o
    r
    ) { .
    .
    . }
    t
    y
    p
    e T
    w
    i
    t
    t
    e
    r
    B
    o
    t i
    n
    t
    e
    r
    f
    a
    c
    e {
    .
    .
    .
    }
    t
    y
    p
    e T
    w
    i
    t
    t
    e
    r
    B
    o
    t
    I
    m
    p
    l s
    t
    r
    u
    c
    t {
    T
    w
    i
    t
    t
    e
    r
    S
    e
    r
    v
    i
    c
    e T
    w
    i
    t
    t
    e
    r
    S
    e
    r
    v
    i
    c
    e
    ,
    .
    .
    .
    }
    f
    u
    n
    c (
    t *
    T
    w
    i
    t
    t
    e
    r
    B
    o
    t
    I
    m
    p
    l
    ) E
    v
    e
    n
    t
    L
    o
    o
    p
    (
    ) e
    r
    r
    o
    r {
    .
    .
    .
    }
    f
    u
    n
    c m
    a
    i
    n
    (
    ) {
    s
    e
    r
    v
    i
    c
    e :
    = &
    T
    w
    i
    t
    t
    e
    r
    S
    e
    r
    v
    i
    c
    e
    I
    m
    p
    l
    { .
    .
    . }
    b
    o
    t :
    = &
    T
    w
    i
    t
    t
    e
    r
    B
    o
    t
    I
    m
    p
    l
    {
    s
    e
    r
    v
    i
    c
    e
    , .
    .
    . }
    .
    .
    . /
    /
    他の T
    w
    i
    t
    t
    e
    r
    B
    o
    t
    を使うオブジェクトを生成
    b
    o
    t
    .
    E
    v
    e
    n
    t
    L
    o
    o
    p
    (
    )
    }
    14 / 31

    View full-size slide

  15. インター
    フェー
    スに対するプログラミ
    ング
    依存しているオブジェクトに対してメソッドを呼ぶのではなく、
    インター
    フェ

    スに対してメソッドを呼ぶべき
    インター
    フェー
    スに対してメソッドを呼べるような設計を心がける
    15 / 31

    View full-size slide

  16. 今日の話
    Dependency Injection
    アプリケー
    ション初期化と DI
    コンテナ
    インター
    フェー
    ス実装によるモックとモックライブラリ
    16 / 31

    View full-size slide

  17. アプリケー
    ション初期化問題
    各モジュー
    ルでインター
    フェー
    スに対するプログラミングはできたが、
    オブジ
    ェクトの実態はどこにあるのか?
    アプリケー
    ション起動時に実際にオブジェクトを生成し、
    順番に依存オブジェ
    クトを注入してやる必要がある
    アプリケー
    ションの初期化
    注入されるオブジェクト間の依存性は有向無閉路グラフ (Directed Acyclic
    Graph, DAG)
    として表される
    DAG
    といえばトポロジカルソー

    UNIX
    にはトポロジカルソー
    トするための t
    s
    o
    r
    t
    というコマンドがあ
    ります (
    これ書いてて知った!)
    17 / 31

    View full-size slide

  18. 依存グラフとトポロジカルソー

    $ c
    a
    t d
    a
    g
    .
    i
    n
    T
    w
    i
    t
    t
    e
    r
    S
    e
    r
    v
    i
    c
    e T
    w
    i
    t
    t
    e
    r
    B
    o
    t
    A
    p
    p
    l
    i
    c
    a
    t
    i
    o
    n
    L
    o
    g
    g
    e
    r T
    w
    i
    t
    t
    e
    r
    S
    e
    r
    v
    i
    c
    e
    T
    h
    r
    e
    a
    d
    P
    o
    o
    l T
    w
    i
    t
    t
    e
    r
    B
    o
    t
    U
    s
    e
    r
    S
    t
    r
    e
    a
    m
    S
    e
    r
    v
    i
    c
    e T
    w
    i
    t
    t
    e
    r
    S
    e
    r
    v
    i
    c
    e
    U
    s
    e
    r
    C
    o
    n
    f
    i
    g A
    p
    p
    l
    i
    c
    a
    t
    i
    o
    n
    L
    o
    g
    g
    e
    r
    T
    w
    i
    t
    t
    e
    r
    C
    r
    e
    d
    e
    n
    t
    i
    a
    l T
    w
    i
    t
    t
    e
    r
    S
    e
    r
    v
    i
    c
    e
    A
    p
    i
    P
    a
    r
    s
    e
    r T
    w
    i
    t
    t
    e
    r
    S
    e
    r
    v
    i
    c
    e
    $ t
    s
    o
    r
    t < d
    a
    g
    .
    i
    n
    A
    p
    i
    P
    a
    r
    s
    e
    r
    T
    h
    r
    e
    a
    d
    P
    o
    o
    l
    T
    w
    i
    t
    t
    e
    r
    C
    r
    e
    d
    e
    n
    t
    i
    a
    l
    U
    s
    e
    r
    C
    o
    n
    f
    i
    g
    U
    s
    e
    r
    S
    t
    r
    e
    a
    m
    S
    e
    r
    v
    i
    c
    e
    A
    p
    p
    l
    i
    c
    a
    t
    i
    o
    n
    L
    o
    g
    g
    e
    r
    T
    w
    i
    t
    t
    e
    r
    S
    e
    r
    v
    i
    c
    e
    T
    w
    i
    t
    t
    e
    r
    B
    o
    t
    18 / 31

    View full-size slide

  19. 初期化コー

    f
    u
    n
    c m
    a
    i
    n
    (
    ) {
    a
    p
    i
    P
    a
    r
    s
    e
    r :
    = &
    A
    p
    i
    P
    a
    r
    s
    e
    r
    I
    m
    p
    l
    { .
    .
    . }
    t
    h
    r
    e
    a
    d
    P
    o
    o
    l :
    = &
    T
    h
    r
    e
    a
    d
    P
    o
    o
    l
    I
    m
    p
    l
    { .
    .
    . }
    t
    w
    i
    t
    t
    e
    r
    C
    r
    e
    d
    e
    n
    t
    i
    a
    l :
    = &
    T
    w
    i
    t
    t
    e
    r
    C
    r
    e
    d
    e
    n
    t
    i
    a
    l
    I
    m
    p
    l
    { .
    .
    . }
    u
    s
    e
    r
    C
    o
    n
    f
    i
    g :
    = &
    U
    s
    e
    r
    C
    o
    n
    f
    i
    g
    I
    m
    p
    l
    { .
    .
    . }
    u
    s
    e
    r
    S
    t
    r
    e
    a
    m
    S
    e
    r
    v
    i
    c
    e :
    = &
    U
    s
    e
    r
    S
    t
    r
    e
    a
    m
    S
    e
    r
    v
    i
    c
    e
    I
    m
    p
    l
    { .
    .
    . }
    a
    p
    p
    l
    i
    c
    a
    t
    i
    o
    n
    L
    o
    g
    g
    e
    r :
    = &
    A
    p
    p
    l
    i
    c
    a
    t
    i
    o
    n
    L
    o
    g
    g
    e
    r
    I
    m
    p
    l
    {
    u
    s
    e
    r
    C
    o
    n
    f
    i
    g
    , .
    .
    . }
    t
    w
    i
    t
    t
    e
    r
    S
    e
    r
    v
    i
    c
    e :
    = &
    T
    w
    i
    t
    t
    e
    r
    S
    e
    r
    v
    i
    c
    e
    I
    m
    p
    l
    {
    t
    w
    i
    t
    t
    e
    r
    C
    r
    e
    d
    e
    n
    t
    i
    a
    l
    ,
    a
    p
    p
    l
    i
    c
    a
    t
    i
    o
    n
    L
    o
    g
    g
    e
    r
    ,
    u
    s
    e
    r
    S
    t
    r
    e
    a
    m
    S
    e
    r
    v
    i
    c
    e
    ,
    a
    p
    i
    P
    a
    r
    s
    e
    r
    ,
    .
    .
    .
    }
    t
    w
    i
    t
    t
    e
    r
    B
    o
    t :
    = &
    T
    w
    i
    t
    t
    e
    r
    B
    o
    t
    I
    m
    p
    l
    {
    u
    s
    e
    r
    C
    o
    n
    f
    i
    g
    ,
    t
    w
    i
    t
    t
    e
    r
    S
    e
    r
    v
    i
    c
    e
    ,
    t
    h
    r
    e
    a
    d
    P
    o
    o
    l
    ,
    .
    .
    .
    }
    t
    w
    i
    t
    t
    e
    r
    B
    o
    t
    .
    E
    v
    e
    n
    t
    L
    o
    o
    p
    (
    )
    }
    めんどくさいしミスりそう
    19 / 31

    View full-size slide

  20. DI
    コンテナ
    依存性を管理していい感じに扱うためのライブラリ
    Google Guice (Java)
    など
    https://github.com/google/guice
    Motivation
    の記事はとてもよくまとまっているので読むといい
    https://github.com/google/guice/wiki/Motivation
    p
    u
    b
    l
    i
    c c
    l
    a
    s
    s B
    i
    l
    l
    i
    n
    g
    M
    o
    d
    u
    l
    e e
    x
    t
    e
    n
    d
    s A
    b
    s
    t
    r
    a
    c
    t
    M
    o
    d
    u
    l
    e {
    @
    O
    v
    e
    r
    r
    i
    d
    e
    p
    r
    o
    t
    e
    c
    t
    e
    d v
    o
    i
    d c
    o
    n
    f
    i
    g
    u
    r
    e
    (
    ) {
    b
    i
    n
    d
    (
    T
    r
    a
    n
    s
    a
    c
    t
    i
    o
    n
    L
    o
    g
    .
    c
    l
    a
    s
    s
    )
    .
    t
    o
    (
    D
    a
    t
    a
    b
    a
    s
    e
    T
    r
    a
    n
    s
    a
    c
    t
    i
    o
    n
    L
    o
    g
    .
    c
    l
    a
    s
    s
    )
    ;
    b
    i
    n
    d
    (
    C
    r
    e
    d
    i
    t
    C
    a
    r
    d
    P
    r
    o
    c
    e
    s
    s
    o
    r
    .
    c
    l
    a
    s
    s
    )
    .
    t
    o
    (
    P
    a
    y
    p
    a
    l
    C
    r
    e
    d
    i
    t
    C
    a
    r
    d
    P
    r
    o
    c
    e
    s
    s
    o
    r
    .
    c
    l
    a
    s
    s
    )
    ;
    b
    i
    n
    d
    (
    B
    i
    l
    l
    i
    n
    g
    S
    e
    r
    v
    i
    c
    e
    .
    c
    l
    a
    s
    s
    )
    .
    t
    o
    (
    R
    e
    a
    l
    B
    i
    l
    l
    i
    n
    g
    S
    e
    r
    v
    i
    c
    e
    .
    c
    l
    a
    s
    s
    )
    ;
    }
    }
    p
    u
    b
    l
    i
    c c
    l
    a
    s
    s R
    e
    a
    l
    B
    i
    l
    l
    i
    n
    g
    S
    e
    r
    v
    i
    c
    e i
    m
    p
    l
    e
    m
    e
    n
    t
    s B
    i
    l
    l
    i
    n
    g
    S
    e
    r
    v
    i
    c
    e {
    p
    r
    i
    v
    a
    t
    e f
    i
    n
    a
    l C
    r
    e
    d
    i
    t
    C
    a
    r
    d
    P
    r
    o
    c
    e
    s
    s
    o
    r p
    r
    o
    c
    e
    s
    s
    o
    r
    ;
    p
    r
    i
    v
    a
    t
    e f
    i
    n
    a
    l T
    r
    a
    n
    s
    a
    c
    t
    i
    o
    n
    L
    o
    g t
    r
    a
    n
    s
    a
    c
    t
    i
    o
    n
    L
    o
    g
    ;
    @
    I
    n
    j
    e
    c
    t
    p
    u
    b
    l
    i
    c R
    e
    a
    l
    B
    i
    l
    l
    i
    n
    g
    S
    e
    r
    v
    i
    c
    e
    (
    C
    r
    e
    d
    i
    t
    C
    a
    r
    d
    P
    r
    o
    c
    e
    s
    s
    o
    r p
    r
    o
    c
    e
    s
    s
    o
    r
    ,
    T
    r
    a
    n
    s
    a
    c
    t
    i
    o
    n
    L
    o
    g t
    r
    a
    n
    s
    a
    c
    t
    i
    o
    n
    L
    o
    g
    ) {
    t
    h
    i
    s
    .
    p
    r
    o
    c
    e
    s
    s
    o
    r = p
    r
    o
    c
    e
    s
    s
    o
    r
    ;
    t
    h
    i
    s
    .
    t
    r
    a
    n
    s
    a
    c
    t
    i
    o
    n
    L
    o
    g = t
    r
    a
    n
    s
    a
    c
    t
    i
    o
    n
    L
    o
    g
    ;
    }
    }
    20 / 31

    View full-size slide

  21. facebookgo/inject
    https://github.com/facebookgo/inject
    Go
    用の DI
    コンテナ
    タグを抽出して自動で依存グラフを作り、
    注入
    リフレクションごりごり…
    紹介記事 http://blog.parse.com/2014/05/13/dependency-injection-with-go/
    21 / 31

    View full-size slide

  22. 私見
    implicit
    なものが大嫌い
    アプリケー
    ションの初期化もプログラマが自分でどの順番でやるべきかを
    指定するべき
    黒魔術的なマクロやシンタックスシュガー
    など使わず、
    明示的に自分で書
    いていくほうが読みやすい
    3
    万行くらいまでなら実証済み
    22 / 31

    View full-size slide

  23. 今日の話
    Dependency Injection
    アプリケー
    ション初期化と DI
    コンテナ
    インター
    フェー
    ス実装によるモックとモックライブラリ
    23 / 31

    View full-size slide

  24. モック
    テスト時に依存オブジェクトの挙動を一時的に変更したい
    モック、
    スタブ、
    スパイ
    DI
    で設計してあれば依存性を後から注入できるので簡単にできる
    24 / 31

    View full-size slide

  25. インター
    フェー
    ス実装してモック
    (Java)
    @
    T
    e
    s
    t
    p
    u
    b
    l
    i
    c v
    o
    i
    d a
    c
    t
    i
    o
    n
    W
    i
    t
    h
    E
    m
    p
    t
    y
    T
    i
    m
    e
    l
    i
    n
    e
    (
    ) {
    T
    w
    i
    t
    t
    e
    r
    S
    e
    r
    v
    i
    c
    e s
    e
    r
    v
    i
    c
    e = n
    e
    w T
    w
    i
    t
    t
    e
    r
    S
    e
    r
    v
    i
    c
    e
    (
    ) {
    L
    i
    s
    t
    <
    S
    t
    a
    t
    u
    s
    > g
    e
    t
    T
    i
    m
    e
    l
    i
    n
    e
    (
    i
    n
    t c
    o
    u
    n
    t
    ) {
    r
    e
    t
    u
    r
    n n
    e
    w L
    i
    s
    t
    <
    S
    t
    a
    t
    u
    s
    >
    (
    )
    ;
    }
    i
    n
    t t
    w
    e
    e
    t
    (
    S
    t
    r
    i
    n
    g t
    e
    x
    t
    , i
    n
    t i
    n
    R
    e
    p
    l
    y
    T
    o
    ) {
    t
    h
    r
    o
    w n
    e
    w R
    u
    n
    t
    i
    m
    e
    E
    x
    c
    e
    p
    t
    i
    o
    n
    (
    )
    ;
    }
    }
    ;
    T
    w
    i
    t
    t
    e
    r
    B
    o
    t b
    o
    t = n
    e
    w T
    w
    i
    t
    t
    e
    r
    B
    o
    t
    I
    m
    p
    l
    (
    s
    e
    r
    v
    i
    c
    e
    )
    ;
    a
    s
    s
    e
    r
    t
    T
    h
    a
    t
    (
    b
    o
    t
    .
    a
    c
    t
    i
    o
    n
    (
    1
    0
    )
    .
    s
    i
    z
    e
    , i
    s
    (
    0
    )
    )
    ;
    }
    25 / 31

    View full-size slide

  26. インター
    フェー
    ス実装してモック (Go)
    t
    y
    p
    e M
    o
    c
    k
    S
    e
    r
    v
    i
    c
    e s
    t
    r
    u
    c
    t
    {
    }
    f
    u
    n
    c (
    x *
    M
    o
    c
    k
    S
    e
    r
    v
    i
    c
    e
    ) G
    e
    t
    T
    i
    m
    e
    l
    i
    n
    e
    (
    c
    o
    u
    n
    t i
    n
    t
    ) (
    [
    ]
    S
    t
    a
    t
    u
    s
    , e
    r
    r
    o
    r
    ) {
    r
    e
    t
    u
    r
    n m
    a
    k
    e
    (
    [
    ]
    S
    t
    a
    t
    u
    s
    , 0
    )
    , n
    i
    l
    }
    f
    u
    n
    c (
    t *
    M
    o
    c
    k
    S
    e
    r
    v
    i
    c
    e
    ) T
    w
    e
    e
    t
    (
    t
    e
    x
    t s
    t
    r
    i
    n
    g
    , i
    n
    R
    e
    p
    l
    y
    T
    o i
    n
    t
    ) (
    i
    n
    t
    , e
    r
    r
    o
    r
    ) {
    p
    a
    n
    i
    c
    (
    "
    "
    )
    }
    f
    u
    n
    c T
    e
    s
    t
    A
    c
    t
    i
    o
    n
    (
    t *
    t
    e
    s
    t
    i
    n
    g
    .
    T
    ) {
    s
    e
    r
    v
    i
    c
    e :
    = &
    M
    o
    c
    k
    S
    e
    r
    v
    i
    c
    e
    {
    }
    b
    o
    t :
    = &
    T
    w
    i
    t
    t
    e
    r
    B
    o
    t
    I
    m
    p
    l
    {
    s
    e
    r
    v
    i
    c
    e
    }
    t
    l
    , _ :
    = b
    o
    t
    .
    A
    c
    t
    i
    o
    n
    (
    1
    0
    )
    i
    f l
    e
    n
    (
    t
    l
    ) !
    = 0 { t
    .
    E
    r
    r
    o
    r
    (
    "
    f
    a
    i
    l
    "
    ) }
    }
    Go
    の場合、
    どのインター
    フェー
    スを実装しているかを明示的に書かない
    ダックタイピング Structural Subtyping
    もし Go
    に匿名インター
    フェー
    ス構文があれば次のように書ける
    s
    e
    r
    v
    i
    c
    e :
    = &
    i
    n
    t
    e
    r
    f
    a
    c
    e
    {
    G
    e
    t
    T
    i
    m
    e
    l
    i
    n
    e
    (
    c
    o
    u
    n
    t i
    n
    t
    ) (
    [
    ]
    S
    t
    a
    t
    u
    s
    , e
    r
    r
    o
    r
    ) { r
    e
    t
    u
    r
    n m
    a
    k
    e
    (
    [
    ]
    S
    t
    a
    t
    u
    s
    , 0
    )
    , n
    i
    l }
    T
    w
    e
    e
    t
    (
    t
    e
    x
    t s
    t
    r
    i
    n
    g
    , i
    n
    R
    e
    p
    l
    y
    T
    o i
    n
    t
    ) (
    i
    n
    t
    , e
    r
    r
    o
    r
    ) { p
    a
    n
    i
    c
    (
    "
    "
    ) }
    }
    26 / 31

    View full-size slide

  27. 問題点

    メソッドの挙動を変える」
    以外の細かいところが地味に面倒
    1
    回目の呼び出しと2
    回目の呼び出しで挙動を変える
    呼び出し順番チェック
    呼び出し回数チェック
    使わないメソッドについてもいちいち実装を指定してあげる必要がある
    とりあえず p
    a
    n
    i
    c
    (
    "
    "
    )
    でいいんだけど
    27 / 31

    View full-size slide

  28. モックライブラリ
    gomock
    https://code.google.com/p/gomock/
    使い方がわかりそうでわかりづらいライブラリ
    完全にドキュメント不足
    使い方の例: https://github.com/daimatz/gomock_example
    各コミットで動くようになっているので試してみてください
    withmock
    というやつもある
    https://github.com/qur/withmock
    gomock
    のラッパー
    っぽい
    試せていない
    28 / 31

    View full-size slide

  29. gomock
    使い方
    $ m
    k
    d
    i
    r $
    G
    O
    P
    A
    T
    H
    /
    s
    r
    c
    /
    g
    i
    t
    h
    u
    b
    .
    c
    o
    m
    /
    d
    a
    i
    m
    a
    t
    z
    /
    g
    o
    m
    o
    c
    k
    _
    u
    s
    a
    g
    e #
    リポジトリ名。
    なんでもいい
    $ c
    d $
    G
    O
    P
    A
    T
    H
    /
    s
    r
    c
    /
    g
    i
    t
    h
    u
    b
    .
    c
    o
    m
    /
    d
    a
    i
    m
    a
    t
    z
    /
    g
    o
    m
    o
    c
    k
    _
    u
    s
    a
    g
    e
    $ m
    k
    d
    i
    r a #
    ディレクトリ名。
    なんでもいい
    $ c
    a
    t > a
    /
    b
    .
    g
    o #
    ファイル名。
    なんでもいい
    p
    a
    c
    k
    a
    g
    e a /
    /
    ディレクトリ名と同じ
    t
    y
    p
    e I i
    n
    t
    e
    r
    f
    a
    c
    e { F
    (
    ) s
    t
    r
    i
    n
    g } /
    /
    名前に制限あり? X
    だとダメだった
    $ m
    k
    d
    i
    r m
    o
    c
    k
    _
    a # m
    o
    c
    k
    _
    ディレクトリ名
    $ m
    o
    c
    k
    g
    e
    n g
    i
    t
    h
    u
    b
    .
    c
    o
    m
    /
    d
    a
    i
    m
    a
    t
    z
    /
    g
    o
    m
    o
    c
    k
    _
    u
    s
    a
    g
    e
    /
    a \ #
    リポジトリ名/
    ディレクトリ名
    I > m
    o
    c
    k
    _
    a
    /
    x
    .
    g
    o #
    インター
    フェー
    ス名 > m
    o
    c
    k
    _
    ディレクトリ名/
    なんでもいい
    $ c
    a
    t > a
    /
    b
    _
    t
    e
    s
    t
    .
    g
    o #
    ファイル名_
    t
    e
    s
    t
    .
    g
    o
    p
    a
    c
    k
    a
    g
    e a
    _
    t
    e
    s
    t /
    /
    ディレクトリ名_
    t
    e
    s
    t
    i
    m
    p
    o
    r
    t (
    "
    t
    e
    s
    t
    i
    n
    g
    "
    "
    c
    o
    d
    e
    .
    g
    o
    o
    g
    l
    e
    .
    c
    o
    m
    /
    p
    /
    g
    o
    m
    o
    c
    k
    /
    g
    o
    m
    o
    c
    k
    "
    "
    g
    i
    t
    h
    u
    b
    .
    c
    o
    m
    /
    d
    a
    i
    m
    a
    t
    z
    /
    g
    o
    m
    o
    c
    k
    _
    u
    s
    a
    g
    e
    /
    m
    o
    c
    k
    _
    a
    " /
    /
    リポジトリ名/
    m
    o
    c
    k
    _
    ディレクトリ名
    )
    f
    u
    n
    c T
    e
    s
    t
    I
    (
    t *
    t
    e
    s
    t
    i
    n
    g
    .
    T
    ) {
    c
    t
    r
    l :
    = g
    o
    m
    o
    c
    k
    .
    N
    e
    w
    C
    o
    n
    t
    r
    o
    l
    l
    e
    r
    (
    t
    )
    d
    e
    f
    e
    r c
    t
    r
    l
    .
    F
    i
    n
    i
    s
    h
    (
    )
    i :
    = m
    o
    c
    k
    _
    a
    .
    N
    e
    w
    M
    o
    c
    k
    I
    (
    c
    t
    r
    l
    ) /
    / N
    e
    w
    M
    o
    c
    k
    インター
    フェー
    ス名
    i
    .
    E
    X
    P
    E
    C
    T
    (
    )
    .
    F
    (
    )
    .
    R
    e
    t
    u
    r
    n
    (
    "
    m
    o
    c
    k
    e
    d
    !
    "
    )
    i
    f i
    .
    F
    (
    ) !
    = "
    m
    o
    c
    k
    e
    d
    !
    " { t
    .
    E
    r
    r
    o
    r
    (
    "
    f
    a
    i
    l
    e
    d
    "
    ) }
    }
    $ c
    d a
    ; g
    o t
    e
    s
    t 29 / 31

    View full-size slide

  30. 他言語のモックライブラリとの比較
    Java
    などのモックライブラリと比べるとかなり面倒
    Mockito
    の例
    T
    w
    i
    t
    t
    e
    r
    S
    e
    r
    v
    i
    c
    e s
    e
    r
    v
    i
    c
    e = M
    o
    c
    k
    i
    t
    o
    .
    m
    o
    c
    k
    (
    T
    w
    i
    t
    t
    e
    r
    S
    e
    r
    v
    i
    c
    e
    .
    c
    l
    a
    s
    s
    )
    ;
    M
    o
    c
    k
    i
    t
    o
    .
    w
    h
    e
    n
    (
    s
    e
    r
    v
    i
    c
    e
    .
    g
    e
    t
    T
    i
    m
    e
    l
    i
    n
    e
    (
    1
    0
    )
    )
    .
    t
    h
    e
    n
    R
    e
    t
    u
    r
    n
    (
    n
    e
    w L
    i
    s
    t
    (
    )
    )
    ;
    Go
    にはジェネリクスがなく、
    インター
    フェー
    スが第一級でないため、
    ソー

    コー
    ド内で簡単にモックを生成することができない?
    s
    e
    r
    v
    i
    c
    e :
    = g
    o
    m
    o
    c
    k
    .
    m
    o
    c
    k
    [
    T
    w
    i
    t
    t
    e
    r
    S
    e
    r
    v
    i
    c
    e
    ]
    (
    ) /
    /
    ジェネリクスがない
    s
    e
    r
    v
    i
    c
    e :
    = g
    o
    m
    o
    c
    k
    .
    m
    o
    c
    k
    (
    T
    w
    i
    t
    t
    e
    r
    S
    e
    r
    v
    i
    c
    e
    ) /
    /
    インター
    フェー
    ス名を渡せない
    30 / 31

    View full-size slide

  31. まとめ
    Dependency Injection
    からモックライブラリの嬉しさまで一周りしました
    テスタブルな設計を目指しましょう
    gomock
    は難しい
    31 / 31

    View full-size slide