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

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

Transcript

  1. Scala ZIOをバッチ処理で使ってみた
 リチャード 伊真岡
 マーベリック株式会社


  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作者
  3. 関数型の最大のメリット(の一つ)はtestability! ②
 “I would argue that the whole point of

    functional programming in general is testing” Free as in Monads - ETE 2017 Daniel Spiewak氏
  4. 純粋関数はtestabilityが高い
 input 1 input 2 output

  5. 純粋関数はtestabilityが高い
 test input 1 test input 2 output expected output

    assert!
  6. 副作用はテストが難しい
 Database
 File
 HTTP


  7. 副作用を含むコード
 副作用
 純粋関数呼び出し


  8. テストしづらい...
 そこで関数型のテクニックを使う!


  9. descriptionとinterpreterの分離
 val programDescription = for { … <- queryDatabase(…) …

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

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

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

  12. descriptionとinterpreterの分離
 • この流れに沿うテクニックとしてfree-monad, tagless-finalなどがある • しかし...

  13. John De Goes氏のThe Death of Tagless Finalより
 https://skillsmatter.com/skillscasts/13247-scala-matters

  14. John De Goes氏のThe Death of Tagless Finalより
 https://skillsmatter.com/skillscasts/13247-scala-matters

  15. 副作用同士はtestで比較できない
 input 1 input 2 description expected description assert!??? e.g.

    println
  16. JOHN A DE GOES - The False Hope of Managing

    Effects with Tagless-Final in Scala 

  17. Scala ZIOの方がtagless finalよりイイ?
 • testabilityの向上 • とくに非関数型プログラマになじみやすい(らしい) ◦ -> ZIO自体の開発動機のひとつ

    (ZIO作者談)

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


  19. ZIOの戻り値型
 ZIO[R, E, A] • R - Environment Type. •

    E - Failure Type. • A - Success Type.
  20. ZIOの戻り値型
 ZIO[R, E, A] • R - Environment Type. •

    E - Failure Type. • A - Success Type. <- Exception, Error
  21. ZIOの戻り値型
 ZIO[R, E, A] • R - Environment Type. •

    E - Failure Type. • A - Success Type. <- DI components, DB, Config, ThreadPool
  22. None
  23. これがCirquaだ!


  24. これがCirquaだ!


  25. これがCirquaだ!


  26. これがCirquaだ!


  27. これがCirquaだ!
 独立している!!

  28. ZIOの戻り値型
 ZIO[R, E, A] • R - Environment Type. •

    E - Failure Type. • A - Success Type. <- DI components, DB, Config, ThreadPool
  29. ZIOでのDI手順例: DIするコンポーネントを特定
 Config S3 Logger Athena Database etc

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

    例:
 cake pattern

  31. trait S3Service { def getFromS3(...): ZIO[Any, Throwable, S3Result] } S3

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

    trait S3Component { val service: S3Service } object S3ProductionComponent extends S3Component { val service: S3.Service = ... }
  33. 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 = ... }
  34. trait MainComponent extends S3Component with AthenaComponent with DatabaseComponent with ConfigComponent

    with LoggerComponent with … … cake pattern
 
 どっちかというとおまんじゅうに見える 

  35. \アッタカイヨー/


  36. CirquaでのZIO利用例
 def run(args: List[String]) = { _ <- logger.info(...) _

    <- logger.info(...extra info...) _ <- databaseComponent.setup(...) result <- athenaComponent.execute(...) ... } yield ()
  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 () あえてZIOの型を書いてみる(必要ない場合普通は書かない)

  38. 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() … }
  39. cakeってアンチパターンじゃないの?


  40. 分割された一つ一つのfor文は
 小さいcakeになるので、昔ながらの cake patternの問題を避けられる
 ZIO cake (module pattern)
 (らしいよ)

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

  42. 関数型の最大のメリット(の一つ)は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の話をしている。 (リチャード)
  43. Algebraic Lawsの話 • プログラムが満たすべきルールを、型クラスが満たすべきルールとして定義してい る(はず…間違ってる?)
 • そもそもデータベース副作用、ファイル副作用に満たすべきAlgebraic Lawつまり代 数的規則などない、数学的に厳密に規則を議論できない
 •

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

  44. 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作者
  45. ZIOとテスト • イマイチdescriptionとinterpreterの分離によるtestabilityの向上がわからない • DIを上手く使えばテストが書けるが、それはdescriptionとinterpreterの分離による testability向上ではないのでは? • 結局この点はについてはtagless-finalも同じだったし、ZIOでも副作用のtestability が向上してるわけではなさそうに見えるのだが… •

    というわけでdescriptionとinterpreterの分離の流れに沿うZIOもtestabilityの向上と いう面で見るとメリットが「私には」理解できなかった • モックを上手く使えばテストが書けるが(同上)
  46. ZIOは理解しやすくtestability以外の
 メリットも有る、という話なら分かる


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


  48. 省略
 ごめん、まとめる時間がなかった