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

PlayFrameworkでFuture[Either[A, B]]どうするのか問題/ PlayFramework return type problem

tsatow
April 18, 2019

PlayFrameworkでFuture[Either[A, B]]どうするのか問題/ PlayFramework return type problem

PlayFrameworkを使ってると頻繁にFuture[Either[A, B]]と遭遇します。
このままだととても取り回しが辛いのですが、それをどうやって解決したか、という話を第0回ゆるふわ.scalaでしました。

(追記)
投稿してから気づいたけど、この内容だとまるで自分が解決策を考えたかのような印象与えますね。解決策を考えたのは私じゃありません。私は知ったかぶりしてるだけです。

(更に追記)
スライドのタイトルだけ変更しました。
「PlayFramework戻り値の型どうするのか問題」というタイトルが内容と合っていない気がしたので。

tsatow

April 18, 2019
Tweet

Other Decks in Technology

Transcript

  1. 2019/4/19 PlayFramework
    戻り値の型どうするのか問題
    127.0.0.1:8080/PlayScalaResult/#1 1/25
    PlayFramework
    でFuture[Either[A, B]]
    どうするのか問題
    佐藤貴比呂
    1 / 25

    View Slide

  2. 2019/4/19 PlayFramework
    戻り値の型どうするのか問題
    127.0.0.1:8080/PlayScalaResult/#1 2/25
    自己紹介
    2 / 25

    View Slide

  3. 2019/4/19 PlayFramework
    戻り値の型どうするのか問題
    127.0.0.1:8080/PlayScalaResult/#1 3/25
    名前
    佐藤 貴比呂(
    さとう たかひろ)
    所属
    株式会社アットウェア
    Scala

    1
    年(2017/7~2018/6)
    Twitter
    @Satoooooooooooo
    趣味
    釣り/
    柔道/
    チアリーディング
    その他
    ガッツあるときYokohama.scala
    開催してます
    3 / 25

    View Slide

  4. 2019/4/19 PlayFramework
    戻り値の型どうするのか問題
    127.0.0.1:8080/PlayScalaResult/#1 4/25
    イントロ
    4 / 25

    View Slide

  5. 2019/4/19 PlayFramework
    戻り値の型どうするのか問題
    127.0.0.1:8080/PlayScalaResult/#1 5/25
    Scala
    初心者も少なくなかったプロジェクト。
    PlayFramework
    使ったらやたらとFuture[Either[A, B]]
    が出てきた。
    5 / 25

    View Slide

  6. 2019/4/19 PlayFramework
    戻り値の型どうするのか問題
    127.0.0.1:8080/PlayScalaResult/#1 6/25
    Play
    を普通に使うとそこらじゅうにFuture
    が出現
    業務例外はEither
    で返すと良いってよく見る
    例外の詳細が型からわかるとか
    網羅性検査が使えるとか
    6 / 25

    View Slide

  7. 2019/4/19 PlayFramework
    戻り値の型どうするのか問題
    127.0.0.1:8080/PlayScalaResult/#1 7/25
    なるほど、失敗する可能性がある処理の戻り値は
    Future[Either[A, B]]
    にすればいいんだな?
    7 / 25

    View Slide

  8. 2019/4/19 PlayFramework
    戻り値の型どうするのか問題
    127.0.0.1:8080/PlayScalaResult/#1 8/25
    実際に書いてみる。
    // subProcess
    がそれぞれFuture[Either[Error, Unit]]
    を返すとする
    def process(input: Input): Future[Either[Error, Unit]]
    for {
    r1 r2 case Right(_) => subProcess2(input)
    case Left(err) => Future.successful(Left(err))
    }
    _ case Right(_) => subProcess3(input)
    case Left(err) => Future.successful(Left(err))
    }
    } yield Right(())
    }
    3つの処理を順番に実行してるだけなのに
    なんかとても辛い。
    8 / 25

    View Slide

  9. 2019/4/19 PlayFramework
    戻り値の型どうするのか問題
    127.0.0.1:8080/PlayScalaResult/#1 9/25
    ドキュメントとか人の言うことに
    素直に従っただけなのに...
    もしかしてPlayFramework
    辛すぎ?
    9 / 25

    View Slide

  10. 2019/4/19 PlayFramework
    戻り値の型どうするのか問題
    127.0.0.1:8080/PlayScalaResult/#1 10/25
    10 / 25

    View Slide

  11. 2019/4/19 PlayFramework
    戻り値の型どうするのか問題
    127.0.0.1:8080/PlayScalaResult/#1 11/25
    初心者でも簡単に扱える解決策が必ずある
    11 / 25

    View Slide

  12. 2019/4/19 PlayFramework
    戻り値の型どうするのか問題
    127.0.0.1:8080/PlayScalaResult/#1 12/25
    本題
    (
    如何にして対処したか)
    12 / 25

    View Slide

  13. 2019/4/19 PlayFramework
    戻り値の型どうするのか問題
    127.0.0.1:8080/PlayScalaResult/#1 13/25
    Future
    とEither
    の成功と失敗の意味を考える。
    Future
    とEither
    で表現される失敗は何が違う?
    業務的な例外はEither
    それ以外の非チェック的な例外はFuture
    =>
    業務的に注目すべきはEither
    の部分だけ?
    13 / 25

    View Slide

  14. 2019/4/19 PlayFramework
    戻り値の型どうするのか問題
    127.0.0.1:8080/PlayScalaResult/#1 14/25
    実際、Future
    がフローに影響する箇所はない。
    def process(input: Input): Future[Either[Error, Unit]]
    for {
    r1 r2 case Right(_) => subProcess2(input)
    case Left(err) => Future.successful(Left(err))
    }
    _ case Right(_) => subProcess3(input)
    case Left(err) => Future.successful(Left(err))
    }
    } yield Right(())
    }
    14 / 25

    View Slide

  15. 2019/4/19 PlayFramework
    戻り値の型どうするのか問題
    127.0.0.1:8080/PlayScalaResult/#1 15/25
    もしかして、Future
    を隠蔽して
    Either
    の成功・失敗に集中できるようなラッパーを作れば良い?
    15 / 25

    View Slide

  16. 2019/4/19 PlayFramework
    戻り値の型どうするのか問題
    127.0.0.1:8080/PlayScalaResult/#1 16/25
    ラッパーをfor
    式で使うにはmap
    やflatMap
    を実装する必要があるけど
    Future
    が失敗のときはそのまま
    Future
    が成功してEither
    が失敗のときもそのまま
    Future
    が成功してEither
    も成功したときだけmap
    する
    となるように実装してあげれば良さそう。
    16 / 25

    View Slide

  17. 2019/4/19 PlayFramework
    戻り値の型どうするのか問題
    127.0.0.1:8080/PlayScalaResult/#1 17/25
    例えばこんな感じ?
    case class MyResult[+E, +R](result: Future[Either[E, R]]) {
    def map[RR](f: R => RR): MyResult[E, RR] = MyResult(result.map(_.map(f)))
    def flatMap[LL >: L, RR](f: R => MyResult[E, RR]): MyResult[E, RR] = MyResult {
    result flatMap {
    case Right(r) => f(r).result
    case Left(err) => Future.successful(Left(err))
    }
    }
    }
    17 / 25

    View Slide

  18. 2019/4/19 PlayFramework
    戻り値の型どうするのか問題
    127.0.0.1:8080/PlayScalaResult/#1 18/25
    実際に使ってみる。
    def process(input: Input): Future[Either[Error, Unit]]
    for {
    _ _ _ } yield Right(())
    }
    最初の処理と比べてだいぶすっきりしたので
    めでたしめでたし!
    18 / 25

    View Slide

  19. 2019/4/19 PlayFramework
    戻り値の型どうするのか問題
    127.0.0.1:8080/PlayScalaResult/#1 19/25
    Q.
    毎回自分で実装しなきゃいけないの?
    19 / 25

    View Slide

  20. 2019/4/19 PlayFramework
    戻り値の型どうするのか問題
    127.0.0.1:8080/PlayScalaResult/#1 20/25
    もちろんそんなことはなくて、
    私が参加したプロジェクトでは使わなかったけど、Scalaz
    やCats

    EitherT
    を導入すれば簡単に実現できる。
    type MyResult[E, R] = EitherT[Future, E, R]
    20 / 25

    View Slide

  21. 2019/4/19 PlayFramework
    戻り値の型どうするのか問題
    127.0.0.1:8080/PlayScalaResult/#1 21/25
    EitherT?
    21 / 25

    View Slide

  22. 2019/4/19 PlayFramework
    戻り値の型どうするのか問題
    127.0.0.1:8080/PlayScalaResult/#1 22/25
    実は今日のテーマは
    Either
    のモナドトランスフォーマーEitherT
    を使ってPlayFramework

    戻り値の型をどうするかという問題に対処したよ、という話でした。
    22 / 25

    View Slide

  23. 2019/4/19 PlayFramework
    戻り値の型どうするのか問題
    127.0.0.1:8080/PlayScalaResult/#1 23/25
    まとめ
    23 / 25

    View Slide

  24. 2019/4/19 PlayFramework
    戻り値の型どうするのか問題
    127.0.0.1:8080/PlayScalaResult/#1 24/25
    モナドトランスフォーマーを使うと、
    Play
    で頻出しがちなFuture[Either[A, B]]
    を隠蔽して業務をスッキリ記述できる。
    24 / 25

    View Slide

  25. 2019/4/19 PlayFramework
    戻り値の型どうするのか問題
    127.0.0.1:8080/PlayScalaResult/#1 25/25
    ご清聴ありがとうございました
    25 / 25

    View Slide