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

Scala ZIOをバッチ処理に使ってみた

Scala ZIOをバッチ処理に使ってみた

More Decks by リチャード 伊真岡

Other Decks in Technology

Transcript

  1. Scala ZIOをバッチ処理で使ってみた

    リチャード 伊真岡

    マーベリック株式会社


    View full-size slide

  2. 関数型の最大のメリット(の一つ)はtestability! ①

    “Functional programming ordinarily
    gives us the incredible ability to
    easily test our software.”
    Beautiful, Simple, Testable Functional Effects for Scala
    JOHN A DE GOES (blog) Feb, 2019
    John De Goes氏 ZIO作者

    View full-size slide

  3. 関数型の最大のメリット(の一つ)はtestability! ②

    “I would argue that the whole point of
    functional programming in general is
    testing”
    Free as in Monads - ETE 2017
    Daniel Spiewak氏

    View full-size slide

  4. 純粋関数はtestabilityが高い

    input 1
    input 2
    output

    View full-size slide

  5. 純粋関数はtestabilityが高い

    test input 1
    test input 2
    output
    expected
    output
    assert!

    View full-size slide

  6. 副作用はテストが難しい

    Database
 File
 HTTP


    View full-size slide

  7. 副作用を含むコード

    副作用

    純粋関数呼び出し


    View full-size slide

  8. テストしづらい...

    そこで関数型のテクニックを使う!


    View full-size slide

  9. descriptionとinterpreterの分離

    val programDescription = for {
    … <- queryDatabase(…)
    … <- callHttpService(…)
    … <- doSomeMagic(…)
    } yield finalResult
    def main(args: Array[String]): Unit = {
    interpreter.unsafeRun(programDescription)
    }

    View full-size slide

  10. descriptionとinterpreterの分離

    val programDescription = for {
    … <- queryDatabase(…)
    … <- callHttpService(…)
    … <- doSomeMagic(…)
    } yield finalResult
    def main(args: Array[String]): Unit = {
    interpreter.unsafeRun(programDescription)
    }

    View full-size slide

  11. descriptionとinterpreterの分離

    val programDescription = for {
    … <- queryDatabase(…)
    … <- callHttpService(…)
    … <- doSomeMagic(…)
    } yield finalResult
    def main(args: Array[String]): Unit = {
    interpreter.unsafeRun(programDescription)
    }
    tree構造

    副作用


    View full-size slide

  12. descriptionとinterpreterの分離

    ● この流れに沿うテクニックとしてfree-monad, tagless-finalなどがある
    ● しかし...

    View full-size slide

  13. John De Goes氏のThe Death of Tagless Finalより

    https://skillsmatter.com/skillscasts/13247-scala-matters

    View full-size slide

  14. John De Goes氏のThe Death of Tagless Finalより

    https://skillsmatter.com/skillscasts/13247-scala-matters

    View full-size slide

  15. 副作用同士はtestで比較できない

    input 1
    input 2
    description
    expected
    description
    assert!???
    e.g. println

    View full-size slide

  16. JOHN A DE GOES - The False Hope of Managing Effects with Tagless-Final in Scala 


    View full-size slide

  17. Scala ZIOの方がtagless finalよりイイ?

    ● testabilityの向上
    ● とくに非関数型プログラマになじみやすい(らしい)
    ○ -> ZIO自体の開発動機のひとつ
    (ZIO作者談)


    View full-size slide

  18. Scala ZIOをバッチ処理で使ってみた


    View full-size slide

  19. ZIOの戻り値型

    ZIO[R, E, A]
    ● R - Environment Type.
    ● E - Failure Type.
    ● A - Success Type.

    View full-size slide

  20. ZIOの戻り値型

    ZIO[R, E, A]
    ● R - Environment Type.
    ● E - Failure Type.
    ● A - Success Type.
    <- Exception, Error

    View full-size slide

  21. ZIOの戻り値型

    ZIO[R, E, A]
    ● R - Environment Type.
    ● E - Failure Type.
    ● A - Success Type.
    <- DI components,
    DB,
    Config,
    ThreadPool

    View full-size slide

  22. これがCirquaだ!


    View full-size slide

  23. これがCirquaだ!


    View full-size slide

  24. これがCirquaだ!


    View full-size slide

  25. これがCirquaだ!


    View full-size slide

  26. これがCirquaだ!

    独立している!!

    View full-size slide

  27. ZIOの戻り値型

    ZIO[R, E, A]
    ● R - Environment Type.
    ● E - Failure Type.
    ● A - Success Type.
    <- DI components,
    DB,
    Config,
    ThreadPool

    View full-size slide

  28. ZIOでのDI手順例: DIするコンポーネントを特定

    Config S3
    Logger
    Athena
    Database etc

    View full-size slide

  29. trait S3Service {
    def getFromS3(...): ZIO[Any, Throwable, S3Result]
    }
    S3
    例:
 cake pattern


    View full-size slide

  30. trait S3Service {
    def getFromS3(...): ZIO[Any, Throwable, S3Result]
    }
    S3
    trait S3Component {
    val service: S3Service
    }

    View full-size slide

  31. trait S3Service {
    def getFromS3(...): ZIO[Any, Throwable, S3Result]
    }
    S3
    trait S3Component {
    val service: S3Service
    }
    object S3ProductionComponent
    extends S3Component {
    val service: S3.Service = ...
    }

    View full-size slide

  32. trait S3Service {
    def getFromS3(...): ZIO[Any, Throwable, S3Result]
    }
    S3
    trait S3Component {
    val service: S3Service
    }
    object S3ProductionComponent
    extends S3Component {
    val service: S3.Service = ...
    }
    object S3TestComponent
    extends S3Component {
    val service: S3.Service = ...
    }

    View full-size slide

  33. trait MainComponent extends
    S3Component with
    AthenaComponent with
    DatabaseComponent with
    ConfigComponent with
    LoggerComponent with


    cake pattern


    どっちかというとおまんじゅうに見える 


    View full-size slide

  34. \アッタカイヨー/


    View full-size slide

  35. CirquaでのZIO利用例

    def run(args: List[String]) = {
    _ <- logger.info(...)
    _ <- logger.info(...extra info...)
    _ <- databaseComponent.setup(...)
    result <- athenaComponent.execute(...)
    ...
    } yield ()

    View full-size slide

  36. CirquaでのZIO利用例

    def run(args: List[String]):
    ZIO[S3Component with AthenaComponent with …, Throwable, BatchResult] = {
    _ <- logger.info(...)
    _ <- logger.info(...extra info...)
    _ <- databaseComponent.setup(...)
    _ <- athenaComponent.setUp(...)
    ...
    } yield ()
    あえてZIOの型を書いてみる(必要ない場合普通は書かない)


    View full-size slide

  37. CirquaでのZIO利用例

    def run(args: List[String]):
    ZIO[S3Component with AthenaComponent with …, Throwable, BatchResult] = {
    _ <- logger.info(...)
    _ <- logger.info(...extra info...)
    _ <- databaseComponent.setup(...)
    _ <- athenaComponent.setUp(...)
    ...
    } yield ()
    def setUp(...): ZIO[..., …, ...] = for {
    _ <- s3Component.setupSomething()

    }

    View full-size slide

  38. cakeってアンチパターンじゃないの?


    View full-size slide

  39. 分割された一つ一つのfor文は

    小さいcakeになるので、昔ながらの
    cake patternの問題を避けられる

    ZIO cake (module pattern)

    (らしいよ)

    View full-size slide

  40. ZIOとテスト
    ● Effect(副作用)はだいたいDIのコンポーネントに集中する
    ● DIを使ってテスト!...あれ?

    View full-size slide

  41. 関数型の最大のメリット(の一つ)はtestability! ②

    “I would argue that the whole point of
    functional programming in general is
    testing”
    Free as in Monads - ETE 2017
    Daniel Spiewak氏 関数型プログラミング等で特に著名
    これ、Algebraic Lawsの話をしている。 (リチャード)

    View full-size slide

  42. Algebraic Lawsの話
    ● プログラムが満たすべきルールを、型クラスが満たすべきルールとして定義してい
    る(はず…間違ってる?)

    ● そもそもデータベース副作用、ファイル副作用に満たすべきAlgebraic Lawつまり代
    数的規則などない、数学的に厳密に規則を議論できない

    ● それはtagless finalに代えてZIOを導入しても同じ


    View full-size slide

  43. John De Goes氏の別の発言

    “Tagless-final type classes do not, in general,
    have algebraic laws. Most have no laws at all.
    This represents a serious abuse of the construct
    of a type class ...”
    Beautiful, Simple, Testable Functional Effects for Scala
    JOHN A DE GOES (blog) Feb, 2019
    John De Goes氏 ZIO作者

    View full-size slide

  44. ZIOとテスト
    ● イマイチdescriptionとinterpreterの分離によるtestabilityの向上がわからない
    ● DIを上手く使えばテストが書けるが、それはdescriptionとinterpreterの分離による
    testability向上ではないのでは?
    ● 結局この点はについてはtagless-finalも同じだったし、ZIOでも副作用のtestability
    が向上してるわけではなさそうに見えるのだが…
    ● というわけでdescriptionとinterpreterの分離の流れに沿うZIOもtestabilityの向上と
    いう面で見るとメリットが「私には」理解できなかった
    ● モックを上手く使えばテストが書けるが(同上)

    View full-size slide

  45. ZIOは理解しやすくtestability以外の

    メリットも有る、という話なら分かる


    View full-size slide

  46. ZIOの他のメリット!!


    View full-size slide

  47. 省略

    ごめん、まとめる時間がなかった

    View full-size slide